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: sdrmeasureprimitive2d.cxx,v $
11 * $Revision: 1.2.18.1 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 #include "precompiled_svx.hxx"
33 #include <svx/sdr/primitive2d/sdrmeasureprimitive2d.hxx>
34 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
35 #include <basegfx/matrix/b2dhommatrix.hxx>
36 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
37 #include <svx/sdr/attribute/sdrtextattribute.hxx>
38 #include <basegfx/polygon/b2dpolypolygontools.hxx>
39 #include <basegfx/tools/canvastools.hxx>
40 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
41 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
42 #include <drawinglayer/primitive2d/hittestprimitive2d.hxx>
44 //////////////////////////////////////////////////////////////////////////////
46 using namespace com::sun::star
;
48 //////////////////////////////////////////////////////////////////////////////
50 namespace drawinglayer
54 Primitive2DReference
SdrMeasurePrimitive2D::impCreatePart(
55 const basegfx::B2DHomMatrix
& rObjectMatrix
,
56 const basegfx::B2DPoint
& rStart
,
57 const basegfx::B2DPoint
& rEnd
,
59 bool bRightActive
) const
61 basegfx::B2DPolygon aPolygon
;
62 aPolygon
.append(rStart
);
63 aPolygon
.append(rEnd
);
65 if(!getSdrLSTAttribute().getLineStartEnd() || (!bLeftActive
&& !bRightActive
))
67 return createPolygonLinePrimitive(aPolygon
, rObjectMatrix
, *getSdrLSTAttribute().getLine(), 0L);
70 if(bLeftActive
&& bRightActive
)
72 return createPolygonLinePrimitive(aPolygon
, rObjectMatrix
, *getSdrLSTAttribute().getLine(), getSdrLSTAttribute().getLineStartEnd());
75 const attribute::SdrLineStartEndAttribute
* pLineStartEnd
= getSdrLSTAttribute().getLineStartEnd();
76 const basegfx::B2DPolyPolygon aEmpty
;
77 const attribute::SdrLineStartEndAttribute
aLineStartEnd(
78 bLeftActive
? pLineStartEnd
->getStartPolyPolygon() : aEmpty
, bRightActive
? pLineStartEnd
->getEndPolyPolygon() : aEmpty
,
79 bLeftActive
? pLineStartEnd
->getStartWidth() : 0.0, bRightActive
? pLineStartEnd
->getEndWidth() : 0.0,
80 bLeftActive
? pLineStartEnd
->isStartActive() : false, bRightActive
? pLineStartEnd
->isEndActive() : false,
81 bLeftActive
? pLineStartEnd
->isStartCentered() : false, bRightActive
? pLineStartEnd
->isEndCentered() : false);
83 return createPolygonLinePrimitive(aPolygon
, rObjectMatrix
, *getSdrLSTAttribute().getLine(), &aLineStartEnd
);
86 Primitive2DSequence
SdrMeasurePrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& aViewInformation
) const
88 Primitive2DSequence aRetval
;
89 SdrBlockTextPrimitive2D
* pBlockText
= 0L;
90 basegfx::B2DRange aTextRange
;
91 double fTextX((getStart().getX() + getEnd().getX()) * 0.5);
92 double fTextY((getStart().getX() + getEnd().getX()) * 0.5);
93 const basegfx::B2DVector
aLine(getEnd() - getStart());
94 const double fDistance(aLine
.getLength());
95 const double fAngle(atan2(aLine
.getY(), aLine
.getX()));
96 bool bAutoUpsideDown(false);
97 const attribute::SdrTextAttribute
* pTextAttribute
= getSdrLSTAttribute().getText();
99 basegfx::B2DHomMatrix aObjectMatrix
;
100 aObjectMatrix
.rotate(fAngle
);
101 aObjectMatrix
.translate(getStart().getX(), getStart().getY());
105 basegfx::B2DHomMatrix aTextMatrix
;
106 double fTestAngle(fAngle
);
108 if(getTextRotation())
110 aTextMatrix
.rotate(-90.0 * F_PI180
);
111 fTestAngle
-= (90.0 * F_PI180
);
113 if(getTextAutoAngle() && fTestAngle
< -F_PI
)
119 if(getTextAutoAngle())
121 if(fTestAngle
> (F_PI
/ 4.0) || fTestAngle
< (-F_PI
* (3.0 / 4.0)))
123 bAutoUpsideDown
= true;
127 // create primitive and get text range
128 pBlockText
= new SdrBlockTextPrimitive2D(
129 &pTextAttribute
->getSdrText(),
130 pTextAttribute
->getOutlinerParaObject(),
132 SDRTEXTHORZADJUST_CENTER
,
133 SDRTEXTVERTADJUST_CENTER
,
134 pTextAttribute
->isScroll(),
138 aTextRange
= pBlockText
->getB2DRange(aViewInformation
);
141 // prepare line attribute and result
142 const attribute::SdrLineAttribute
* pLineAttribute(getSdrLSTAttribute().getLine());
146 // if initially no line is defined, create one for HitTest and BoundRect
147 pLineAttribute
= new attribute::SdrLineAttribute(basegfx::BColor(0.0, 0.0, 0.0));
151 bool bArrowsOutside(false);
152 bool bMainLineSplitted(false);
153 const attribute::SdrLineStartEndAttribute
* pLineStartEnd
= getSdrLSTAttribute().getLineStartEnd();
154 double fStartArrowW(0.0);
155 double fStartArrowH(0.0);
156 double fEndArrowW(0.0);
157 double fEndArrowH(0.0);
161 if(pLineStartEnd
->isStartActive())
163 const basegfx::B2DRange
aArrowRange(basegfx::tools::getRange(pLineStartEnd
->getStartPolyPolygon()));
164 fStartArrowW
= pLineStartEnd
->getStartWidth();
165 fStartArrowH
= aArrowRange
.getHeight() * fStartArrowW
/ aArrowRange
.getWidth();
167 if(pLineStartEnd
->isStartCentered())
173 if(pLineStartEnd
->isEndActive())
175 const basegfx::B2DRange
aArrowRange(basegfx::tools::getRange(pLineStartEnd
->getEndPolyPolygon()));
176 fEndArrowW
= pLineStartEnd
->getEndWidth();
177 fEndArrowH
= aArrowRange
.getHeight() * fEndArrowW
/ aArrowRange
.getWidth();
179 if(pLineStartEnd
->isEndCentered())
186 const double fSpaceNeededByArrows(fStartArrowH
+ fEndArrowH
+ ((fStartArrowW
+ fEndArrowW
) * 0.5));
187 const double fArrowsOutsideLen((fStartArrowH
+ fEndArrowH
+ fStartArrowW
+ fEndArrowW
) * 0.5);
188 const double fHalfLineWidth(pLineAttribute
->getWidth() * 0.5);
190 if(fSpaceNeededByArrows
> fDistance
)
192 bArrowsOutside
= true;
195 MeasureTextPosition
eHorizontal(getHorizontal());
196 MeasureTextPosition
eVertical(getVertical());
198 if(MEASURETEXTPOSITION_AUTOMATIC
== eVertical
)
200 eVertical
= MEASURETEXTPOSITION_NEGATIVE
;
203 if(MEASURETEXTPOSITION_CENTERED
== eVertical
)
205 bMainLineSplitted
= true;
208 if(MEASURETEXTPOSITION_AUTOMATIC
== eHorizontal
)
210 if(aTextRange
.getWidth() > fDistance
)
212 eHorizontal
= MEASURETEXTPOSITION_NEGATIVE
;
216 eHorizontal
= MEASURETEXTPOSITION_CENTERED
;
219 if(bMainLineSplitted
)
221 if(aTextRange
.getWidth() + fSpaceNeededByArrows
> fDistance
)
223 bArrowsOutside
= true;
228 const double fSmallArrowNeed(fStartArrowH
+ fEndArrowH
+ ((fStartArrowW
+ fEndArrowW
) * 0.125));
230 if(aTextRange
.getWidth() + fSmallArrowNeed
> fDistance
)
232 bArrowsOutside
= true;
237 if(MEASURETEXTPOSITION_CENTERED
!= eHorizontal
)
239 bArrowsOutside
= true;
242 // switch text above/below?
243 if(getBelow() || (bAutoUpsideDown
&& !getTextRotation()))
245 if(MEASURETEXTPOSITION_NEGATIVE
== eVertical
)
247 eVertical
= MEASURETEXTPOSITION_POSITIVE
;
249 else if(MEASURETEXTPOSITION_POSITIVE
== eVertical
)
251 eVertical
= MEASURETEXTPOSITION_NEGATIVE
;
255 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
256 const basegfx::B2DPoint
aMainLeft(0.0, fMainLineOffset
);
257 const basegfx::B2DPoint
aMainRight(fDistance
, fMainLineOffset
);
262 double fLenLeft(fArrowsOutsideLen
);
263 double fLenRight(fArrowsOutsideLen
);
265 if(!bMainLineSplitted
)
267 if(MEASURETEXTPOSITION_NEGATIVE
== eHorizontal
)
269 fLenLeft
= fStartArrowH
+ aTextRange
.getWidth();
271 else if(MEASURETEXTPOSITION_POSITIVE
== eHorizontal
)
273 fLenRight
= fEndArrowH
+ aTextRange
.getWidth();
277 const basegfx::B2DPoint
aMainLeftLeft(aMainLeft
.getX() - fLenLeft
, aMainLeft
.getY());
278 const basegfx::B2DPoint
aMainRightRight(aMainRight
.getX() + fLenRight
, aMainRight
.getY());
280 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainLeftLeft
, aMainLeft
, false, true));
281 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainRight
, aMainRightRight
, true, false));
283 if(!bMainLineSplitted
|| MEASURETEXTPOSITION_CENTERED
!= eHorizontal
)
285 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainLeft
, aMainRight
, false, false));
290 if(bMainLineSplitted
)
292 const double fHalfLength((fDistance
- (aTextRange
.getWidth() + (fStartArrowH
+ fEndArrowH
) * 0.25)) * 0.5);
293 const basegfx::B2DPoint
aMainInnerLeft(aMainLeft
.getX() + fHalfLength
, aMainLeft
.getY());
294 const basegfx::B2DPoint
aMainInnerRight(aMainRight
.getX() - fHalfLength
, aMainRight
.getY());
296 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainLeft
, aMainInnerLeft
, true, false));
297 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainInnerRight
, aMainRight
, false, true));
301 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aMainLeft
, aMainRight
, true, true));
305 // left/right help line value preparation
306 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
307 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
308 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
311 const basegfx::B2DPoint
aLeftUp(0.0, fTopEdge
);
312 const basegfx::B2DPoint
aLeftDown(0.0, fBottomLeft
);
314 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aLeftDown
, aLeftUp
, false, false));
317 const basegfx::B2DPoint
aRightUp(fDistance
, fTopEdge
);
318 const basegfx::B2DPoint
aRightDown(fDistance
, fBottomRight
);
320 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, impCreatePart(aObjectMatrix
, aRightDown
, aRightUp
, false, false));
322 // text horizontal position
323 if(MEASURETEXTPOSITION_NEGATIVE
== eHorizontal
)
326 const double fSmall(fArrowsOutsideLen
* 0.18);
327 fTextX
= aMainLeft
.getX() - (fStartArrowH
+ aTextRange
.getWidth() + fSmall
+ fHalfLineWidth
);
329 if(bMainLineSplitted
)
331 fTextX
-= (fArrowsOutsideLen
- fStartArrowH
);
336 fTextX
-= pTextAttribute
->getTextRightDistance();
339 else if(MEASURETEXTPOSITION_POSITIVE
== eHorizontal
)
342 const double fSmall(fArrowsOutsideLen
* 0.18);
343 fTextX
= aMainRight
.getX() + (fEndArrowH
+ fSmall
+ fHalfLineWidth
);
345 if(bMainLineSplitted
)
347 fTextX
+= (fArrowsOutsideLen
- fEndArrowH
);
352 fTextX
+= pTextAttribute
->getTextLeftDistance();
355 else // MEASURETEXTPOSITION_CENTERED
358 fTextX
= aMainLeft
.getX() + ((fDistance
- aTextRange
.getWidth()) * 0.5);
362 fTextX
+= (pTextAttribute
->getTextLeftDistance() - pTextAttribute
->getTextRightDistance()) / 2L;
366 // text vertical position
367 if(MEASURETEXTPOSITION_NEGATIVE
== eVertical
)
370 const double fSmall(fArrowsOutsideLen
* 0.10);
371 fTextY
= aMainLeft
.getY() - (aTextRange
.getHeight() + fSmall
+ fHalfLineWidth
);
375 fTextY
-= pTextAttribute
->getTextLowerDistance();
378 else if(MEASURETEXTPOSITION_POSITIVE
== eVertical
)
381 const double fSmall(fArrowsOutsideLen
* 0.10);
382 fTextY
= aMainLeft
.getY() + (fSmall
+ fHalfLineWidth
);
386 fTextY
+= pTextAttribute
->getTextUpperDistance();
389 else // MEASURETEXTPOSITION_CENTERED
392 fTextY
= aMainLeft
.getY() - (aTextRange
.getHeight() * 0.5);
396 fTextY
+= (pTextAttribute
->getTextUpperDistance() - pTextAttribute
->getTextLowerDistance()) / 2L;
401 if(!getSdrLSTAttribute().getLine())
403 // embed line geometry to invisible line group
404 const Primitive2DReference
xHiddenLines(new HitTestPrimitive2D(aRetval
));
405 aRetval
= Primitive2DSequence(&xHiddenLines
, 1);
407 // delete temporary LineAttribute again
408 delete pLineAttribute
;
413 // create transformation to text primitive end position
414 basegfx::B2DHomMatrix aChange
;
416 // handle auto text rotation
419 aChange
.rotate(F_PI
);
422 // move from aTextRange.TopLeft to fTextX, fTextY
423 aChange
.translate(fTextX
- aTextRange
.getMinX(), fTextY
- aTextRange
.getMinY());
425 // apply object matrix
426 aChange
*= aObjectMatrix
;
428 // apply to existing text primitive
429 SdrTextPrimitive2D
* pNewBlockText
= pBlockText
->createTransformedClone(aChange
);
430 OSL_ENSURE(pNewBlockText
, "SdrMeasurePrimitive2D::createLocalDecomposition: Could not create transformed clone of text primitive (!)");
433 // add to local primitives
434 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval
, Primitive2DReference(pNewBlockText
));
438 if(getSdrLSTAttribute().getShadow())
440 aRetval
= createEmbeddedShadowPrimitive(aRetval
, *getSdrLSTAttribute().getShadow());
446 SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
447 const attribute::SdrLineShadowTextAttribute
& rSdrLSTAttribute
,
448 const basegfx::B2DPoint
& rStart
,
449 const basegfx::B2DPoint
& rEnd
,
450 MeasureTextPosition eHorizontal
,
451 MeasureTextPosition eVertical
,
461 maSdrLSTAttribute(rSdrLSTAttribute
),
464 meHorizontal(eHorizontal
),
465 meVertical(eVertical
),
466 mfDistance(fDistance
),
469 mfLeftDelta(fLeftDelta
),
470 mfRightDelta(fRightDelta
),
472 mbTextRotation(bTextRotation
),
473 mbTextAutoAngle(bTextAutoAngle
)
477 bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
479 if(BasePrimitive2D::operator==(rPrimitive
))
481 const SdrMeasurePrimitive2D
& rCompare
= (SdrMeasurePrimitive2D
&)rPrimitive
;
483 return (getStart() == rCompare
.getStart()
484 && getEnd() == rCompare
.getEnd()
485 && getHorizontal() == rCompare
.getHorizontal()
486 && getVertical() == rCompare
.getVertical()
487 && getDistance() == rCompare
.getDistance()
488 && getUpper() == rCompare
.getUpper()
489 && getLower() == rCompare
.getLower()
490 && getLeftDelta() == rCompare
.getLeftDelta()
491 && getRightDelta() == rCompare
.getRightDelta()
492 && getBelow() == rCompare
.getBelow()
493 && getTextRotation() == rCompare
.getTextRotation()
494 && getTextAutoAngle() == rCompare
.getTextAutoAngle()
495 && getSdrLSTAttribute() == rCompare
.getSdrLSTAttribute());
502 ImplPrimitrive2DIDBlock(SdrMeasurePrimitive2D
, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
)
504 } // end of namespace primitive2d
505 } // end of namespace drawinglayer
507 //////////////////////////////////////////////////////////////////////////////