LibreOffice Module svx (master) 1
sdrmeasureprimitive2d.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
26#include <rtl/ref.hxx>
30#include <osl/diagnose.h>
31
32
33using namespace com::sun::star;
34
35
37{
39 const attribute::SdrLineAttribute& rLineAttribute,
40 const basegfx::B2DHomMatrix& rObjectMatrix,
41 const basegfx::B2DPoint& rStart,
42 const basegfx::B2DPoint& rEnd,
43 bool bLeftActive,
44 bool bRightActive) const
45 {
47 basegfx::B2DPolygon aPolygon;
48
49 aPolygon.append(rStart);
50 aPolygon.append(rEnd);
51 aPolygon.transform(rObjectMatrix);
52
53 if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
54 {
56 aPolygon,
57 rLineAttribute,
59 }
60
61 if(bLeftActive && bRightActive)
62 {
64 aPolygon,
65 rLineAttribute,
66 rLineStartEnd);
67 }
68
69 const basegfx::B2DPolyPolygon aEmpty;
70 const attribute::SdrLineStartEndAttribute aLineStartEnd(
71 bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
72 bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
73 bLeftActive && rLineStartEnd.isStartActive(), bRightActive && rLineStartEnd.isEndActive(),
74 bLeftActive && rLineStartEnd.isStartCentered(), bRightActive && rLineStartEnd.isEndCentered());
75
77 aPolygon,
78 rLineAttribute,
79 aLineStartEnd);
80 }
81
83 {
86 basegfx::B2DRange aTextRange;
87 const basegfx::B2DVector aLine(getEnd() - getStart());
88 const double fDistance(aLine.getLength());
89 const double fAngle(atan2(aLine.getY(), aLine.getX()));
90 bool bAutoUpsideDown(false);
92 const basegfx::B2DHomMatrix aObjectMatrix(
94
95 // prepare text, but do not add yet; it needs to be aligned to
96 // the line geometry
97 if(!rTextAttribute.isDefault())
98 {
99 basegfx::B2DHomMatrix aTextMatrix;
100 double fTestAngle(fAngle);
101
102 if(getTextRotation())
103 {
104 aTextMatrix.rotate(-M_PI_2);
105 fTestAngle -= (M_PI_2);
106
107 if(getTextAutoAngle() && fTestAngle < -M_PI)
108 {
109 fTestAngle += 2 * M_PI;
110 }
111 }
112
113 if(getTextAutoAngle())
114 {
115 if(fTestAngle > (M_PI / 4.0) || fTestAngle < (-M_PI * (3.0 / 4.0)))
116 {
117 bAutoUpsideDown = true;
118 }
119 }
120
121 // create primitive and get text range
122 xBlockText = new SdrBlockTextPrimitive2D(
123 &rTextAttribute.getSdrText(),
124 rTextAttribute.getOutlinerParaObject(),
125 aTextMatrix,
128 rTextAttribute.isScroll(),
129 false,
130 false,
131 false);
132
133 aTextRange = xBlockText->getB2DRange(aViewInformation);
134 }
135
136 // prepare line attribute and result
137 double fTextX;
138 double fTextY;
139 {
140 const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
141 bool bArrowsOutside(false);
142 bool bMainLineSplitted(false);
144 double fStartArrowW(0.0);
145 double fStartArrowH(0.0);
146 double fEndArrowW(0.0);
147 double fEndArrowH(0.0);
148
149 if(!rLineStartEnd.isDefault())
150 {
151 if(rLineStartEnd.isStartActive())
152 {
153 const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getStartPolyPolygon()));
154 fStartArrowW = rLineStartEnd.getStartWidth();
155 fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
156
157 if(rLineStartEnd.isStartCentered())
158 {
159 fStartArrowH *= 0.5;
160 }
161 }
162
163 if(rLineStartEnd.isEndActive())
164 {
165 const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getEndPolyPolygon()));
166 fEndArrowW = rLineStartEnd.getEndWidth();
167 fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
168
169 if(rLineStartEnd.isEndCentered())
170 {
171 fEndArrowH *= 0.5;
172 }
173 }
174 }
175
176 const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
177 const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
178 const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
179
180 if(fSpaceNeededByArrows > fDistance)
181 {
182 bArrowsOutside = true;
183 }
184
185 MeasureTextPosition eHorizontal(getHorizontal());
186 MeasureTextPosition eVertical(getVertical());
187
188 if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
189 {
191 }
192
193 if(MEASURETEXTPOSITION_CENTERED == eVertical)
194 {
195 bMainLineSplitted = true;
196 }
197
198 if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
199 {
200 if(aTextRange.getWidth() > fDistance)
201 {
202 eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
203 }
204 else
205 {
206 eHorizontal = MEASURETEXTPOSITION_CENTERED;
207 }
208
209 if(bMainLineSplitted)
210 {
211 if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
212 {
213 bArrowsOutside = true;
214 }
215 }
216 else
217 {
218 const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
219
220 if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
221 {
222 bArrowsOutside = true;
223 }
224 }
225 }
226
227 if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
228 {
229 bArrowsOutside = true;
230 }
231
232 // switch text above/below?
233 if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
234 {
235 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
236 {
238 }
239 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
240 {
242 }
243 }
244
245 const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
246 const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
247 const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
248
249 // main line
250 if(bArrowsOutside)
251 {
252 double fLenLeft(fArrowsOutsideLen);
253 double fLenRight(fArrowsOutsideLen);
254
255 if(!bMainLineSplitted)
256 {
257 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
258 {
259 fLenLeft = fStartArrowH + aTextRange.getWidth();
260 }
261 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
262 {
263 fLenRight = fEndArrowH + aTextRange.getWidth();
264 }
265 }
266
267 const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
268 const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
269
270 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
271 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
272
273 if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
274 {
275 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
276 }
277 }
278 else
279 {
280 if(bMainLineSplitted)
281 {
282 const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
283 const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
284 const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
285
286 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
287 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
288 }
289 else
290 {
291 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
292 }
293 }
294
295 // left/right help line value preparation
296 const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
297 const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
298 const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
299
300 // left help line
301 const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
302 const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
303
304 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
305
306 // right help line
307 const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
308 const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
309
310 aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
311
312 // text horizontal position
313 if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
314 {
315 // left
316 const double fSmall(fArrowsOutsideLen * 0.18);
317 fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
318
319 if(bMainLineSplitted)
320 {
321 fTextX -= (fArrowsOutsideLen - fStartArrowH);
322 }
323
324 if(!rTextAttribute.isDefault())
325 {
326 fTextX -= rTextAttribute.getTextRightDistance();
327 }
328 }
329 else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
330 {
331 // right
332 const double fSmall(fArrowsOutsideLen * 0.18);
333 fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
334
335 if(bMainLineSplitted)
336 {
337 fTextX += (fArrowsOutsideLen - fEndArrowH);
338 }
339
340 if(!rTextAttribute.isDefault())
341 {
342 fTextX += rTextAttribute.getTextLeftDistance();
343 }
344 }
345 else // MEASURETEXTPOSITION_CENTERED
346 {
347 // centered
348 fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
349
350 if(!rTextAttribute.isDefault())
351 {
352 fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
353 }
354 }
355
356 // text vertical position
357 if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
358 {
359 // top
360 const double fSmall(fArrowsOutsideLen * 0.10);
361 fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
362
363 if(!rTextAttribute.isDefault())
364 {
365 fTextY -= rTextAttribute.getTextLowerDistance();
366 }
367 }
368 else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
369 {
370 // bottom
371 const double fSmall(fArrowsOutsideLen * 0.10);
372 fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
373
374 if(!rTextAttribute.isDefault())
375 {
376 fTextY += rTextAttribute.getTextUpperDistance();
377 }
378 }
379 else // MEASURETEXTPOSITION_CENTERED
380 {
381 // centered
382 fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
383
384 if(!rTextAttribute.isDefault())
385 {
386 fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
387 }
388 }
389 }
390
392 {
393 // embed line geometry to invisible (100% transparent) line group for HitTest
394 Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(std::move(aRetval)));
395
396 aRetval = Primitive2DContainer { xHiddenLines };
397 }
398
399 if(xBlockText.is())
400 {
401 // create transformation to text primitive end position
402 basegfx::B2DHomMatrix aChange;
403
404 // handle auto text rotation
405 if(bAutoUpsideDown)
406 {
407 aChange.rotate(M_PI);
408 }
409
410 // move from aTextRange.TopLeft to fTextX, fTextY
411 aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
412
413 // apply object matrix
414 aChange *= aObjectMatrix;
415
416 // apply to existing text primitive
417 rtl::Reference<SdrTextPrimitive2D> pNewBlockText = xBlockText->createTransformedClone(aChange);
418 OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
419 xBlockText.clear();
420
421 // add to local primitives
422 aRetval.push_back(pNewBlockText);
423 }
424
425 // add shadow
426 if(!getSdrLSTAttribute().getShadow().isDefault())
427 {
429 std::move(aRetval),
430 getSdrLSTAttribute().getShadow());
431 }
432
433 rContainer.append(std::move(aRetval));
434 }
435
437 const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
438 const basegfx::B2DPoint& rStart,
439 const basegfx::B2DPoint& rEnd,
440 MeasureTextPosition eHorizontal,
441 MeasureTextPosition eVertical,
442 double fDistance,
443 double fUpper,
444 double fLower,
445 double fLeftDelta,
446 double fRightDelta,
447 bool bBelow,
448 bool bTextRotation,
449 bool bTextAutoAngle)
450 : maSdrLSTAttribute(rSdrLSTAttribute),
451 maStart(rStart),
452 maEnd(rEnd),
453 meHorizontal(eHorizontal),
454 meVertical(eVertical),
455 mfDistance(fDistance),
456 mfUpper(fUpper),
457 mfLower(fLower),
458 mfLeftDelta(fLeftDelta),
459 mfRightDelta(fRightDelta),
460 mbBelow(bBelow),
461 mbTextRotation(bTextRotation),
462 mbTextAutoAngle(bTextAutoAngle)
463 {
464 }
465
467 {
468 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
469 {
470 const SdrMeasurePrimitive2D& rCompare = static_cast<const SdrMeasurePrimitive2D&>(rPrimitive);
471
472 return (getStart() == rCompare.getStart()
473 && getEnd() == rCompare.getEnd()
474 && getHorizontal() == rCompare.getHorizontal()
475 && getVertical() == rCompare.getVertical()
476 && getDistance() == rCompare.getDistance()
477 && getUpper() == rCompare.getUpper()
478 && getLower() == rCompare.getLower()
479 && getLeftDelta() == rCompare.getLeftDelta()
480 && getRightDelta() == rCompare.getRightDelta()
481 && getBelow() == rCompare.getBelow()
482 && getTextRotation() == rCompare.getTextRotation()
483 && getTextAutoAngle() == rCompare.getTextAutoAngle()
484 && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
485 }
486
487 return false;
488 }
489
490 // provide unique ID
492 {
494 }
495
496} // end of namespace
497
498/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Point maStart
const Point maEnd
void rotate(double fRadiant)
void translate(double fX, double fY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
double getLength() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
const basegfx::B2DPolyPolygon & getStartPolyPolygon() const
const basegfx::B2DPolyPolygon & getEndPolyPolygon() const
const OutlinerParaObject & getOutlinerParaObject() const
void append(const Primitive2DReference &)
virtual void create2DDecomposition(Primitive2DContainer &rContainer, const geometry::ViewInformation2D &aViewInformation) const override
SdrMeasurePrimitive2D(const attribute::SdrLineEffectsTextAttribute &rSdrLSTAttribute, const basegfx::B2DPoint &rStart, const basegfx::B2DPoint &rEnd, MeasureTextPosition eHorizontal, MeasureTextPosition eVertical, double fDistance, double fUpper, double fLower, double fLeftDelta, double fRightDelta, bool bBelow, bool bTextRotation, bool bTextAutoAngle)
virtual sal_uInt32 getPrimitive2DID() const override
virtual bool operator==(const BasePrimitive2D &rPrimitive) const override
const attribute::SdrLineEffectsTextAttribute & getSdrLSTAttribute() const
Primitive2DReference impCreatePart(const attribute::SdrLineAttribute &rLineAttribute, const basegfx::B2DHomMatrix &rObjectMatrix, const basegfx::B2DPoint &rStart, const basegfx::B2DPoint &rEnd, bool bLeftActive, bool bRightActive) const
B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
B2DRange getRange(const B2DPolygon &rCandidate)
Primitive2DContainer createEmbeddedShadowPrimitive(Primitive2DContainer &&rContent, const attribute::SdrShadowAttribute &rShadow, const basegfx::B2DHomMatrix &rObjectMatrix, const Primitive2DContainer *pContentForShadow)
Primitive2DReference createPolygonLinePrimitive(const basegfx::B2DPolygon &rPolygon, const attribute::SdrLineAttribute &rLine, const attribute::SdrLineStartEndAttribute &rStroke)
@ SDRTEXTVERTADJUST_CENTER
Definition: sdtaitm.hxx:30
@ SDRTEXTHORZADJUST_CENTER
Definition: sdtaitm.hxx:54
#define PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D