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 "svx/EnhancedCustomShape2d.hxx"
21 #include "svx/EnhancedCustomShapeGeometry.hxx"
22 #include "svx/EnhancedCustomShapeTypeNames.hxx"
23 #include <svx/svdoashp.hxx>
24 #include <svx/svdtrans.hxx>
25 #include <svx/svdocirc.hxx>
26 #include <svx/svdogrp.hxx>
27 #include <svx/svdopath.hxx>
28 #include <svx/svdocapt.hxx>
29 #include <svx/svdpage.hxx>
30 #include <svx/xflclit.hxx>
31 #include <svx/sdasaitm.hxx>
32 #include <svx/svdmodel.hxx>
34 #include <rtl/math.hxx>
35 #include <svx/xfillit0.hxx>
36 #include <svx/xlnstit.hxx>
37 #include <svx/xlnedit.hxx>
38 #include <svx/xlnstwit.hxx>
39 #include <svx/xlnedwit.hxx>
40 #include <svx/xlnstcit.hxx>
41 #include <svx/xlnedcit.hxx>
42 #include <svx/xflgrit.hxx>
43 #include <svx/xflhtit.hxx>
44 #include <svx/xbtmpit.hxx>
45 #include <svx/xgrad.hxx>
46 #include <svx/xhatch.hxx>
47 #include <com/sun/star/awt/Size.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
50 #include <basegfx/numeric/ftools.hxx>
51 #include <basegfx/color/bcolortools.hxx>
52 #include <basegfx/polygon/b2dpolygon.hxx>
53 #include <basegfx/polygon/b2dpolygontools.hxx>
54 #include <basegfx/matrix/b2dhommatrixtools.hxx>
55 #include <rtl/strbuf.hxx>
58 using namespace ::com::sun::star
;
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::drawing
;
61 using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand
;
63 void EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( EnhancedCustomShapeParameter
& rParameter
, const sal_Int32 nValue
)
65 sal_uInt32 nDat
= (sal_uInt32
)nValue
;
66 sal_Int32 nNewValue
= nValue
;
68 // check if this is a special point
69 if ( ( nDat
>> 16 ) == 0x8000 )
71 nNewValue
= (sal_uInt16
)nDat
;
72 rParameter
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
75 rParameter
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
76 rParameter
.Value
<<= nNewValue
;
79 OUString
EnhancedCustomShape2d::GetEquation( const sal_uInt16 nFlags
, sal_Int32 nP1
, sal_Int32 nP2
, sal_Int32 nP3
)
82 bool b1Special
= ( nFlags
& 0x2000 ) != 0;
83 bool b2Special
= ( nFlags
& 0x4000 ) != 0;
84 bool b3Special
= ( nFlags
& 0x8000 ) != 0;
85 switch( nFlags
& 0xff )
90 sal_Int32 nOptimize
= 0;
106 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
111 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
115 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
117 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
121 if ( b3Special
|| nP3
)
124 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
130 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
131 if ( b2Special
|| ( nP2
!= 1 ) )
134 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
136 if ( b3Special
|| ( ( nP3
!= 1 ) && ( nP3
!= 0 ) ) )
139 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
146 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
148 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
155 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
162 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
164 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
171 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
173 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
180 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
182 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
184 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
190 aEquation
+= "sqrt(";
191 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
193 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
195 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
197 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
199 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
201 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
207 aEquation
+= "atan2(";
208 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
210 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
211 aEquation
+= ")/(pi/180)";
216 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
217 aEquation
+= "*sin(";
218 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
219 aEquation
+= "*(pi/180))";
224 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
225 aEquation
+= "*cos(";
226 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
227 aEquation
+= "*(pi/180))";
232 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
233 aEquation
+= "*cos(atan2(";
234 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
236 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
242 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
243 aEquation
+= "*sin(atan2(";
244 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
246 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
252 aEquation
+= "sqrt(";
253 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
259 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
260 aEquation
+= "*sqrt(1-(";
261 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
263 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
266 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
268 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
274 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
275 aEquation
+= "*tan(";
276 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
282 aEquation
+= "sqrt(";
283 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
285 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
287 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
289 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
295 aEquation
+= "(cos(";
296 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
297 aEquation
+= "*(pi/180))*(";
298 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
299 aEquation
+= "-10800)+sin(";
300 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
301 aEquation
+= "*(pi/180))*(";
302 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
303 aEquation
+= "-10800))+10800";
308 aEquation
+= "-(sin(";
309 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
310 aEquation
+= "*(pi/180))*(";
311 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP1
, b1Special
);
312 aEquation
+= "-10800)-cos(";
313 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP3
, b3Special
);
314 aEquation
+= "*(pi/180))*(";
315 EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation
, nP2
, b2Special
);
316 aEquation
+= "-10800))+10800";
323 void EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( OUString
& rParameter
, const sal_Int32 nPara
, const bool bIsSpecialValue
)
325 if ( bIsSpecialValue
)
330 rParameter
+= OUString::number( ( nPara
& 0xff ) );
337 case DFF_Prop_adjustValue
:
338 case DFF_Prop_adjust2Value
:
339 case DFF_Prop_adjust3Value
:
340 case DFF_Prop_adjust4Value
:
341 case DFF_Prop_adjust5Value
:
342 case DFF_Prop_adjust6Value
:
343 case DFF_Prop_adjust7Value
:
344 case DFF_Prop_adjust8Value
:
345 case DFF_Prop_adjust9Value
:
346 case DFF_Prop_adjust10Value
:
349 rParameter
+= OUString::number( ( nPara
- DFF_Prop_adjustValue
) );
353 case DFF_Prop_geoLeft
:
355 rParameter
+= "left";
358 case DFF_Prop_geoTop
:
363 case DFF_Prop_geoRight
:
365 rParameter
+= "right";
368 case DFF_Prop_geoBottom
:
370 rParameter
+= "bottom";
378 rParameter
+= OUString::number( ( nPara
) );
382 void EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( EnhancedCustomShapeParameter
& rParameter
, const sal_Int32 nPara
, const bool bIsSpecialValue
, bool bHorz
)
384 sal_Int32 nValue
= 0;
385 if ( bIsSpecialValue
)
387 if ( ( nPara
>= 0x100 ) && ( nPara
<= 0x107 ) )
389 nValue
= nPara
& 0xff;
390 rParameter
.Type
= EnhancedCustomShapeParameterType::ADJUSTMENT
;
392 else if ( ( nPara
>= 3 ) && ( nPara
<= 0x82 ) )
395 rParameter
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
397 else if ( nPara
== 0 )
401 rParameter
.Type
= EnhancedCustomShapeParameterType::LEFT
;
403 rParameter
.Type
= EnhancedCustomShapeParameterType::TOP
;
405 else if ( nPara
== 1 )
409 rParameter
.Type
= EnhancedCustomShapeParameterType::RIGHT
;
411 rParameter
.Type
= EnhancedCustomShapeParameterType::BOTTOM
;
413 else if ( nPara
== 2 ) // means to be centered, but should not be
414 { // used in our implementation
416 rParameter
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
421 rParameter
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
427 rParameter
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
429 rParameter
.Value
<<= nValue
;
432 bool EnhancedCustomShape2d::ConvertSequenceToEnhancedCustomShape2dHandle(
433 const css::beans::PropertyValues
& rHandleProperties
,
434 EnhancedCustomShape2d::Handle
& rDestinationHandle
)
436 bool bRetValue
= false;
437 sal_uInt32 i
, nProperties
= rHandleProperties
.getLength();
440 rDestinationHandle
.nFlags
= HandleFlags::NONE
;
441 for ( i
= 0; i
< nProperties
; i
++ )
443 const css::beans::PropertyValue
& rPropVal
= rHandleProperties
[ i
];
445 if ( rPropVal
.Name
== "Position" )
447 if ( rPropVal
.Value
>>= rDestinationHandle
.aPosition
)
450 else if ( rPropVal
.Name
== "MirroredX" )
453 if ( rPropVal
.Value
>>= bMirroredX
)
456 rDestinationHandle
.nFlags
|= HandleFlags::MIRRORED_X
;
459 else if ( rPropVal
.Name
== "MirroredY" )
462 if ( rPropVal
.Value
>>= bMirroredY
)
465 rDestinationHandle
.nFlags
|= HandleFlags::MIRRORED_Y
;
468 else if ( rPropVal
.Name
== "Switched" )
471 if ( rPropVal
.Value
>>= bSwitched
)
474 rDestinationHandle
.nFlags
|= HandleFlags::SWITCHED
;
477 else if ( rPropVal
.Name
== "Polar" )
479 if ( rPropVal
.Value
>>= rDestinationHandle
.aPolar
)
480 rDestinationHandle
.nFlags
|= HandleFlags::POLAR
;
482 else if ( rPropVal
.Name
== "RefX" )
484 if ( rPropVal
.Value
>>= rDestinationHandle
.nRefX
)
485 rDestinationHandle
.nFlags
|= HandleFlags::REFX
;
487 else if ( rPropVal
.Name
== "RefY" )
489 if ( rPropVal
.Value
>>= rDestinationHandle
.nRefY
)
490 rDestinationHandle
.nFlags
|= HandleFlags::REFY
;
492 else if ( rPropVal
.Name
== "RefAngle" )
494 if ( rPropVal
.Value
>>= rDestinationHandle
.nRefAngle
)
495 rDestinationHandle
.nFlags
|= HandleFlags::REFANGLE
;
497 else if ( rPropVal
.Name
== "RefR" )
499 if ( rPropVal
.Value
>>= rDestinationHandle
.nRefR
)
500 rDestinationHandle
.nFlags
|= HandleFlags::REFR
;
502 else if ( rPropVal
.Name
== "RadiusRangeMinimum" )
504 if ( rPropVal
.Value
>>= rDestinationHandle
.aRadiusRangeMinimum
)
505 rDestinationHandle
.nFlags
|= HandleFlags::RADIUS_RANGE_MINIMUM
;
507 else if ( rPropVal
.Name
== "RadiusRangeMaximum" )
509 if ( rPropVal
.Value
>>= rDestinationHandle
.aRadiusRangeMaximum
)
510 rDestinationHandle
.nFlags
|= HandleFlags::RADIUS_RANGE_MAXIMUM
;
512 else if ( rPropVal
.Name
== "RangeXMinimum" )
514 if ( rPropVal
.Value
>>= rDestinationHandle
.aXRangeMinimum
)
515 rDestinationHandle
.nFlags
|= HandleFlags::RANGE_X_MINIMUM
;
517 else if ( rPropVal
.Name
== "RangeXMaximum" )
519 if ( rPropVal
.Value
>>= rDestinationHandle
.aXRangeMaximum
)
520 rDestinationHandle
.nFlags
|= HandleFlags::RANGE_X_MAXIMUM
;
522 else if ( rPropVal
.Name
== "RangeYMinimum" )
524 if ( rPropVal
.Value
>>= rDestinationHandle
.aYRangeMinimum
)
525 rDestinationHandle
.nFlags
|= HandleFlags::RANGE_Y_MINIMUM
;
527 else if ( rPropVal
.Name
== "RangeYMaximum" )
529 if ( rPropVal
.Value
>>= rDestinationHandle
.aYRangeMaximum
)
530 rDestinationHandle
.nFlags
|= HandleFlags::RANGE_Y_MAXIMUM
;
537 void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryItem
& rGeometryItem
)
540 const Any
* pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( "AdjustmentValues" );
542 *pAny
>>= seqAdjustmentValues
;
546 const Any
* pViewBox
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( "ViewBox" );
547 css::awt::Rectangle aViewBox
;
548 if ( pViewBox
&& (*pViewBox
>>= aViewBox
) )
550 nCoordLeft
= aViewBox
.X
;
551 nCoordTop
= aViewBox
.Y
;
552 nCoordWidthG
= labs( aViewBox
.Width
);
553 nCoordHeightG
= labs( aViewBox
.Height
);
555 const OUString
sPath( "Path" );
559 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "Coordinates" );
561 *pAny
>>= seqCoordinates
;
565 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "GluePoints" );
567 *pAny
>>= seqGluePoints
;
571 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "Segments" );
573 *pAny
>>= seqSegments
;
577 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "SubViewSize" );
579 *pAny
>>= seqSubViewSize
;
583 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "StretchX" );
586 sal_Int32 nStretchX
= 0;
587 if ( *pAny
>>= nStretchX
)
593 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "StretchY" );
596 sal_Int32 nStretchY
= 0;
597 if ( *pAny
>>= nStretchY
)
603 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, "TextFrames" );
605 *pAny
>>= seqTextFrames
;
609 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( "Equations" );
611 *pAny
>>= seqEquations
;
615 pAny
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( "Handles" );
617 *pAny
>>= seqHandles
;
620 EnhancedCustomShape2d::~EnhancedCustomShape2d()
624 void EnhancedCustomShape2d::SetPathSize( sal_Int32 nIndex
)
626 sal_Int32 nWidth
= 0;
627 sal_Int32 nHeight
= 0;
629 if ( seqSubViewSize
.getLength() && nIndex
< seqSubViewSize
.getLength() ) {
630 nWidth
= seqSubViewSize
[ nIndex
].Width
;
631 nHeight
= seqSubViewSize
[ nIndex
].Height
;
634 "set subpath " << nIndex
<< " size: " << nWidth
<< " x "
638 if ( nWidth
&& nHeight
) {
639 nCoordWidth
= nWidth
;
640 nCoordHeight
= nHeight
;
642 nCoordWidth
= nCoordWidthG
;
643 nCoordHeight
= nCoordHeightG
;
646 fXScale
= nCoordWidth
== 0 ? 0.0 : (double)aLogicRect
.GetWidth() / (double)nCoordWidth
;
647 fYScale
= nCoordHeight
== 0 ? 0.0 : (double)aLogicRect
.GetHeight() / (double)nCoordHeight
;
652 "ooxml shape, path width: " << nCoordWidth
<< " height: "
655 // Try to set up scale separately, if given only width or height
656 // This is possible case in OOXML when only width or height is non-zero
657 if ( nCoordWidth
== 0 )
660 fXScale
= (double)aLogicRect
.GetWidth() / (double)nWidth
;
664 if ( nCoordHeight
== 0 )
667 fYScale
= (double)aLogicRect
.GetHeight() / (double)nHeight
;
672 if ( (sal_uInt32
)nXRef
!= 0x80000000 && aLogicRect
.GetHeight() )
674 fXRatio
= (double)aLogicRect
.GetWidth() / (double)aLogicRect
.GetHeight();
682 if ( (sal_uInt32
)nYRef
!= 0x80000000 && aLogicRect
.GetWidth() )
684 fYRatio
= (double)aLogicRect
.GetHeight() / (double)aLogicRect
.GetWidth();
694 EnhancedCustomShape2d::EnhancedCustomShape2d( SdrObject
* pAObj
) :
695 SfxItemSet ( pAObj
->GetMergedItemSet() ),
696 pCustomShapeObj ( pAObj
),
697 eSpType ( mso_sptNil
),
700 nCoordWidthG ( 21600 ),
701 nCoordHeightG ( 21600 ),
702 bOOXMLShape ( false ),
703 nXRef ( 0x80000000 ),
704 nYRef ( 0x80000000 ),
707 bFilled ( static_cast<const XFillStyleItem
&>(pAObj
->GetMergedItem( XATTR_FILLSTYLE
)).GetValue() != drawing::FillStyle_NONE
),
708 bStroked ( static_cast<const XLineStyleItem
&>(pAObj
->GetMergedItem( XATTR_LINESTYLE
)).GetValue() != drawing::LineStyle_NONE
),
712 // bTextFlow needs to be set before clearing the TextDirection Item
714 ClearItem( SDRATTR_TEXTDIRECTION
); //SJ: vertical writing is not required, by removing this item no outliner is created
716 // #i105323# For 2D AutoShapes, the shadow attribute does not need to be applied to any
717 // of the constructed helper SdrObjects. This would lead to problems since the shadow
718 // of one helper object would fall on one helper object behind it (e.g. with the
719 // eyes of the smiley shape). This is not wanted; instead a single shadow 'behind'
720 // the AutoShape visualisation is wanted. This is done with primitive functionality
721 // now in SdrCustomShapePrimitive2D::create2DDecomposition, but only for 2D objects
722 // (see there and in EnhancedCustomShape3d::Create3DObject to read more).
723 // This exception may be removed later when AutoShapes will create primitives directly.
724 // So, currently remove the ShadowAttribute from the ItemSet to not apply it to any
726 ClearItem(SDRATTR_SHADOW
);
728 Point
aP( pCustomShapeObj
->GetSnapRect().Center() );
729 Size
aS( pCustomShapeObj
->GetLogicRect().GetSize() );
730 aP
.X() -= aS
.Width() / 2;
731 aP
.Y() -= aS
.Height() / 2;
732 aLogicRect
= tools::Rectangle( aP
, aS
);
735 const SdrCustomShapeGeometryItem
& rGeometryItem
= static_cast<const SdrCustomShapeGeometryItem
&>(pCustomShapeObj
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
));
736 const Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "Type" );
738 *pAny
>>= sShapeType
;
739 bOOXMLShape
= sShapeType
.startsWith("ooxml-");
740 SAL_INFO("svx", "shape type: " << sShapeType
<< " " << bOOXMLShape
);
742 eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
744 pAny
= rGeometryItem
.GetPropertyValueByName( "MirroredX" );
747 pAny
= rGeometryItem
.GetPropertyValueByName( "MirroredY" );
751 if ( dynamic_cast<const SdrObjCustomShape
*>( pCustomShapeObj
) != nullptr ) // should always be a SdrObjCustomShape, but you don't know
752 nRotateAngle
= (sal_Int32
)(static_cast<SdrObjCustomShape
*>(pCustomShapeObj
)->GetObjectRotation() * 100.0);
754 nRotateAngle
= pCustomShapeObj
->GetRotateAngle();
756 /*const sal_Int32* pDefData =*/ ApplyShapeAttributes( rGeometryItem
);
761 case mso_sptCan
: nColorData
= 0x20400000; break;
762 case mso_sptCube
: nColorData
= 0x302e0000; break;
763 case mso_sptActionButtonBlank
: nColorData
= 0x502ce400; break;
764 case mso_sptActionButtonHome
: nColorData
= 0x702ce4ce; break;
765 case mso_sptActionButtonHelp
: nColorData
= 0x602ce4c0; break;
766 case mso_sptActionButtonInformation
: nColorData
= 0x702ce4c5; break;
767 case mso_sptActionButtonBackPrevious
: nColorData
= 0x602ce4c0; break;
768 case mso_sptActionButtonForwardNext
: nColorData
= 0x602ce4c0; break;
769 case mso_sptActionButtonBeginning
: nColorData
= 0x602ce4c0; break;
770 case mso_sptActionButtonEnd
: nColorData
= 0x602ce4c0; break;
771 case mso_sptActionButtonReturn
: nColorData
= 0x602ce4c0; break;
772 case mso_sptActionButtonDocument
: nColorData
= 0x702ce4ec; break;
773 case mso_sptActionButtonSound
: nColorData
= 0x602ce4c0; break;
774 case mso_sptActionButtonMovie
: nColorData
= 0x602ce4c0; break;
775 case mso_sptBevel
: nColorData
= 0x502ce400; break;
776 case mso_sptFoldedCorner
: nColorData
= 0x20e00000; break;
777 case mso_sptSmileyFace
: nColorData
= 0x20e00000; break;
780 if( sShapeType
.getLength() > 4 &&
781 sShapeType
.match( "col-" ))
783 nColorData
= sShapeType
.copy( 4 ).toUInt32( 16 );
787 case mso_sptCurvedLeftArrow
:
788 case mso_sptCurvedRightArrow
:
789 case mso_sptCurvedUpArrow
:
790 case mso_sptCurvedDownArrow
: nColorData
= 0x20d00000; break;
791 case mso_sptRibbon2
: nColorData
= 0x30ee0000; break;
792 case mso_sptRibbon
: nColorData
= 0x30ee0000; break;
794 case mso_sptEllipseRibbon2
: nColorData
= 0x30ee0000; break;
795 case mso_sptEllipseRibbon
: nColorData
= 0x30ee0000; break;
797 case mso_sptVerticalScroll
: nColorData
= 0x30ee0000; break;
798 case mso_sptHorizontalScroll
: nColorData
= 0x30ee0000; break;
803 sal_Int32 i
, nLength
= seqEquations
.getLength();
807 vNodesSharedPtr
.resize( nLength
);
808 vEquationResults
.resize( nLength
);
809 for ( i
= 0; i
< seqEquations
.getLength(); i
++ )
811 vEquationResults
[ i
].bReady
= false;
814 vNodesSharedPtr
[ i
] = EnhancedCustomShape::FunctionParser::parseFunction( seqEquations
[ i
], *this );
816 catch ( EnhancedCustomShape::ParseError
& )
820 "error: equation number: " << i
<< ", parser failed ("
821 << seqEquations
[i
] << ")");
827 using EnhancedCustomShape::ExpressionFunct
;
829 double EnhancedCustomShape2d::GetEnumFunc( const ExpressionFunct eFunc
) const
834 case ExpressionFunct::EnumPi
: fRet
= F_PI
; break;
835 case ExpressionFunct::EnumLeft
: fRet
= 0.0; break;
836 case ExpressionFunct::EnumTop
: fRet
= 0.0; break;
837 case ExpressionFunct::EnumRight
: fRet
= (double)nCoordWidth
* fXRatio
; break;
838 case ExpressionFunct::EnumBottom
: fRet
= (double)nCoordHeight
* fYRatio
; break;
839 case ExpressionFunct::EnumXStretch
: fRet
= nXRef
; break;
840 case ExpressionFunct::EnumYStretch
: fRet
= nYRef
; break;
841 case ExpressionFunct::EnumHasStroke
: fRet
= bStroked
? 1.0 : 0.0; break;
842 case ExpressionFunct::EnumHasFill
: fRet
= bFilled
? 1.0 : 0.0; break;
843 case ExpressionFunct::EnumWidth
: fRet
= nCoordWidth
; break;
844 case ExpressionFunct::EnumHeight
: fRet
= nCoordHeight
; break;
845 case ExpressionFunct::EnumLogWidth
: fRet
= aLogicRect
.GetWidth(); break;
846 case ExpressionFunct::EnumLogHeight
: fRet
= aLogicRect
.GetHeight(); break;
851 double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex
) const
853 double fNumber
= 0.0;
854 if ( nIndex
< seqAdjustmentValues
.getLength() )
856 if ( seqAdjustmentValues
[ nIndex
].Value
.getValueTypeClass() == TypeClass_DOUBLE
)
857 seqAdjustmentValues
[ nIndex
].Value
>>= fNumber
;
860 sal_Int32 nNumber
= 0;
861 seqAdjustmentValues
[ nIndex
].Value
>>= nNumber
;
862 fNumber
= (double)nNumber
;
867 double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex
) const
869 double fNumber
= 0.0;
870 static sal_uInt32 nLevel
= 0;
871 if ( nIndex
< (sal_Int32
)vNodesSharedPtr
.size() )
873 if ( vNodesSharedPtr
[ nIndex
].get() ) {
877 if ( vEquationResults
[ nIndex
].bReady
)
878 fNumber
= vEquationResults
[ nIndex
].fValue
;
880 // cast to non const, so that we can optimize by caching
881 // equation results, without changing all the const in the stack
882 struct EquationResult
&aResult
= const_cast<EnhancedCustomShape2d
*>(this)->vEquationResults
[ nIndex
];
884 fNumber
= aResult
.fValue
= (*vNodesSharedPtr
[ nIndex
])();
885 aResult
.bReady
= true;
887 if ( !rtl::math::isFinite( fNumber
) )
889 SAL_INFO("svx", "equation " << nLevel
<< " (level: " << seqEquations
[nIndex
] << "): "
890 << fNumber
<< " --> " << 180.0*fNumber
/10800000.0);
895 SAL_WARN("svx", "EnhancedCustomShape2d::GetEquationValueAsDouble failed");
901 "?" << nIndex
<< " --> " << fNumber
<< " (angle: "
902 << 180.0*fNumber
/10800000.0 << ")");
908 bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double& rValue
, const sal_Int32 nIndex
)
910 bool bRetValue
= false;
911 if ( nIndex
< seqAdjustmentValues
.getLength() )
913 // updating our local adjustment sequence
914 seqAdjustmentValues
[ nIndex
].Value
<<= rValue
;
915 seqAdjustmentValues
[ nIndex
].State
= css::beans::PropertyState_DIRECT_VALUE
;
921 Point
EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair
& rPair
,
922 const bool bScale
, const bool bReplaceGeoSize
) const
925 sal_uInt32 nPass
= 0;
928 sal_uInt32 nIndex
= nPass
;
931 const EnhancedCustomShapeParameter
& rParameter
= nIndex
? rPair
.Second
: rPair
.First
;
932 if ( nPass
) // height
934 GetParameter( fVal
, rParameter
, false, bReplaceGeoSize
);
940 aRetValue
.Y() = (sal_Int32
)fVal
;
944 GetParameter( fVal
, rParameter
, bReplaceGeoSize
, false );
950 aRetValue
.X() = static_cast<long>(fVal
);
953 while ( ++nPass
< 2 );
957 void EnhancedCustomShape2d::GetParameter( double& rRetValue
, const EnhancedCustomShapeParameter
& rParameter
,
958 const bool bReplaceGeoWidth
, const bool bReplaceGeoHeight
) const
961 switch ( rParameter
.Type
)
963 case EnhancedCustomShapeParameterType::ADJUSTMENT
:
965 sal_Int32 nAdjustmentIndex
= 0;
966 if ( rParameter
.Value
>>= nAdjustmentIndex
)
968 rRetValue
= GetAdjustValueAsDouble( nAdjustmentIndex
);
972 case EnhancedCustomShapeParameterType::EQUATION
:
974 sal_Int32 nEquationIndex
= 0;
975 if ( rParameter
.Value
>>= nEquationIndex
)
977 rRetValue
= GetEquationValueAsDouble( nEquationIndex
);
981 case EnhancedCustomShapeParameterType::NORMAL
:
983 if ( rParameter
.Value
.getValueTypeClass() == TypeClass_DOUBLE
)
986 if ( rParameter
.Value
>>= fValue
)
993 sal_Int32 nValue
= 0;
994 if ( rParameter
.Value
>>= nValue
)
997 if ( bReplaceGeoWidth
&& ( nValue
== nCoordWidth
) )
998 rRetValue
*= fXRatio
;
999 else if ( bReplaceGeoHeight
&& ( nValue
== nCoordHeight
) )
1000 rRetValue
*= fYRatio
;
1005 case EnhancedCustomShapeParameterType::LEFT
:
1010 case EnhancedCustomShapeParameterType::TOP
:
1015 case EnhancedCustomShapeParameterType::RIGHT
:
1017 rRetValue
= nCoordWidth
;
1020 case EnhancedCustomShapeParameterType::BOTTOM
:
1022 rRetValue
= nCoordHeight
;
1028 // nLumDat 28-31 = number of luminance entries in nLumDat
1029 // nLumDat 27-24 = nLumDatEntry 0
1030 // nLumDat 23-20 = nLumDatEntry 1 ...
1031 // each 4bit entry is to be interpreted as a 10 percent signed luminance changing
1032 sal_Int32
EnhancedCustomShape2d::GetLuminanceChange( sal_uInt32 nIndex
) const
1034 const sal_uInt32 nCount
= nColorData
>> 28;
1038 if ( nIndex
>= nCount
)
1039 nIndex
= nCount
- 1;
1041 const sal_Int32 nLumDat
= nColorData
<< ( ( 1 + nIndex
) << 2 );
1042 return ( nLumDat
>> 28 ) * 10;
1045 Color
EnhancedCustomShape2d::GetColorData( const Color
& rFillColor
, sal_uInt32 nIndex
, double dBrightness
) const
1047 if ( bOOXMLShape
|| ( mso_sptMin
== eSpType
/* ODF "non-primitive" */ ) )
1048 { //do LibreOffice way, using dBrightness
1049 if ( dBrightness
== 0.0)
1055 if (dBrightness
>=0.0)
1056 { //lighten, blending with white
1057 return Color( (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetRed() * (1.0-dBrightness
) + dBrightness
* 255.0, 0.0, 255.0) ),
1058 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetGreen() * (1.0-dBrightness
) + dBrightness
* 255.0, 0.0, 255.0) ),
1059 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetBlue() * (1.0-dBrightness
) + dBrightness
* 255.0, 0.0, 255.0) ) );
1062 { //darken (indicated by negative sign), blending with black
1063 return Color( (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetRed() * (1.0+dBrightness
), 0.0, 255.0) ),
1064 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetGreen() * (1.0+dBrightness
), 0.0, 255.0) ),
1065 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(rFillColor
.GetBlue() * (1.0+dBrightness
), 0.0, 255.0) ) );
1070 { //do OpenOffice way, using nColorData
1071 const sal_Int32 nLuminance
= GetLuminanceChange(nIndex
);
1075 basegfx::BColor aHSVColor
=
1076 basegfx::tools::rgb2hsv(
1077 basegfx::BColor(rFillColor
.GetRed()/255.0,
1078 rFillColor
.GetGreen()/255.0,
1079 rFillColor
.GetBlue()/255.0));
1081 if( nLuminance
> 0 )
1084 aHSVColor
.getGreen() * (1.0-nLuminance
/100.0));
1087 (1.0-nLuminance
/100.0)*aHSVColor
.getBlue());
1089 else if( nLuminance
< 0 )
1092 (1.0+nLuminance
/100.0)*aHSVColor
.getBlue());
1095 aHSVColor
= basegfx::tools::hsv2rgb(aHSVColor
);
1096 return Color( (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(aHSVColor
.getRed(),0.0,1.0) * 255.0 + 0.5 ),
1097 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(aHSVColor
.getGreen(),0.0,1.0) * 255.0 + 0.5 ),
1098 (sal_uInt8
)static_cast< sal_Int32
>( basegfx::clamp(aHSVColor
.getBlue(),0.0,1.0) * 255.0 + 0.5 ) );
1102 tools::Rectangle
EnhancedCustomShape2d::GetTextRect() const
1104 sal_Int32 nIndex
, nSize
= seqTextFrames
.getLength();
1108 if ( bTextFlow
&& ( nSize
> 1 ) )
1110 Point
aTopLeft( GetPoint( seqTextFrames
[ nIndex
].TopLeft
, !bOOXMLShape
, true ) );
1111 Point
aBottomRight( GetPoint( seqTextFrames
[ nIndex
].BottomRight
, !bOOXMLShape
, true ) );
1114 aTopLeft
.X() = aLogicRect
.GetWidth() - aTopLeft
.X();
1115 aBottomRight
.X() = aLogicRect
.GetWidth() - aBottomRight
.X();
1119 aTopLeft
.Y() = aLogicRect
.GetHeight() - aTopLeft
.Y();
1120 aBottomRight
.Y() = aLogicRect
.GetHeight() - aBottomRight
.Y();
1122 tools::Rectangle
aRect( aTopLeft
, aBottomRight
);
1123 SAL_INFO("svx", aRect
.GetWidth() << " x " << aRect
.GetHeight());
1124 if( aRect
.GetWidth() <= 1 || aRect
.GetHeight() <= 1 )
1126 aRect
.Move( aLogicRect
.Left(), aLogicRect
.Top() );
1131 sal_uInt32
EnhancedCustomShape2d::GetHdlCount() const
1133 return seqHandles
.getLength();
1136 bool EnhancedCustomShape2d::GetHandlePosition( const sal_uInt32 nIndex
, Point
& rReturnPosition
) const
1138 bool bRetValue
= false;
1139 if ( nIndex
< GetHdlCount() )
1142 if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles
[ nIndex
], aHandle
) )
1144 if ( aHandle
.nFlags
& HandleFlags::POLAR
)
1146 Point
aReferencePoint( GetPoint( aHandle
.aPolar
) );
1150 GetParameter( fRadius
, aHandle
.aPosition
.First
, false, false );
1151 GetParameter( fAngle
, aHandle
.aPosition
.Second
, false, false );
1153 double a
= ( 360.0 - fAngle
) * F_PI180
;
1154 double dx
= fRadius
* fXScale
;
1155 double fX
= dx
* cos( a
);
1156 double fY
=-dx
* sin( a
);
1159 svx::Round( fX
+ aReferencePoint
.X() ),
1160 basegfx::fTools::equalZero(fXScale
) ? aReferencePoint
.Y() :
1161 svx::Round( ( fY
* fYScale
) / fXScale
+ aReferencePoint
.Y() ) );
1165 if ( aHandle
.nFlags
& HandleFlags::SWITCHED
)
1167 if ( aLogicRect
.GetHeight() > aLogicRect
.GetWidth() )
1169 css::drawing::EnhancedCustomShapeParameter aFirst
= aHandle
.aPosition
.First
;
1170 css::drawing::EnhancedCustomShapeParameter aSecond
= aHandle
.aPosition
.Second
;
1171 aHandle
.aPosition
.First
= aSecond
;
1172 aHandle
.aPosition
.Second
= aFirst
;
1175 rReturnPosition
= GetPoint( aHandle
.aPosition
);
1177 const GeoStat
aGeoStat( static_cast<SdrObjCustomShape
*>(pCustomShapeObj
)->GetGeoStat() );
1178 if ( aGeoStat
.nShearAngle
)
1180 double nTan
= aGeoStat
.nTan
;
1181 if ((bFlipV
&&!bFlipH
)||(bFlipH
&&!bFlipV
))
1183 ShearPoint( rReturnPosition
, Point( aLogicRect
.GetWidth() / 2, aLogicRect
.GetHeight() / 2 ), nTan
);
1187 double a
= nRotateAngle
* F_PI18000
;
1188 RotatePoint( rReturnPosition
, Point( aLogicRect
.GetWidth() / 2, aLogicRect
.GetHeight() / 2 ), sin( a
), cos( a
) );
1191 rReturnPosition
.X() = aLogicRect
.GetWidth() - rReturnPosition
.X();
1193 rReturnPosition
.Y() = aLogicRect
.GetHeight() - rReturnPosition
.Y();
1194 rReturnPosition
.Move( aLogicRect
.Left(), aLogicRect
.Top() );
1201 bool EnhancedCustomShape2d::SetHandleControllerPosition( const sal_uInt32 nIndex
, const css::awt::Point
& rPosition
)
1203 bool bRetValue
= false;
1204 if ( nIndex
< GetHdlCount() )
1207 if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles
[ nIndex
], aHandle
) )
1209 Point
aP( rPosition
.X
, rPosition
.Y
);
1210 // apply the negative object rotation to the controller position
1212 aP
.Move( -aLogicRect
.Left(), -aLogicRect
.Top() );
1214 aP
.X() = aLogicRect
.GetWidth() - aP
.X();
1216 aP
.Y() = aLogicRect
.GetHeight() - aP
.Y();
1219 double a
= -nRotateAngle
* F_PI18000
;
1220 RotatePoint( aP
, Point( aLogicRect
.GetWidth() / 2, aLogicRect
.GetHeight() / 2 ), sin( a
), cos( a
) );
1222 const GeoStat
aGeoStat( static_cast<SdrObjCustomShape
*>(pCustomShapeObj
)->GetGeoStat() );
1223 if ( aGeoStat
.nShearAngle
)
1225 double nTan
= -aGeoStat
.nTan
;
1226 if ((bFlipV
&&!bFlipH
)||(bFlipH
&&!bFlipV
))
1228 ShearPoint( aP
, Point( aLogicRect
.GetWidth() / 2, aLogicRect
.GetHeight() / 2 ), nTan
);
1231 double fPos1
= aP
.X(); //( bFlipH ) ? aLogicRect.GetWidth() - aP.X() : aP.X();
1232 double fPos2
= aP
.Y(); //( bFlipV ) ? aLogicRect.GetHeight() -aP.Y() : aP.Y();
1236 // Used for scaling the adjustment values based on handle positions
1240 if ( nCoordWidth
|| nCoordHeight
)
1242 fWidth
= nCoordWidth
;
1243 fHeight
= nCoordHeight
;
1247 fWidth
= aLogicRect
.GetWidth();
1248 fHeight
= aLogicRect
.GetHeight();
1251 if ( aHandle
.nFlags
& HandleFlags::SWITCHED
)
1253 if ( aLogicRect
.GetHeight() > aLogicRect
.GetWidth() )
1257 double fTmp
= fWidth
;
1265 sal_Int32 nFirstAdjustmentValue
= -1, nSecondAdjustmentValue
= -1;
1267 if ( aHandle
.aPosition
.First
.Type
== EnhancedCustomShapeParameterType::ADJUSTMENT
)
1268 aHandle
.aPosition
.First
.Value
>>= nFirstAdjustmentValue
;
1269 if ( aHandle
.aPosition
.Second
.Type
== EnhancedCustomShapeParameterType::ADJUSTMENT
)
1270 aHandle
.aPosition
.Second
.Value
>>= nSecondAdjustmentValue
;
1273 // DrawingML polar handles set REFR or REFANGLE instead of POLAR
1274 if ( aHandle
.nFlags
& ( HandleFlags::POLAR
| HandleFlags::REFR
| HandleFlags::REFANGLE
) )
1276 double fXRef
, fYRef
, fAngle
;
1277 if ( aHandle
.nFlags
& HandleFlags::POLAR
)
1279 GetParameter( fXRef
, aHandle
.aPolar
.First
, false, false );
1280 GetParameter( fYRef
, aHandle
.aPolar
.Second
, false, false );
1284 // DrawingML polar handles don't have reference center.
1286 fYRef
= fHeight
/ 2;
1288 const double fDX
= fPos1
- fXRef
;
1289 fAngle
= -( atan2( -fPos2
+ fYRef
, ( ( fDX
== 0.0L ) ? 0.000000001 : fDX
) ) / F_PI180
);
1290 double fX
= ( fPos1
- fXRef
);
1291 double fY
= ( fPos2
- fYRef
);
1292 double fRadius
= sqrt( fX
* fX
+ fY
* fY
);
1293 if ( aHandle
.nFlags
& HandleFlags::RADIUS_RANGE_MINIMUM
)
1296 GetParameter( fMin
, aHandle
.aRadiusRangeMinimum
, false, false );
1297 if ( fRadius
< fMin
)
1300 if ( aHandle
.nFlags
& HandleFlags::RADIUS_RANGE_MAXIMUM
)
1303 GetParameter( fMax
, aHandle
.aRadiusRangeMaximum
, false, false );
1304 if ( fRadius
> fMax
)
1307 if (aHandle
.nFlags
& HandleFlags::REFR
)
1309 fRadius
*= 100000.0;
1310 fRadius
/= sqrt( fWidth
* fWidth
+ fHeight
* fHeight
);
1311 nFirstAdjustmentValue
= aHandle
.nRefR
;
1313 if (aHandle
.nFlags
& HandleFlags::REFANGLE
)
1317 // Adjustment value referred by nRefAngle needs to be in 60000th a degree
1318 // from 0 to 21600000.
1320 nSecondAdjustmentValue
= aHandle
.nRefAngle
;
1322 if ( nFirstAdjustmentValue
>= 0 )
1323 SetAdjustValueAsDouble( fRadius
, nFirstAdjustmentValue
);
1324 if ( nSecondAdjustmentValue
>= 0 )
1325 SetAdjustValueAsDouble( fAngle
, nSecondAdjustmentValue
);
1329 if ( aHandle
.nFlags
& HandleFlags::REFX
)
1331 nFirstAdjustmentValue
= aHandle
.nRefX
;
1335 if ( aHandle
.nFlags
& HandleFlags::REFY
)
1337 nSecondAdjustmentValue
= aHandle
.nRefY
;
1341 if ( nFirstAdjustmentValue
>= 0 )
1343 if ( aHandle
.nFlags
& HandleFlags::RANGE_X_MINIMUM
) // check if horizontal handle needs to be within a range
1346 GetParameter( fXMin
, aHandle
.aXRangeMinimum
, false, false );
1347 if ( fPos1
< fXMin
)
1350 if ( aHandle
.nFlags
& HandleFlags::RANGE_X_MAXIMUM
) // check if horizontal handle needs to be within a range
1353 GetParameter( fXMax
, aHandle
.aXRangeMaximum
, false, false );
1354 if ( fPos1
> fXMax
)
1357 SetAdjustValueAsDouble( fPos1
, nFirstAdjustmentValue
);
1359 if ( nSecondAdjustmentValue
>= 0 )
1361 if ( aHandle
.nFlags
& HandleFlags::RANGE_Y_MINIMUM
) // check if vertical handle needs to be within a range
1364 GetParameter( fYMin
, aHandle
.aYRangeMinimum
, false, false );
1365 if ( fPos2
< fYMin
)
1368 if ( aHandle
.nFlags
& HandleFlags::RANGE_Y_MAXIMUM
) // check if vertical handle needs to be within a range
1371 GetParameter( fYMax
, aHandle
.aYRangeMaximum
, false, false );
1372 if ( fPos2
> fYMax
)
1375 SetAdjustValueAsDouble( fPos2
, nSecondAdjustmentValue
);
1378 // and writing them back into the GeometryItem
1379 SdrCustomShapeGeometryItem
aGeometryItem(
1380 static_cast<const SdrCustomShapeGeometryItem
&>(pCustomShapeObj
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
)));
1381 css::beans::PropertyValue aPropVal
;
1382 aPropVal
.Name
= "AdjustmentValues";
1383 aPropVal
.Value
<<= seqAdjustmentValues
;
1384 aGeometryItem
.SetPropertyValue( aPropVal
);
1385 pCustomShapeObj
->SetMergedItem( aGeometryItem
);
1392 void EnhancedCustomShape2d::SwapStartAndEndArrow( SdrObject
* pObj
) //#108274
1394 XLineStartItem aLineStart
;
1395 aLineStart
.SetLineStartValue(static_cast<const XLineStartItem
&>(pObj
->GetMergedItem( XATTR_LINEEND
)).GetLineStartValue());
1396 XLineStartWidthItem
aLineStartWidth(static_cast<const XLineStartWidthItem
&>(pObj
->GetMergedItem( XATTR_LINEENDWIDTH
)).GetValue());
1397 XLineStartCenterItem
aLineStartCenter(static_cast<const XLineStartCenterItem
&>(pObj
->GetMergedItem( XATTR_LINEENDCENTER
)).GetValue());
1399 XLineEndItem aLineEnd
;
1400 aLineEnd
.SetLineEndValue(static_cast<const XLineEndItem
&>(pObj
->GetMergedItem( XATTR_LINESTART
)).GetLineEndValue());
1401 XLineEndWidthItem
aLineEndWidth(static_cast<const XLineEndWidthItem
&>(pObj
->GetMergedItem( XATTR_LINESTARTWIDTH
)).GetValue());
1402 XLineEndCenterItem
aLineEndCenter(static_cast<const XLineEndCenterItem
&>(pObj
->GetMergedItem( XATTR_LINESTARTCENTER
)).GetValue());
1404 pObj
->SetMergedItem( aLineStart
);
1405 pObj
->SetMergedItem( aLineStartWidth
);
1406 pObj
->SetMergedItem( aLineStartCenter
);
1407 pObj
->SetMergedItem( aLineEnd
);
1408 pObj
->SetMergedItem( aLineEndWidth
);
1409 pObj
->SetMergedItem( aLineEndCenter
);
1412 static basegfx::B2DPolygon
CreateArc( const tools::Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
, const bool bClockwise
, bool bFullCircle
= false )
1414 tools::Rectangle
aRect( rRect
);
1415 Point
aStart( rStart
);
1418 sal_Int32 bSwapStartEndAngle
= 0;
1420 if ( aRect
.Left() > aRect
.Right() )
1421 bSwapStartEndAngle
^= 0x01;
1422 if ( aRect
.Top() > aRect
.Bottom() )
1423 bSwapStartEndAngle
^= 0x11;
1424 if ( bSwapStartEndAngle
)
1427 if ( bSwapStartEndAngle
& 1 )
1429 Point
aTmp( aStart
);
1435 tools::Polygon
aTempPoly( aRect
, aStart
, aEnd
, PolyStyle::Arc
, bFullCircle
);
1436 basegfx::B2DPolygon aRetval
;
1440 for ( sal_uInt16 j
= aTempPoly
.GetSize(); j
--; )
1442 aRetval
.append(basegfx::B2DPoint(aTempPoly
[ j
].X(), aTempPoly
[ j
].Y()));
1447 for ( sal_uInt16 j
= 0; j
< aTempPoly
.GetSize(); j
++ )
1449 aRetval
.append(basegfx::B2DPoint(aTempPoly
[ j
].X(), aTempPoly
[ j
].Y()));
1456 void EnhancedCustomShape2d::CreateSubPath( sal_Int32
& rSrcPt
, sal_Int32
& rSegmentInd
, std::vector
< SdrPathObj
* >& rObjectList
,
1457 const bool bLineGeometryNeededOnly
,
1458 const bool bSortFilledObjectsToBack
,
1461 bool bNoFill
= false;
1462 bool bNoStroke
= false;
1463 double dBrightness
= 0.0; //no blending
1465 basegfx::B2DPolyPolygon aNewB2DPolyPolygon
;
1466 basegfx::B2DPolygon aNewB2DPolygon
;
1468 SetPathSize( nIndex
);
1470 sal_Int32 nCoordSize
= seqCoordinates
.getLength();
1471 sal_Int32 nSegInfoSize
= seqSegments
.getLength();
1472 if ( !nSegInfoSize
)
1474 const EnhancedCustomShapeParameterPair
* pTmp
= seqCoordinates
.getArray();
1476 for ( sal_Int32
nPtNum(0L); nPtNum
< nCoordSize
; nPtNum
++ )
1478 const Point
aTempPoint(GetPoint( *pTmp
++, true, true ));
1479 aNewB2DPolygon
.append(basegfx::B2DPoint(aTempPoint
.X(), aTempPoint
.Y()));
1482 aNewB2DPolygon
.setClosed(true);
1486 for ( ;rSegmentInd
< nSegInfoSize
; )
1488 sal_Int16 nCommand
= seqSegments
[ rSegmentInd
].Command
;
1489 sal_Int16 nPntCount
= seqSegments
[ rSegmentInd
++ ].Count
;
1500 dBrightness
= -0.4; //use sign to distinguish DARKEN from LIGHTEN
1513 if(aNewB2DPolygon
.count() > 1L)
1515 // #i76201# Add conversion to closed polygon when first and last points are equal
1516 basegfx::tools::checkClosed(aNewB2DPolygon
);
1517 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1520 aNewB2DPolygon
.clear();
1522 if ( rSrcPt
< nCoordSize
)
1524 const Point
aTempPoint(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1527 "moveTo: " << aTempPoint
.X() << ","
1529 aNewB2DPolygon
.append(basegfx::B2DPoint(aTempPoint
.X(), aTempPoint
.Y()));
1537 if(aNewB2DPolygon
.count())
1539 if(aNewB2DPolygon
.count() > 1L)
1541 aNewB2DPolygon
.setClosed(true);
1542 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1545 aNewB2DPolygon
.clear();
1551 for ( sal_uInt16 i
= 0; ( i
< nPntCount
) && ( ( rSrcPt
+ 2 ) < nCoordSize
); i
++ )
1553 const Point
aControlA(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1554 const Point
aControlB(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1555 const Point
aEnd(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1557 DBG_ASSERT(aNewB2DPolygon
.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding control point (!)");
1558 aNewB2DPolygon
.appendBezierSegment(
1559 basegfx::B2DPoint(aControlA
.X(), aControlA
.Y()),
1560 basegfx::B2DPoint(aControlB
.X(), aControlB
.Y()),
1561 basegfx::B2DPoint(aEnd
.X(), aEnd
.Y()));
1570 if(aNewB2DPolygon
.count() > 1L)
1572 // #i76201# Add conversion to closed polygon when first and last points are equal
1573 basegfx::tools::checkClosed(aNewB2DPolygon
);
1574 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1576 aNewB2DPolygon
.clear();
1580 case ANGLEELLIPSETO
:
1582 for ( sal_uInt16 i
= 0; ( i
< nPntCount
) && ( ( rSrcPt
+ 2 ) < nCoordSize
); i
++ )
1586 double fWidth
, fHeight
;
1587 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( mso_sptEllipse
);
1588 bool bIsDefaultViewBox
= false;
1589 bool bIsDefaultPath
= false;
1590 bool bIsMSEllipse
= false;
1592 if( ( nCoordWidth
== pDefCustomShape
->nCoordWidth
)
1593 && ( nCoordHeight
== pDefCustomShape
->nCoordHeight
) )
1594 bIsDefaultViewBox
= true;
1595 sal_Int32 j
, nCount
= pDefCustomShape
->nVertices
;//==3
1596 std::vector
< css::drawing::EnhancedCustomShapeParameterPair
> seqCoordinates1
, seqCoordinates2
;
1598 seqCoordinates1
.resize( nCount
);
1599 for ( j
= 0; j
< nCount
; j
++ )
1601 seqCoordinates1
[j
] = seqCoordinates
[ rSrcPt
+ j
];
1604 seqCoordinates2
.resize( nCount
);
1605 for ( j
= 0; j
< nCount
; j
++ )
1607 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2
[ j
].First
, pDefCustomShape
->pVertices
[ j
].nValA
);
1608 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2
[ j
].Second
, pDefCustomShape
->pVertices
[ j
].nValB
);
1610 if(seqCoordinates1
== seqCoordinates2
)
1611 bIsDefaultPath
= true;
1614 SdrCustomShapeGeometryItem
& rGeometryItem
= const_cast<SdrCustomShapeGeometryItem
&>(static_cast<const SdrCustomShapeGeometryItem
&>(pCustomShapeObj
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
)));
1615 Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "Type" );
1618 if( sShpType
.getLength() > 3 &&
1619 sShpType
.startsWith( "mso" )){
1620 bIsMSEllipse
= true;
1622 if( (! bIsDefaultPath
&& ! bIsDefaultViewBox
) || (bIsDefaultViewBox
&& bIsMSEllipse
) /*&& (nGeneratorVersion == SfxObjectShell::Sym_L2)*/ )
1624 _aCenter
= GetPoint( seqCoordinates
[ rSrcPt
], true, true );
1625 GetParameter( fWidth
, seqCoordinates
[ rSrcPt
+ 1 ].First
, true, false );
1626 GetParameter( fHeight
, seqCoordinates
[ rSrcPt
+ 1 ].Second
, false, true );
1629 }else if( bIsDefaultPath
&& !bIsDefaultViewBox
/*&& (nGeneratorVersion == SfxObjectShell::Sym_L2)*/ )
1631 _aCenter
.X() = nCoordWidth
/2 * fXScale
;
1632 _aCenter
.Y() = nCoordHeight
/2 * fYScale
;
1633 fWidth
= nCoordWidth
/2;
1634 fHeight
= nCoordHeight
/2;
1635 const Any
* pViewBox
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( "ViewBox" );
1636 css::awt::Rectangle aViewBox
;
1637 if ( pViewBox
&& (*pViewBox
>>= aViewBox
) )
1639 aViewBox
.Width
= pDefCustomShape
->nCoordWidth
;
1640 aViewBox
.Height
= pDefCustomShape
->nCoordHeight
;
1642 css::beans::PropertyValue aPropVal
;
1643 aPropVal
.Name
= "ViewBox";
1644 aPropVal
.Value
<<= aViewBox
;
1645 rGeometryItem
.SetPropertyValue( aPropVal
);
1646 pCustomShapeObj
->SetMergedItem( rGeometryItem
);
1648 _aCenter
= GetPoint( seqCoordinates
[ rSrcPt
], true, true );
1649 GetParameter( fWidth
, seqCoordinates
[ rSrcPt
+ 1 ].First
, true, false);
1650 GetParameter( fHeight
, seqCoordinates
[ rSrcPt
+ 1 ].Second
, false, true );
1655 Point
aP( (sal_Int32
)( _aCenter
.X() - fWidth
), (sal_Int32
)( _aCenter
.Y() - fHeight
) );
1656 Size
aS( (sal_Int32
)( fWidth
* 2.0 ), (sal_Int32
)( fHeight
* 2.0 ) );
1657 tools::Rectangle
aRect( aP
, aS
);
1658 if ( aRect
.GetWidth() && aRect
.GetHeight() )
1660 double fStartAngle
, fEndAngle
;
1661 GetParameter( fStartAngle
, seqCoordinates
[ rSrcPt
+ 2 ].First
, false, false );
1662 GetParameter( fEndAngle
, seqCoordinates
[ rSrcPt
+ 2 ].Second
, false, false );
1664 if ( ((sal_Int32
)fStartAngle
% 360) != ((sal_Int32
)fEndAngle
% 360) )
1666 if ( (sal_Int32
)fStartAngle
& 0x7fff0000 ) // SJ: if the angle was imported from our escher import, then the
1667 fStartAngle
/= 65536.0; // value is shifted by 16. TODO: already change the fixed float to a
1668 if ( (sal_Int32
)fEndAngle
& 0x7fff0000 ) // double in the import filter
1670 fEndAngle
/= 65536.0;
1671 fEndAngle
= fEndAngle
+ fStartAngle
;
1672 if ( fEndAngle
< 0 )
1673 { // in the binary filter the endangle is the amount
1674 double fTemp
= fStartAngle
;
1675 fStartAngle
= fEndAngle
;
1679 double fCenterX
= aRect
.Center().X();
1680 double fCenterY
= aRect
.Center().Y();
1681 double fx1
= ( cos( fStartAngle
* F_PI180
) * 65536.0 * fXScale
) + fCenterX
;
1682 double fy1
= ( -sin( fStartAngle
* F_PI180
) * 65536.0 * fYScale
) + fCenterY
;
1683 double fx2
= ( cos( fEndAngle
* F_PI180
) * 65536.0 * fXScale
) + fCenterX
;
1684 double fy2
= ( -sin( fEndAngle
* F_PI180
) * 65536.0 * fYScale
) + fCenterY
;
1685 aNewB2DPolygon
.append(CreateArc( aRect
, Point( (sal_Int32
)fx1
, (sal_Int32
)fy1
), Point( (sal_Int32
)fx2
, (sal_Int32
)fy2
), false));
1688 { /* SJ: TODO: this block should be replaced sometimes, because the current point
1689 is not set correct, it also does not use the correct moveto
1690 point if ANGLEELLIPSETO was used, but the method CreateArc
1691 is at the moment not able to draw full circles (if startangle is 0
1692 and endangle 360 nothing is painted :-( */
1693 sal_Int32 nXControl
= (sal_Int32
)((double)aRect
.GetWidth() * 0.2835 );
1694 sal_Int32 nYControl
= (sal_Int32
)((double)aRect
.GetHeight() * 0.2835 );
1695 Point
aCenter( aRect
.Center() );
1697 // append start point
1698 aNewB2DPolygon
.append(basegfx::B2DPoint(aCenter
.X(), aRect
.Top()));
1700 // append four bezier segments
1701 aNewB2DPolygon
.appendBezierSegment(
1702 basegfx::B2DPoint(aCenter
.X() + nXControl
, aRect
.Top()),
1703 basegfx::B2DPoint(aRect
.Right(), aCenter
.Y() - nYControl
),
1704 basegfx::B2DPoint(aRect
.Right(), aCenter
.Y()));
1706 aNewB2DPolygon
.appendBezierSegment(
1707 basegfx::B2DPoint(aRect
.Right(), aCenter
.Y() + nYControl
),
1708 basegfx::B2DPoint(aCenter
.X() + nXControl
, aRect
.Bottom()),
1709 basegfx::B2DPoint(aCenter
.X(), aRect
.Bottom()));
1711 aNewB2DPolygon
.appendBezierSegment(
1712 basegfx::B2DPoint(aCenter
.X() - nXControl
, aRect
.Bottom()),
1713 basegfx::B2DPoint(aRect
.Left(), aCenter
.Y() + nYControl
),
1714 basegfx::B2DPoint(aRect
.Left(), aCenter
.Y()));
1716 aNewB2DPolygon
.appendBezierSegment(
1717 basegfx::B2DPoint(aRect
.Left(), aCenter
.Y() - nYControl
),
1718 basegfx::B2DPoint(aCenter
.X() - nXControl
, aRect
.Top()),
1719 basegfx::B2DPoint(aCenter
.X(), aRect
.Top()));
1721 // close, rescue last controlpoint, remove double last point
1722 basegfx::tools::closeWithGeometryChange(aNewB2DPolygon
);
1730 case QUADRATICCURVETO
:
1732 for ( sal_Int32
i(0L); ( i
< nPntCount
) && ( rSrcPt
+ 1 < nCoordSize
); i
++ )
1736 const Point
aPreviousEndPoint(GetPoint( seqCoordinates
[ rSrcPt
- 1 ], true, true));
1737 const Point
aControlQ(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1738 const Point
aEnd(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1739 const Point
aControlA((aPreviousEndPoint
+ (aControlQ
* 2)) / 3);
1740 const Point
aControlB(((aControlQ
* 2) + aEnd
) / 3);
1742 DBG_ASSERT(aNewB2DPolygon
.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding Q control point (!)");
1743 aNewB2DPolygon
.appendBezierSegment(
1744 basegfx::B2DPoint(aControlA
.X(), aControlA
.Y()),
1745 basegfx::B2DPoint(aControlB
.X(), aControlB
.Y()),
1746 basegfx::B2DPoint(aEnd
.X(), aEnd
.Y()));
1748 else // no previous point , do a moveto
1750 rSrcPt
++; // skip control point
1751 const Point
aEnd(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1753 DBG_ASSERT(aNewB2DPolygon
.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding Q control point (!)");
1754 aNewB2DPolygon
.append(basegfx::B2DPoint(aEnd
.X(), aEnd
.Y()));
1762 for ( sal_Int32
i(0L); ( i
< nPntCount
) && ( rSrcPt
< nCoordSize
); i
++ )
1764 const Point
aTempPoint(GetPoint( seqCoordinates
[ rSrcPt
++ ], true, true ));
1767 "lineTo: " << aTempPoint
.X() << ","
1769 aNewB2DPolygon
.append(basegfx::B2DPoint(aTempPoint
.X(), aTempPoint
.Y()));
1777 if(aNewB2DPolygon
.count() > 1L)
1779 // #i76201# Add conversion to closed polygon when first and last points are equal
1780 basegfx::tools::checkClosed(aNewB2DPolygon
);
1781 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1784 aNewB2DPolygon
.clear();
1789 case CLOCKWISEARCTO
:
1791 bool bClockwise
= ( nCommand
== CLOCKWISEARC
) || ( nCommand
== CLOCKWISEARCTO
);
1792 sal_uInt32 nXor
= bClockwise
? 3 : 2;
1793 for ( sal_uInt16 i
= 0; ( i
< nPntCount
) && ( ( rSrcPt
+ 3 ) < nCoordSize
); i
++ )
1795 tools::Rectangle
aRect( GetPoint( seqCoordinates
[ rSrcPt
], true, true ), GetPoint( seqCoordinates
[ rSrcPt
+ 1 ], true, true ) );
1796 if ( aRect
.GetWidth() && aRect
.GetHeight() )
1798 Point
aCenter( aRect
.Center() );
1799 Point
aStart( GetPoint( seqCoordinates
[ (sal_uInt16
)( rSrcPt
+ nXor
) ], true, true ) );
1800 Point
aEnd( GetPoint( seqCoordinates
[ (sal_uInt16
)( rSrcPt
+ ( nXor
^ 1 ) ) ], true, true ) );
1801 aStart
.X() = (sal_Int32
)( ( (double)( aStart
.X() - aCenter
.X() ) ) ) + aCenter
.X();
1802 aStart
.Y() = (sal_Int32
)( ( (double)( aStart
.Y() - aCenter
.Y() ) ) ) + aCenter
.Y();
1803 aEnd
.X() = (sal_Int32
)( ( (double)( aEnd
.X() - aCenter
.X() ) ) ) + aCenter
.X();
1804 aEnd
.Y() = (sal_Int32
)( ( (double)( aEnd
.Y() - aCenter
.Y() ) ) ) + aCenter
.Y();
1805 aNewB2DPolygon
.append(CreateArc( aRect
, aStart
, aEnd
, bClockwise
));
1814 double fWR
, fHR
, fStartAngle
, fSwingAngle
;
1816 for ( sal_uInt16 i
= 0; ( i
< nPntCount
) && ( rSrcPt
+ 1 < nCoordSize
); i
++ )
1818 GetParameter ( fWR
, seqCoordinates
[ (sal_uInt16
)( rSrcPt
) ].First
, true, false );
1819 GetParameter ( fHR
, seqCoordinates
[ (sal_uInt16
)( rSrcPt
) ].Second
, false, true );
1821 GetParameter ( fStartAngle
, seqCoordinates
[ (sal_uInt16
)( rSrcPt
+ 1) ].First
, false, false );
1822 GetParameter ( fSwingAngle
, seqCoordinates
[ (sal_uInt16
)( rSrcPt
+ 1 ) ].Second
, false, false );
1824 // Convert angles to radians, but don't do any scaling / translation yet.
1826 fStartAngle
*= F_PI180
;
1827 fSwingAngle
*= F_PI180
;
1829 SAL_INFO("svx", "ARCANGLETO scale: " << fWR
<< "x" << fHR
<< " angles: " << fStartAngle
<< "," << fSwingAngle
);
1831 bool bClockwise
= fSwingAngle
>= 0.0;
1833 if (aNewB2DPolygon
.count() > 0)
1835 basegfx::B2DPoint
aStartPointB2D( aNewB2DPolygon
.getB2DPoint(aNewB2DPolygon
.count() - 1 ) );
1836 Point
aStartPoint( 0, 0 );
1838 double fT
= atan2((fWR
*sin(fStartAngle
)), (fHR
*cos(fStartAngle
)));
1839 double fTE
= atan2((fWR
*sin(fStartAngle
+ fSwingAngle
)), fHR
*cos(fStartAngle
+ fSwingAngle
));
1841 SAL_INFO("svx", "ARCANGLETO angles: " << fStartAngle
<< ", " << fSwingAngle
1842 << " --> parameters: " << fT
<<", " << fTE
);
1847 tools::Rectangle
aRect ( Point ( aStartPoint
.getX() - fWR
*cos(fT
) - fWR
, aStartPoint
.getY() - fHR
*sin(fT
) - fHR
),
1848 Point ( aStartPoint
.getX() - fWR
*cos(fT
) + fWR
, aStartPoint
.getY() - fHR
*sin(fT
) + fHR
) );
1850 Point
aEndPoint ( aStartPoint
.getX() - fWR
*(cos(fT
) - cos(fTE
)), aStartPoint
.getY() - fHR
*(sin(fT
) - sin(fTE
)) );
1854 "ARCANGLETO rect: " << aRect
.Left() << ", "
1855 << aRect
.Top() << " x " << aRect
.Right()
1856 << ", " << aRect
.Bottom() << " start: "
1857 << aStartPoint
.X() << ", "
1858 << aStartPoint
.Y() << " end: "
1859 << aEndPoint
.X() << ", " << aEndPoint
.Y()
1860 << " clockwise: " << int(bClockwise
));
1861 basegfx::B2DPolygon aArc
= CreateArc( aRect
, bClockwise
? aEndPoint
: aStartPoint
, bClockwise
? aStartPoint
: aEndPoint
, bClockwise
, aStartPoint
== aEndPoint
&& ((bClockwise
&& fSwingAngle
> F_PI
) || (!bClockwise
&& fSwingAngle
< -F_PI
)));
1862 // Now that we have the arc, move it to aStartPointB2D.
1863 basegfx::B2DHomMatrix aMatrix
= basegfx::tools::createTranslateB2DHomMatrix(aStartPointB2D
.getX(), aStartPointB2D
.getY());
1864 aArc
.transform(aMatrix
);
1865 aNewB2DPolygon
.append(aArc
);
1873 case ELLIPTICALQUADRANTX
:
1874 case ELLIPTICALQUADRANTY
:
1876 bool bFirstDirection(true);
1877 basegfx::B2DPoint aControlPointA
;
1878 basegfx::B2DPoint aControlPointB
;
1880 for ( sal_uInt16 i
= 0; ( i
< nPntCount
) && ( rSrcPt
< nCoordSize
); i
++ )
1882 sal_uInt32 nModT
= ( nCommand
== ELLIPTICALQUADRANTX
) ? 1 : 0;
1883 Point
aCurrent( GetPoint( seqCoordinates
[ rSrcPt
], true, true ) );
1885 if ( rSrcPt
) // we need a previous point
1887 Point
aPrev( GetPoint( seqCoordinates
[ rSrcPt
- 1 ], true, true ) );
1889 nX
= aCurrent
.X() - aPrev
.X();
1890 nY
= aCurrent
.Y() - aPrev
.Y();
1891 if ( ( nY
^ nX
) & 0x80000000 )
1894 bFirstDirection
= true;
1895 else if ( !bFirstDirection
)
1901 bFirstDirection
= false;
1902 else if ( bFirstDirection
)
1905 if ( nModT
) // get the right corner
1915 sal_Int32 nXVec
= ( nX
- aPrev
.X() ) >> 1;
1916 sal_Int32 nYVec
= ( nY
- aPrev
.Y() ) >> 1;
1917 Point
aControl1( aPrev
.X() + nXVec
, aPrev
.Y() + nYVec
);
1919 aControlPointA
= basegfx::B2DPoint(aControl1
.X(), aControl1
.Y());
1921 nXVec
= ( nX
- aCurrent
.X() ) >> 1;
1922 nYVec
= ( nY
- aCurrent
.Y() ) >> 1;
1923 Point
aControl2( aCurrent
.X() + nXVec
, aCurrent
.Y() + nYVec
);
1925 aControlPointB
= basegfx::B2DPoint(aControl2
.X(), aControl2
.Y());
1927 aNewB2DPolygon
.appendBezierSegment(
1930 basegfx::B2DPoint(aCurrent
.X(), aCurrent
.Y()));
1934 aNewB2DPolygon
.append(basegfx::B2DPoint(aCurrent
.X(), aCurrent
.Y()));
1942 #ifdef DBG_CUSTOMSHAPE
1946 OStringBuffer
aString("CustomShapes::unknown PolyFlagValue :");
1947 aString
.append(static_cast<sal_Int32
>(nCommand
));
1948 OSL_FAIL(aString
.getStr());
1953 if ( nCommand
== ENDSUBPATH
)
1957 if ( rSegmentInd
== nSegInfoSize
)
1960 if(aNewB2DPolygon
.count() > 1L)
1962 // #i76201# Add conversion to closed polygon when first and last points are equal
1963 basegfx::tools::checkClosed(aNewB2DPolygon
);
1964 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1967 if(aNewB2DPolyPolygon
.count())
1969 if( !bLineGeometryNeededOnly
)
1971 // hack aNewB2DPolyPolygon to fill logic rect - this is
1972 // needed to produce gradient fills that look like mso
1973 aNewB2DPolygon
.clear();
1974 aNewB2DPolygon
.append(basegfx::B2DPoint(0,0));
1975 aNewB2DPolygon
.setClosed(true);
1976 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1978 aNewB2DPolygon
.clear();
1979 aNewB2DPolygon
.append(basegfx::B2DPoint(aLogicRect
.GetWidth(),
1980 aLogicRect
.GetHeight()));
1981 aNewB2DPolygon
.setClosed(true);
1982 aNewB2DPolyPolygon
.append(aNewB2DPolygon
);
1986 bool bForceCreateTwoObjects(false);
1988 if(!bSortFilledObjectsToBack
&& !aNewB2DPolyPolygon
.isClosed() && !bNoStroke
)
1990 bForceCreateTwoObjects
= true;
1993 if(bLineGeometryNeededOnly
)
1995 bForceCreateTwoObjects
= true;
2000 if(bForceCreateTwoObjects
|| bSortFilledObjectsToBack
)
2002 if(bFilled
&& !bNoFill
)
2004 basegfx::B2DPolyPolygon
aClosedPolyPolygon(aNewB2DPolyPolygon
);
2005 aClosedPolyPolygon
.setClosed(true);
2006 SdrPathObj
* pFill
= new SdrPathObj(OBJ_POLY
, aClosedPolyPolygon
, dBrightness
);
2007 SfxItemSet
aTempSet(*this);
2008 aTempSet
.Put(makeSdrShadowItem(false));
2009 aTempSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
2010 pFill
->SetMergedItemSet(aTempSet
);
2011 rObjectList
.push_back(pFill
);
2016 // there is no reason to use OBJ_PLIN here when the polygon is actually closed,
2017 // the non-fill is defined by XFILL_NONE. Since SdrPathObj::ImpForceKind() needs
2018 // to correct the polygon (here: open it) using the type, the last edge may get lost.
2019 // Thus, use a type that fits the polygon
2020 SdrPathObj
* pStroke
= new SdrPathObj(
2021 aNewB2DPolyPolygon
.isClosed() ? OBJ_POLY
: OBJ_PLIN
,
2022 aNewB2DPolyPolygon
, dBrightness
);
2023 SfxItemSet
aTempSet(*this);
2024 aTempSet
.Put(makeSdrShadowItem(false));
2025 aTempSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
2026 pStroke
->SetMergedItemSet(aTempSet
);
2027 rObjectList
.push_back(pStroke
);
2032 SdrPathObj
* pObj
= nullptr;
2033 SfxItemSet
aTempSet(*this);
2034 aTempSet
.Put(makeSdrShadowItem(false));
2038 // see comment above about OBJ_PLIN
2039 pObj
= new SdrPathObj(
2040 aNewB2DPolyPolygon
.isClosed() ? OBJ_POLY
: OBJ_PLIN
,
2041 aNewB2DPolyPolygon
, dBrightness
);
2042 aTempSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
2046 aNewB2DPolyPolygon
.setClosed(true);
2047 pObj
= new SdrPathObj(OBJ_POLY
, aNewB2DPolyPolygon
, dBrightness
);
2052 aTempSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
2057 pObj
->SetMergedItemSet(aTempSet
);
2058 rObjectList
.push_back(pObj
);
2064 void CorrectCalloutArrows( MSO_SPT eSpType
, sal_uInt32 nLineObjectCount
, std::vector
< SdrPathObj
* >& vObjectList
)
2066 bool bAccent
= false;
2069 case mso_sptCallout1
:
2070 case mso_sptBorderCallout1
:
2071 case mso_sptCallout90
:
2072 case mso_sptBorderCallout90
:
2076 case mso_sptAccentCallout1
:
2077 case mso_sptAccentBorderCallout1
:
2078 case mso_sptAccentCallout90
:
2079 case mso_sptAccentBorderCallout90
:
2081 sal_uInt32 nLine
= 0;
2082 for ( SdrPathObj
* pObj
: vObjectList
)
2087 if ( nLine
== nLineObjectCount
)
2089 pObj
->ClearMergedItem( XATTR_LINESTART
);
2090 pObj
->ClearMergedItem( XATTR_LINEEND
);
2097 // switch start & end
2098 case mso_sptAccentCallout2
:
2099 case mso_sptAccentBorderCallout2
:
2102 case mso_sptCallout2
:
2103 case mso_sptBorderCallout2
:
2105 sal_uInt32 nLine
= 0;
2106 for ( SdrPathObj
* pObj
: vObjectList
)
2112 pObj
->ClearMergedItem( XATTR_LINEEND
);
2113 else if ( ( bAccent
&& ( nLine
== nLineObjectCount
- 1 ) ) || ( !bAccent
&& ( nLine
== nLineObjectCount
) ) )
2114 pObj
->ClearMergedItem( XATTR_LINESTART
);
2117 pObj
->ClearMergedItem( XATTR_LINESTART
);
2118 pObj
->ClearMergedItem( XATTR_LINEEND
);
2125 case mso_sptAccentCallout3
:
2126 case mso_sptAccentBorderCallout3
:
2127 case mso_sptCallout3
:
2128 case mso_sptBorderCallout3
:
2130 sal_uInt32 nLine
= 0;
2131 for ( SdrPathObj
* pObj
: vObjectList
)
2137 pObj
->ClearMergedItem( XATTR_LINESTART
);
2138 pObj
->ClearMergedItem( XATTR_LINEEND
);
2141 EnhancedCustomShape2d::SwapStartAndEndArrow( pObj
);
2151 void EnhancedCustomShape2d::AdaptObjColor(SdrPathObj
& rObj
, const SfxItemSet
& rCustomShapeSet
,
2152 sal_uInt32
& nColorIndex
, sal_uInt32 nColorCount
)
2154 if ( !rObj
.IsLine() )
2156 const drawing::FillStyle eFillStyle
= static_cast<const XFillStyleItem
&>(rObj
.GetMergedItem(XATTR_FILLSTYLE
)).GetValue();
2157 switch( eFillStyle
)
2160 case drawing::FillStyle_SOLID
:
2163 if ( nColorCount
|| rObj
.GetBrightness() != 0.0 )
2165 aFillColor
= GetColorData(
2166 static_cast<const XFillColorItem
&>(rCustomShapeSet
.Get( XATTR_FILLCOLOR
)).GetColorValue(),
2167 std::min(nColorIndex
, nColorCount
-1), rObj
.GetBrightness() );
2168 rObj
.SetMergedItem( XFillColorItem( "", aFillColor
) );
2172 case drawing::FillStyle_GRADIENT
:
2174 XGradient
aXGradient(static_cast<const XFillGradientItem
&>(rObj
.GetMergedItem(XATTR_FILLGRADIENT
)).GetGradientValue());
2175 if ( nColorCount
|| rObj
.GetBrightness() != 0.0 )
2177 aXGradient
.SetStartColor(
2179 aXGradient
.GetStartColor(),
2180 std::min(nColorIndex
, nColorCount
-1), rObj
.GetBrightness() ));
2181 aXGradient
.SetEndColor(
2183 aXGradient
.GetEndColor(),
2184 std::min(nColorIndex
, nColorCount
-1), rObj
.GetBrightness() ));
2187 rObj
.SetMergedItem( XFillGradientItem( "", aXGradient
) );
2190 case drawing::FillStyle_HATCH
:
2192 XHatch
aXHatch(static_cast<const XFillHatchItem
&>(rObj
.GetMergedItem(XATTR_FILLHATCH
)).GetHatchValue());
2193 if ( nColorCount
|| rObj
.GetBrightness() != 0.0 )
2198 std::min(nColorIndex
, nColorCount
-1), rObj
.GetBrightness() ));
2201 rObj
.SetMergedItem( XFillHatchItem( "", aXHatch
) );
2204 case drawing::FillStyle_BITMAP
:
2206 if ( nColorCount
|| rObj
.GetBrightness() != 0.0 )
2208 Bitmap
aBitmap(static_cast<const XFillBitmapItem
&>(rObj
.GetMergedItem(XATTR_FILLBITMAP
)).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
2211 static_cast< short > ( GetLuminanceChange(
2212 std::min(nColorIndex
, nColorCount
-1))));
2214 rObj
.SetMergedItem(XFillBitmapItem(OUString(), Graphic(aBitmap
)));
2221 if ( nColorIndex
< nColorCount
)
2226 SdrObject
* EnhancedCustomShape2d::CreatePathObj( bool bLineGeometryNeededOnly
)
2228 sal_Int32 nCoordSize
= seqCoordinates
.getLength();
2232 std::vector
< SdrPathObj
* > vObjectList
;
2233 bool bSortFilledObjectsToBack
= SortFilledObjectsToBackByDefault( eSpType
);
2235 sal_Int32 nSubPathIndex
= 0;
2237 sal_Int32 nSrcPt
= 0;
2238 sal_Int32 nSegmentInd
= 0;
2239 while( nSegmentInd
<= seqSegments
.getLength() )
2241 CreateSubPath( nSrcPt
, nSegmentInd
, vObjectList
, bLineGeometryNeededOnly
, bSortFilledObjectsToBack
, nSubPathIndex
);
2245 SdrObject
* pRet
= nullptr;
2247 if ( !vObjectList
.empty() )
2249 const SfxItemSet
& rCustomShapeSet
= pCustomShapeObj
->GetMergedItemSet();
2250 sal_uInt32 nColorCount
= nColorData
>> 28;
2251 sal_uInt32 nColorIndex
= 0;
2253 // #i37011# remove invisible objects
2254 if(!vObjectList
.empty())
2256 std::vector
< SdrPathObj
* > vTempList
;
2258 for(SdrPathObj
* pObj
: vObjectList
)
2260 const drawing::LineStyle eLineStyle
=static_cast<const XLineStyleItem
&>(pObj
->GetMergedItem(XATTR_LINESTYLE
)).GetValue();
2261 const drawing::FillStyle eFillStyle
= static_cast<const XFillStyleItem
&>(pObj
->GetMergedItem(XATTR_FILLSTYLE
)).GetValue();
2263 // #i40600# if bLineGeometryNeededOnly is set, linestyle does not matter
2264 if( !bLineGeometryNeededOnly
&& ( drawing::LineStyle_NONE
== eLineStyle
) && ( drawing::FillStyle_NONE
== eFillStyle
) )
2267 vTempList
.push_back(pObj
);
2270 vObjectList
= vTempList
;
2273 if(1L == vObjectList
.size())
2275 // a single object, correct some values
2276 AdaptObjColor(*vObjectList
[0L],rCustomShapeSet
,nColorIndex
,nColorCount
);
2280 sal_Int32 nLineObjectCount
= 0;
2281 sal_Int32 nAreaObjectCount
= 0;
2283 // correct some values and collect content data
2284 for (SdrPathObj
* pObj
: vObjectList
)
2293 AdaptObjColor(*pObj
,rCustomShapeSet
,nColorIndex
,nColorCount
);
2297 // #i88870# correct line arrows for callouts
2298 if ( nLineObjectCount
)
2299 CorrectCalloutArrows( eSpType
, nLineObjectCount
, vObjectList
);
2301 // sort objects so that filled ones are in front. Necessary
2302 // for some strange objects
2303 if ( bSortFilledObjectsToBack
)
2305 std::vector
< SdrPathObj
* > vTempList
;
2306 vTempList
.reserve(vObjectList
.size());
2308 for (SdrPathObj
* pObj
: vObjectList
)
2310 if ( !pObj
->IsLine() )
2312 vTempList
.push_back(pObj
);
2316 for (SdrPathObj
* pObj
: vObjectList
)
2318 if ( pObj
->IsLine() )
2320 vTempList
.push_back(pObj
);
2324 vObjectList
= vTempList
;
2330 if(!vObjectList
.empty())
2332 // copy remaining objects to pRet
2333 if(vObjectList
.size() > 1)
2335 pRet
= new SdrObjGroup
;
2337 for (SdrPathObj
* pObj
: vObjectList
)
2339 pRet
->GetSubList()->NbcInsertObject(pObj
);
2342 else if(1 == vObjectList
.size())
2344 pRet
= vObjectList
[0L];
2349 // move to target position
2350 tools::Rectangle
aCurRect(pRet
->GetSnapRect());
2351 aCurRect
.Move(aLogicRect
.Left(), aLogicRect
.Top());
2352 pRet
->NbcSetSnapRect(aCurRect
);
2359 SdrObject
* EnhancedCustomShape2d::CreateObject( bool bLineGeometryNeededOnly
)
2361 SdrObject
* pRet
= nullptr;
2363 if ( eSpType
== mso_sptRectangle
)
2365 pRet
= new SdrRectObj( aLogicRect
);
2366 pRet
->SetMergedItemSet( *this );
2369 pRet
= CreatePathObj( bLineGeometryNeededOnly
);
2374 void EnhancedCustomShape2d::ApplyGluePoints( SdrObject
* pObj
)
2376 if ( pObj
&& seqGluePoints
.getLength() )
2378 sal_uInt32 i
, nCount
= seqGluePoints
.getLength();
2379 for ( i
= 0; i
< nCount
; i
++ )
2381 SdrGluePoint aGluePoint
;
2383 aGluePoint
.SetPos( GetPoint( seqGluePoints
[ i
], true, true ) );
2384 aGluePoint
.SetPercent( false );
2385 aGluePoint
.SetAlign( SdrAlign::VERT_TOP
| SdrAlign::HORZ_LEFT
);
2386 aGluePoint
.SetEscDir( SdrEscapeDirection::SMART
);
2387 SdrGluePointList
* pList
= pObj
->ForceGluePointList();
2389 /* sal_uInt16 nId = */ pList
->Insert( aGluePoint
);
2394 bool EnhancedCustomShape2d::IsPostRotate() const
2396 return dynamic_cast<const SdrObjCustomShape
*>( pCustomShapeObj
) != nullptr && static_cast<SdrObjCustomShape
*>(pCustomShapeObj
)->IsPostRotate();
2399 SdrObject
* EnhancedCustomShape2d::CreateLineGeometry()
2401 return CreateObject( true );
2405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */