/src/libreoffice/chart2/source/view/main/PolarLabelPositionHelper.cxx
Line | Count | Source |
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 | | |
20 | | #include <PolarLabelPositionHelper.hxx> |
21 | | #include <PlottingPositionHelper.hxx> |
22 | | #include <basegfx/vector/b2dvector.hxx> |
23 | | #include <basegfx/vector/b2ivector.hxx> |
24 | | |
25 | | #include <com/sun/star/chart/DataLabelPlacement.hpp> |
26 | | |
27 | | namespace chart |
28 | | { |
29 | | using namespace ::com::sun::star; |
30 | | |
31 | | PolarLabelPositionHelper::PolarLabelPositionHelper( |
32 | | PolarPlottingPositionHelper* pPosHelper |
33 | | , sal_Int32 nDimensionCount |
34 | | , const rtl::Reference<SvxShapeGroupAnyD>& xLogicTarget ) |
35 | 0 | : LabelPositionHelper( nDimensionCount, xLogicTarget ) |
36 | 0 | , m_pPosHelper(pPosHelper) |
37 | 0 | { |
38 | 0 | } |
39 | | |
40 | | PolarLabelPositionHelper::~PolarLabelPositionHelper() |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForLogicValues( |
45 | | LabelAlignment& rAlignment |
46 | | , double fLogicValueOnAngleAxis |
47 | | , double fLogicValueOnRadiusAxis |
48 | | , double fLogicZ |
49 | | , sal_Int32 nScreenValueOffsetInRadiusDirection ) const |
50 | 0 | { |
51 | 0 | double fUnitCircleAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicValueOnAngleAxis ); |
52 | 0 | double fUnitCircleRadius = m_pPosHelper->transformToRadius( fLogicValueOnRadiusAxis ); |
53 | |
|
54 | 0 | return getLabelScreenPositionAndAlignmentForUnitCircleValues( |
55 | 0 | rAlignment, css::chart::DataLabelPlacement::OUTSIDE |
56 | 0 | , fUnitCircleAngleDegree, 0.0 |
57 | 0 | , fUnitCircleRadius, fUnitCircleRadius, fLogicZ, nScreenValueOffsetInRadiusDirection ); |
58 | 0 | } |
59 | | |
60 | | awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues( |
61 | | LabelAlignment& rAlignment, sal_Int32 nLabelPlacement |
62 | | , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree |
63 | | , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius |
64 | | , double fLogicZ |
65 | | , sal_Int32 nScreenValueOffsetInRadiusDirection |
66 | | , const ::basegfx::B3DVector& aOffset) const |
67 | 0 | { |
68 | 0 | bool bCenter = (nLabelPlacement != css::chart::DataLabelPlacement::OUTSIDE) |
69 | 0 | && (nLabelPlacement != css::chart::DataLabelPlacement::INSIDE); |
70 | |
|
71 | 0 | double fAngleDegree = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0; |
72 | 0 | double fRadius = 0.0; |
73 | 0 | if( !bCenter ) //e.g. for pure pie chart(one ring only) or for angle axis of polar coordinate system |
74 | 0 | fRadius = fUnitCircleOuterRadius; |
75 | 0 | else |
76 | 0 | fRadius = fUnitCircleInnerRadius + (fUnitCircleOuterRadius-fUnitCircleInnerRadius)/2.0 ; |
77 | |
|
78 | 0 | awt::Point aRet( transformSceneToScreenPosition( |
79 | 0 | m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, |
80 | 0 | fLogicZ+0.5, aOffset ) ) ); |
81 | |
|
82 | 0 | if(m_nDimensionCount==3 && nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE) |
83 | 0 | { |
84 | | //check whether the upper or the downer edge is more distant from the center |
85 | | //take the farthest point to put the label to |
86 | |
|
87 | 0 | awt::Point aP0( transformSceneToScreenPosition( |
88 | 0 | m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ, aOffset ) ) ); |
89 | 0 | awt::Point aP1(aRet); |
90 | 0 | awt::Point aP2( transformSceneToScreenPosition( |
91 | 0 | m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, |
92 | 0 | fLogicZ-0.5, aOffset ) ) ); |
93 | |
|
94 | 0 | ::basegfx::B2DVector aV0( aP0.X, aP0.Y ); |
95 | 0 | ::basegfx::B2DVector aV1( aP1.X, aP1.Y ); |
96 | 0 | ::basegfx::B2DVector aV2( aP2.X, aP2.Y ); |
97 | |
|
98 | 0 | double fL1 = ::basegfx::B2DVector(aV1-aV0).getLength(); |
99 | 0 | double fL2 = ::basegfx::B2DVector(aV2-aV0).getLength(); |
100 | |
|
101 | 0 | if(fL2>fL1) |
102 | 0 | aRet = aP2; |
103 | | |
104 | | //calculate new angle for alignment |
105 | 0 | double fDX = aRet.X-aP0.X; |
106 | 0 | double fDY = aRet.Y-aP0.Y; |
107 | 0 | fDY*=-1.0;//drawing layer has inverse y values |
108 | |
|
109 | 0 | fAngleDegree = basegfx::rad2deg(atan2(fDY,fDX)); |
110 | 0 | } |
111 | | //set LabelAlignment |
112 | 0 | if( !bCenter ) |
113 | 0 | { |
114 | | // tdf#123504: both 0 and 360 are valid and different values here! |
115 | 0 | while (fAngleDegree > 360.0) |
116 | 0 | fAngleDegree -= 360.0; |
117 | 0 | while (fAngleDegree < 0.0) |
118 | 0 | fAngleDegree += 360.0; |
119 | |
|
120 | 0 | bool bOutside = nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE; |
121 | |
|
122 | 0 | if (fAngleDegree <= 5 || fAngleDegree >= 355) |
123 | 0 | rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; |
124 | 0 | else if (fAngleDegree < 85) |
125 | 0 | rAlignment = bOutside ? LABEL_ALIGN_RIGHT_TOP : LABEL_ALIGN_LEFT_BOTTOM; |
126 | 0 | else if (fAngleDegree <= 95) |
127 | 0 | rAlignment = bOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; |
128 | 0 | else if (fAngleDegree < 175) |
129 | 0 | rAlignment = bOutside ? LABEL_ALIGN_LEFT_TOP : LABEL_ALIGN_RIGHT_BOTTOM; |
130 | 0 | else if (fAngleDegree <= 185) |
131 | 0 | rAlignment = bOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; |
132 | 0 | else if (fAngleDegree < 265) |
133 | 0 | rAlignment = bOutside ? LABEL_ALIGN_LEFT_BOTTOM : LABEL_ALIGN_RIGHT_TOP; |
134 | 0 | else if (fAngleDegree <= 275) |
135 | 0 | rAlignment = bOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; |
136 | 0 | else |
137 | 0 | rAlignment = bOutside ? LABEL_ALIGN_RIGHT_BOTTOM : LABEL_ALIGN_LEFT_TOP; |
138 | 0 | } |
139 | 0 | else |
140 | 0 | { |
141 | 0 | rAlignment = LABEL_ALIGN_CENTER; |
142 | 0 | } |
143 | | |
144 | | //add a scaling independent Offset if requested |
145 | 0 | if( nScreenValueOffsetInRadiusDirection != 0) |
146 | 0 | { |
147 | 0 | awt::Point aOrigin( transformSceneToScreenPosition( |
148 | 0 | m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+0.5, |
149 | 0 | aOffset ) ) ); |
150 | 0 | basegfx::B2IVector aDirection( aRet.X- aOrigin.X, aRet.Y- aOrigin.Y ); |
151 | 0 | aDirection.setLength(nScreenValueOffsetInRadiusDirection); |
152 | 0 | aRet.X += aDirection.getX(); |
153 | 0 | aRet.Y += aDirection.getY(); |
154 | 0 | } |
155 | |
|
156 | 0 | return aRet; |
157 | 0 | } |
158 | | |
159 | | } //namespace chart |
160 | | |
161 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |