/src/libreoffice/chart2/source/view/diagram/VDiagram.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 <ShapeFactory.hxx> |
21 | | #include <VDiagram.hxx> |
22 | | #include <Diagram.hxx> |
23 | | #include <PropertyMapper.hxx> |
24 | | #include <ViewDefines.hxx> |
25 | | #include <Stripe.hxx> |
26 | | #include <ObjectIdentifier.hxx> |
27 | | #include <ChartType.hxx> |
28 | | #include <BaseGFXHelper.hxx> |
29 | | #include <ThreeDHelper.hxx> |
30 | | #include <defines.hxx> |
31 | | #include <editeng/unoprnms.hxx> |
32 | | #include <svx/scene3d.hxx> |
33 | | #include <svx/e3dsceneupdater.hxx> |
34 | | #include <comphelper/diagnose_ex.hxx> |
35 | | |
36 | | namespace chart |
37 | | { |
38 | | using namespace ::com::sun::star; |
39 | | using namespace ::com::sun::star::chart2; |
40 | | |
41 | | VDiagram::VDiagram( |
42 | | const rtl::Reference<Diagram> & xDiagram, const drawing::Direction3D& rPreferredAspectRatio, |
43 | | sal_Int32 nDimension ) |
44 | 0 | : m_nDimensionCount(nDimension) |
45 | 0 | , m_xDiagram(xDiagram) |
46 | 0 | , m_aPreferredAspectRatio(rPreferredAspectRatio) |
47 | 0 | , m_fXAnglePi(0) |
48 | 0 | , m_fYAnglePi(0) |
49 | 0 | , m_fZAnglePi(0) |
50 | 0 | , m_bRightAngledAxes(false) |
51 | 0 | { |
52 | 0 | if( m_nDimensionCount != 3) |
53 | 0 | return; |
54 | | |
55 | 0 | xDiagram->getRotationAngle( m_fXAnglePi, m_fYAnglePi, m_fZAnglePi ); |
56 | 0 | auto xChartType = m_xDiagram->getChartTypeByIndex(0); |
57 | 0 | if (xChartType.is() ? xChartType->isSupportingRightAngledAxes() : true) |
58 | 0 | { |
59 | 0 | if(xDiagram.is()) |
60 | 0 | xDiagram->getPropertyValue(u"RightAngledAxes"_ustr) >>= m_bRightAngledAxes; |
61 | 0 | if( m_bRightAngledAxes ) |
62 | 0 | { |
63 | 0 | ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fXAnglePi, m_fYAnglePi ); |
64 | 0 | m_fZAnglePi=0.0; |
65 | 0 | } |
66 | 0 | } |
67 | 0 | } |
68 | | |
69 | | VDiagram::~VDiagram() |
70 | 0 | { |
71 | 0 | } |
72 | | |
73 | | void VDiagram::init( const rtl::Reference<SvxShapeGroupAnyD>& xTarget ) |
74 | 0 | { |
75 | 0 | m_xTarget = xTarget; |
76 | 0 | } |
77 | | |
78 | | void VDiagram::createShapes( const awt::Point& rPos, const awt::Size& rSize ) |
79 | 0 | { |
80 | 0 | m_aAvailablePosIncludingAxes = rPos; |
81 | 0 | m_aAvailableSizeIncludingAxes = rSize; |
82 | |
|
83 | 0 | if( m_nDimensionCount == 3 ) |
84 | 0 | createShapes_3d(); |
85 | 0 | else |
86 | 0 | createShapes_2d(); |
87 | 0 | } |
88 | | |
89 | | ::basegfx::B2IRectangle VDiagram::adjustPosAndSize( const awt::Point& rPos, const awt::Size& rSize ) |
90 | 0 | { |
91 | 0 | ::basegfx::B2IRectangle aAllowedRect( BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) ); |
92 | 0 | ::basegfx::B2IRectangle aNewInnerRect( BaseGFXHelper::makeRectangle(rPos,rSize) ); |
93 | 0 | aNewInnerRect.intersect( aAllowedRect ); |
94 | |
|
95 | 0 | if( m_nDimensionCount == 3 ) |
96 | 0 | aNewInnerRect = adjustPosAndSize_3d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); |
97 | 0 | else |
98 | 0 | aNewInnerRect = adjustPosAndSize_2d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); |
99 | |
|
100 | 0 | return aNewInnerRect; |
101 | 0 | } |
102 | | |
103 | | ::basegfx::B2IRectangle VDiagram::adjustPosAndSize_2d( const awt::Point& rPos, const awt::Size& rAvailableSize ) |
104 | 0 | { |
105 | 0 | m_aCurrentPosWithoutAxes = rPos; |
106 | 0 | m_aCurrentSizeWithoutAxes = rAvailableSize; |
107 | 0 | if( m_aPreferredAspectRatio.DirectionX > 0 && m_aPreferredAspectRatio.DirectionY > 0) |
108 | 0 | { |
109 | | //do not change aspect ratio |
110 | 0 | awt::Size aAspectRatio( static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME), |
111 | 0 | static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME )); |
112 | 0 | m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio( |
113 | 0 | rAvailableSize, aAspectRatio ); |
114 | | //center diagram position |
115 | 0 | m_aCurrentPosWithoutAxes = ShapeFactory::calculateTopLeftPositionToCenterObject( |
116 | 0 | rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ); |
117 | |
|
118 | 0 | } |
119 | |
|
120 | 0 | if( m_xWall2D.is() ) |
121 | 0 | { |
122 | 0 | m_xWall2D->setSize( m_aCurrentSizeWithoutAxes); |
123 | 0 | m_xWall2D->setPosition(m_aCurrentPosWithoutAxes); |
124 | 0 | } |
125 | |
|
126 | 0 | return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); |
127 | 0 | } |
128 | | |
129 | | void VDiagram::createShapes_2d() |
130 | 0 | { |
131 | 0 | OSL_PRECOND(m_xTarget.is(), "is not proper initialized"); |
132 | 0 | if (!m_xTarget.is()) |
133 | 0 | return; |
134 | | |
135 | | //create group shape |
136 | 0 | rtl::Reference<SvxShapeGroupAnyD> xOuterGroup_Shapes = ShapeFactory::createGroup2D(m_xTarget); |
137 | 0 | m_xOuterGroupShape = xOuterGroup_Shapes; |
138 | |
|
139 | 0 | rtl::Reference<SvxShapeGroupAnyD> xGroupForWall( ShapeFactory::createGroup2D(xOuterGroup_Shapes,u"PlotAreaExcludingAxes"_ustr) ); |
140 | | |
141 | | //create independent group shape as container for datapoints and such things |
142 | 0 | m_xCoordinateRegionShape = ShapeFactory::createGroup2D(xOuterGroup_Shapes,u"testonly;CooContainer=XXX_CID"_ustr); |
143 | |
|
144 | 0 | bool bAddFloorAndWall = m_xDiagram->isSupportingFloorAndWall(); |
145 | | |
146 | | //add back wall |
147 | 0 | { |
148 | 0 | m_xWall2D = ShapeFactory::createRectangle( xGroupForWall ); |
149 | |
|
150 | 0 | try |
151 | 0 | { |
152 | 0 | OSL_ENSURE( m_xDiagram.is(), "Invalid Diagram model" ); |
153 | 0 | if( m_xDiagram.is() ) |
154 | 0 | { |
155 | 0 | uno::Reference< beans::XPropertySet > xWallProp( m_xDiagram->getWall()); |
156 | 0 | if( xWallProp.is()) |
157 | 0 | PropertyMapper::setMappedProperties( *m_xWall2D, xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties() ); |
158 | 0 | } |
159 | 0 | if( !bAddFloorAndWall ) |
160 | 0 | { |
161 | | //we always need this object as dummy object for correct scene dimensions |
162 | | //but it should not be visible in this case: |
163 | 0 | ShapeFactory::makeShapeInvisible( m_xWall2D ); |
164 | 0 | } |
165 | 0 | else |
166 | 0 | { |
167 | | //CID for selection handling |
168 | 0 | OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model |
169 | 0 | m_xWall2D->SvxShape::setPropertyValue( UNO_NAME_MISC_OBJ_NAME, uno::Any( aWallCID ) ); |
170 | 0 | } |
171 | 0 | } |
172 | 0 | catch( const uno::Exception& ) |
173 | 0 | { |
174 | 0 | TOOLS_WARN_EXCEPTION("chart2", "" ); |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | //position and size for diagram |
179 | 0 | adjustPosAndSize_2d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); |
180 | 0 | } |
181 | | |
182 | | static E3dScene* lcl_getE3dScene( const rtl::Reference<SvxShapeGroupAnyD>& xShape ) |
183 | 0 | { |
184 | 0 | return DynCastE3dScene(xShape->GetSdrObject()); |
185 | 0 | } |
186 | | |
187 | | static void lcl_setLightSources( |
188 | | const uno::Reference< beans::XPropertySet > & xSource, |
189 | | const uno::Reference< beans::XPropertySet > & xDest ) |
190 | 0 | { |
191 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1, |
192 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1)); |
193 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2, |
194 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2)); |
195 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3, |
196 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3)); |
197 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4, |
198 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4)); |
199 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5, |
200 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5)); |
201 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6, |
202 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6)); |
203 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7, |
204 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7)); |
205 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8, |
206 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8)); |
207 | |
|
208 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1, |
209 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1)); |
210 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2, |
211 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2)); |
212 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3, |
213 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3)); |
214 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4, |
215 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4)); |
216 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5, |
217 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5)); |
218 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6, |
219 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6)); |
220 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7, |
221 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7)); |
222 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8, |
223 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8)); |
224 | |
|
225 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_1, |
226 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_1)); |
227 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2, |
228 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2)); |
229 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_3, |
230 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_3)); |
231 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_4, |
232 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_4)); |
233 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_5, |
234 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_5)); |
235 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_6, |
236 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_6)); |
237 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_7, |
238 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_7)); |
239 | 0 | xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_8, |
240 | 0 | xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_8)); |
241 | 0 | } |
242 | | |
243 | | namespace |
244 | | { |
245 | | |
246 | | void lcl_ensureScaleValue( double& rfScale ) |
247 | 0 | { |
248 | 0 | OSL_ENSURE(rfScale>0, "calculation error for automatic 3D height in chart"); |
249 | 0 | if( rfScale<0 ) |
250 | 0 | rfScale = 1.0; |
251 | 0 | else if( rfScale<0.2 ) |
252 | 0 | rfScale = 0.2; |
253 | 0 | else if( rfScale>5.0 ) |
254 | 0 | rfScale = 5.0; |
255 | 0 | } |
256 | | |
257 | | } |
258 | | |
259 | | void VDiagram::adjustAspectRatio3d( const awt::Size& rAvailableSize ) |
260 | 0 | { |
261 | 0 | OSL_PRECOND(m_xAspectRatio3D.is(), "created shape offers no XPropertySet"); |
262 | 0 | if( !m_xAspectRatio3D.is()) |
263 | 0 | return; |
264 | | |
265 | 0 | try |
266 | 0 | { |
267 | 0 | double fScaleX = m_aPreferredAspectRatio.DirectionX; |
268 | 0 | double fScaleY = m_aPreferredAspectRatio.DirectionY; |
269 | 0 | double fScaleZ = m_aPreferredAspectRatio.DirectionZ; |
270 | | |
271 | | //normalize scale factors |
272 | 0 | { |
273 | 0 | double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); |
274 | 0 | fScaleX/=fMax; |
275 | 0 | fScaleY/=fMax; |
276 | 0 | fScaleZ/=fMax; |
277 | 0 | } |
278 | |
|
279 | 0 | if( fScaleX<0 || fScaleY<0 || fScaleZ<0 ) |
280 | 0 | { |
281 | | //calculate automatic 3D aspect ratio that fits good into the given 2D area |
282 | 0 | double fW = rAvailableSize.Width; |
283 | 0 | double fH = rAvailableSize.Height; |
284 | |
|
285 | 0 | double sx = fabs(sin(m_fXAnglePi)); |
286 | 0 | double sy = fabs(sin(m_fYAnglePi)); |
287 | 0 | double cz = fabs(cos(m_fZAnglePi)); |
288 | 0 | double sz = fabs(sin(m_fZAnglePi)); |
289 | |
|
290 | 0 | if(m_bRightAngledAxes) |
291 | 0 | { |
292 | | //base equations: |
293 | | //fH*zoomfactor == sx*fScaleZ + fScaleY; |
294 | | //fW*zoomfactor == sy*fScaleZ + fScaleX; |
295 | |
|
296 | 0 | if( fScaleX>0 && fScaleZ>0 ) |
297 | 0 | { |
298 | | //calculate fScaleY: |
299 | 0 | if( !::basegfx::fTools::equalZero(fW) ) |
300 | 0 | { |
301 | 0 | fScaleY = (fH/fW)*(sy*fScaleZ+fScaleX)-(sx*fScaleZ); |
302 | 0 | lcl_ensureScaleValue( fScaleY ); |
303 | 0 | } |
304 | 0 | else |
305 | 0 | fScaleY = 1.0;//looking from top or bottom the height is irrelevant |
306 | 0 | } |
307 | 0 | else if( fScaleY>0 && fScaleZ>0 ) |
308 | 0 | { |
309 | | //calculate fScaleX: |
310 | 0 | if( !::basegfx::fTools::equalZero(fH) ) |
311 | 0 | { |
312 | 0 | fScaleX = (fW/fH)*(sx*fScaleZ+fScaleY)-(sy*fScaleZ); |
313 | 0 | lcl_ensureScaleValue(fScaleX); |
314 | 0 | } |
315 | 0 | else |
316 | 0 | fScaleX = 1.0;//looking from top or bottom height is irrelevant |
317 | 0 | } |
318 | 0 | else |
319 | 0 | { |
320 | | //todo |
321 | 0 | OSL_FAIL("not implemented yet"); |
322 | |
|
323 | 0 | if( fScaleX<0 ) |
324 | 0 | fScaleX = 1.0; |
325 | 0 | if( fScaleY<0 ) |
326 | 0 | fScaleY = 1.0; |
327 | 0 | if( fScaleZ<0 ) |
328 | 0 | fScaleZ = 1.0; |
329 | 0 | } |
330 | 0 | } |
331 | 0 | else |
332 | 0 | { |
333 | | //base equations: |
334 | | //fH*zoomfactor == cz*fScaleY + sz*fScaleX; |
335 | | //fW*zoomfactor == cz*fScaleX + sz*fScaleY; |
336 | | //==> fScaleY*(fH*sz-fW*cz) == fScaleX*(fW*sz-fH*cz); |
337 | 0 | if( fScaleX>0 && fScaleZ>0 ) |
338 | 0 | { |
339 | | //calculate fScaleY: |
340 | 0 | double fDivide = fH*sz-fW*cz; |
341 | 0 | if( !::basegfx::fTools::equalZero(fDivide) ) |
342 | 0 | { |
343 | 0 | fScaleY = fScaleX*(fW*sz-fH*cz) / fDivide; |
344 | 0 | lcl_ensureScaleValue(fScaleY); |
345 | 0 | } |
346 | 0 | else |
347 | 0 | fScaleY = 1.0;//looking from top or bottom the height is irrelevant |
348 | |
|
349 | 0 | } |
350 | 0 | else if( fScaleY>0 && fScaleZ>0 ) |
351 | 0 | { |
352 | | //calculate fScaleX: |
353 | 0 | double fDivide = fW*sz-fH*cz; |
354 | 0 | if( !::basegfx::fTools::equalZero(fDivide) ) |
355 | 0 | { |
356 | 0 | fScaleX = fScaleY*(fH*sz-fW*cz) / fDivide; |
357 | 0 | lcl_ensureScaleValue(fScaleX); |
358 | 0 | } |
359 | 0 | else |
360 | 0 | fScaleX = 1.0;//looking from top or bottom height is irrelevant |
361 | 0 | } |
362 | 0 | else |
363 | 0 | { |
364 | | //todo |
365 | 0 | OSL_FAIL("not implemented yet"); |
366 | |
|
367 | 0 | if( fScaleX<0 ) |
368 | 0 | fScaleX = 1.0; |
369 | 0 | if( fScaleY<0 ) |
370 | 0 | fScaleY = 1.0; |
371 | 0 | if( fScaleZ<0 ) |
372 | 0 | fScaleZ = 1.0; |
373 | 0 | } |
374 | 0 | } |
375 | 0 | } |
376 | | |
377 | | //normalize scale factors |
378 | 0 | { |
379 | 0 | double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); |
380 | 0 | fScaleX/=fMax; |
381 | 0 | fScaleY/=fMax; |
382 | 0 | fScaleZ/=fMax; |
383 | 0 | } |
384 | | |
385 | | // identity matrix |
386 | 0 | ::basegfx::B3DHomMatrix aResult; |
387 | 0 | aResult.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, |
388 | 0 | -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, |
389 | 0 | -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); |
390 | 0 | aResult.scale( fScaleX, fScaleY, fScaleZ ); |
391 | 0 | aResult.translate( FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, |
392 | 0 | FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, |
393 | 0 | FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); |
394 | | |
395 | | // To get the 3D aspect ratio's effect on the 2D scene size, the scene's 2D size needs to be adapted to |
396 | | // 3D content changes here. The tooling class remembers the current 3D transformation stack |
397 | | // and in its destructor, calculates a new 2D SnapRect for the scene and it's modified 3D geometry. |
398 | 0 | E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); |
399 | |
|
400 | 0 | m_xAspectRatio3D->setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX |
401 | 0 | , uno::Any(BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aResult )) ); |
402 | 0 | } |
403 | 0 | catch( const uno::Exception& ) |
404 | 0 | { |
405 | 0 | TOOLS_WARN_EXCEPTION("chart2", "" ); |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | | ::basegfx::B2IRectangle VDiagram::adjustPosAndSize_3d( const awt::Point& rPos, const awt::Size& rAvailableSize ) |
410 | 0 | { |
411 | 0 | adjustAspectRatio3d( rAvailableSize ); |
412 | | |
413 | | //do not change aspect ratio of 3D scene with 2D bound rect |
414 | 0 | m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio( |
415 | 0 | rAvailableSize, m_xOuterGroupShape->getSize() ); |
416 | 0 | m_xOuterGroupShape->setSize( m_aCurrentSizeWithoutAxes ); |
417 | | |
418 | | //center diagram position |
419 | 0 | m_aCurrentPosWithoutAxes= ShapeFactory::calculateTopLeftPositionToCenterObject( |
420 | 0 | rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ); |
421 | 0 | m_xOuterGroupShape->setPosition(m_aCurrentPosWithoutAxes); |
422 | |
|
423 | 0 | return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); |
424 | 0 | } |
425 | | |
426 | | void VDiagram::createShapes_3d() |
427 | 0 | { |
428 | 0 | OSL_PRECOND(m_xTarget.is(), "is not proper initialized"); |
429 | 0 | if (!m_xTarget.is()) |
430 | 0 | return; |
431 | | |
432 | | //create shape |
433 | 0 | rtl::Reference<Svx3DSceneObject> xShapes = ShapeFactory::createGroup3D( m_xTarget, u"PlotAreaExcludingAxes"_ustr ); |
434 | 0 | m_xOuterGroupShape = xShapes; |
435 | |
|
436 | 0 | rtl::Reference<SvxShapeGroupAnyD> xOuterGroup_Shapes = m_xOuterGroupShape; |
437 | | |
438 | | //create additional group to manipulate the aspect ratio of the whole diagram: |
439 | 0 | { |
440 | 0 | rtl::Reference<Svx3DSceneObject> xAdditionalGroup = ShapeFactory::createGroup3D( xOuterGroup_Shapes ); |
441 | 0 | xOuterGroup_Shapes = xAdditionalGroup; |
442 | |
|
443 | 0 | m_xAspectRatio3D = std::move(xAdditionalGroup); |
444 | 0 | } |
445 | |
|
446 | 0 | bool bAddFloorAndWall = m_xDiagram->isSupportingFloorAndWall(); |
447 | |
|
448 | 0 | const bool bDoubleSided = false; |
449 | | |
450 | | //add walls |
451 | 0 | { |
452 | 0 | uno::Reference< beans::XPropertySet > xWallProp; |
453 | 0 | if( m_xDiagram.is() ) |
454 | 0 | xWallProp.set( m_xDiagram->getWall() ); |
455 | |
|
456 | 0 | OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model |
457 | 0 | if( !bAddFloorAndWall ) |
458 | 0 | aWallCID.clear(); |
459 | 0 | rtl::Reference<Svx3DSceneObject> xWallGroup_Shapes = ShapeFactory::createGroup3D( xOuterGroup_Shapes, aWallCID ); |
460 | |
|
461 | 0 | CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( m_xDiagram ) ); |
462 | 0 | CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( m_xDiagram ) ); |
463 | | |
464 | | //add left wall |
465 | 0 | { |
466 | 0 | short nRotatedTexture = ( eBackWallPos==CuboidPlanePosition_Front ) ? 3 : 1; |
467 | 0 | double xPos = 0.0; |
468 | 0 | if( eLeftWallPos==CuboidPlanePosition_Right ) |
469 | 0 | xPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; |
470 | 0 | Stripe aStripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) |
471 | 0 | , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) |
472 | 0 | , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); |
473 | 0 | if( eLeftWallPos==CuboidPlanePosition_Right ) |
474 | 0 | { |
475 | 0 | nRotatedTexture = ( eBackWallPos==CuboidPlanePosition_Front ) ? 2 : 0; |
476 | 0 | aStripe = Stripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) |
477 | 0 | , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) |
478 | 0 | , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) ); |
479 | 0 | } |
480 | 0 | aStripe.InvertNormal(true); |
481 | |
|
482 | 0 | rtl::Reference<Svx3DPolygonObject> xShape = |
483 | 0 | ShapeFactory::createStripe( xWallGroup_Shapes, aStripe |
484 | 0 | , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture ); |
485 | 0 | if( !bAddFloorAndWall ) |
486 | 0 | { |
487 | | //we always need this object as dummy object for correct scene dimensions |
488 | | //but it should not be visible in this case: |
489 | 0 | ShapeFactory::makeShapeInvisible( xShape ); |
490 | 0 | } |
491 | 0 | } |
492 | | //add back wall |
493 | 0 | { |
494 | 0 | short nRotatedTexture = 0; |
495 | 0 | double zPos = 0.0; |
496 | 0 | if( eBackWallPos==CuboidPlanePosition_Front ) |
497 | 0 | zPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; |
498 | 0 | Stripe aStripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) |
499 | 0 | , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) |
500 | 0 | , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); |
501 | 0 | if( eBackWallPos==CuboidPlanePosition_Front ) |
502 | 0 | { |
503 | 0 | aStripe = Stripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) |
504 | 0 | , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) |
505 | 0 | , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); |
506 | 0 | nRotatedTexture = 3; |
507 | 0 | } |
508 | 0 | aStripe.InvertNormal(true); |
509 | |
|
510 | 0 | rtl::Reference<Svx3DPolygonObject> xShape = |
511 | 0 | ShapeFactory::createStripe(xWallGroup_Shapes, aStripe |
512 | 0 | , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture ); |
513 | 0 | if( !bAddFloorAndWall ) |
514 | 0 | { |
515 | | //we always need this object as dummy object for correct scene dimensions |
516 | | //but it should not be visible in this case: |
517 | 0 | ShapeFactory::makeShapeInvisible( xShape ); |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | |
|
522 | 0 | try |
523 | 0 | { |
524 | | //perspective |
525 | 0 | { |
526 | | //ignore distance and focal length from file format and model completely |
527 | | //use vrp only to indicate the distance of the camera and thus influence the perspective |
528 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_DISTANCE, uno::Any( |
529 | 0 | static_cast<sal_Int32>(m_xDiagram->getCameraDistance()))); |
530 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_PERSPECTIVE, |
531 | 0 | m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_PERSPECTIVE)); |
532 | 0 | } |
533 | | |
534 | | //light |
535 | 0 | { |
536 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_SHADE_MODE, |
537 | 0 | m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_SHADE_MODE)); |
538 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR, |
539 | 0 | m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR)); |
540 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING, |
541 | 0 | m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING)); |
542 | 0 | lcl_setLightSources( m_xDiagram, m_xOuterGroupShape ); |
543 | 0 | } |
544 | | |
545 | | //rotation |
546 | 0 | { |
547 | | //set diagrams rotation is set exclusively via the transformation matrix |
548 | | //don't set a camera at all! |
549 | | //the camera's rotation is incorporated into this matrix |
550 | |
|
551 | 0 | ::basegfx::B3DHomMatrix aEffectiveTransformation; |
552 | 0 | aEffectiveTransformation.translate(-FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0); |
553 | |
|
554 | 0 | if(!m_bRightAngledAxes) |
555 | 0 | aEffectiveTransformation.rotate(m_fXAnglePi,m_fYAnglePi,m_fZAnglePi); |
556 | 0 | else |
557 | 0 | aEffectiveTransformation.shearXY(m_fYAnglePi,-m_fXAnglePi); |
558 | | |
559 | | //#i98497# 3D charts are rendered with wrong size |
560 | 0 | E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); |
561 | |
|
562 | 0 | m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX, |
563 | 0 | uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aEffectiveTransformation ) ) ); |
564 | 0 | } |
565 | 0 | } |
566 | 0 | catch( const uno::Exception & ) |
567 | 0 | { |
568 | 0 | DBG_UNHANDLED_EXCEPTION("chart2" ); |
569 | 0 | } |
570 | | |
571 | | //add floor plate |
572 | 0 | { |
573 | 0 | uno::Reference< beans::XPropertySet > xFloorProp; |
574 | 0 | if( m_xDiagram.is() ) |
575 | 0 | xFloorProp.set( m_xDiagram->getFloor() ); |
576 | |
|
577 | 0 | Stripe aStripe( drawing::Position3D(0,0,0) |
578 | 0 | , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) |
579 | 0 | , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); |
580 | 0 | aStripe.InvertNormal(true); |
581 | |
|
582 | 0 | rtl::Reference<Svx3DPolygonObject> xShape = |
583 | 0 | ShapeFactory::createStripe(xOuterGroup_Shapes, aStripe |
584 | 0 | , xFloorProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided ); |
585 | |
|
586 | 0 | CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( m_xDiagram ) ); |
587 | 0 | if( !bAddFloorAndWall || (eBottomPos!=CuboidPlanePosition_Bottom) ) |
588 | 0 | { |
589 | | //we always need this object as dummy object for correct scene dimensions |
590 | | //but it should not be visible in this case: |
591 | 0 | ShapeFactory::makeShapeInvisible( xShape ); |
592 | 0 | } |
593 | 0 | else |
594 | 0 | { |
595 | 0 | OUString aFloorCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, u"" ) );//@todo read CID from model |
596 | 0 | ShapeFactory::setShapeName( xShape, aFloorCID ); |
597 | 0 | } |
598 | 0 | } |
599 | | |
600 | | //create an additional scene for the smaller inner coordinate region: |
601 | 0 | { |
602 | 0 | rtl::Reference<Svx3DSceneObject> xShapes2 = ShapeFactory::createGroup3D( xOuterGroup_Shapes,u"testonly;CooContainer=XXX_CID"_ustr ); |
603 | 0 | m_xCoordinateRegionShape = xShapes2; |
604 | |
|
605 | 0 | try |
606 | 0 | { |
607 | 0 | double fXScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; |
608 | 0 | double fYScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; |
609 | 0 | double fZScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; |
610 | |
|
611 | 0 | ::basegfx::B3DHomMatrix aM; |
612 | 0 | aM.translate(GRID_TO_WALL_DISTANCE/fXScale, GRID_TO_WALL_DISTANCE/fYScale, GRID_TO_WALL_DISTANCE/fZScale); |
613 | 0 | aM.scale( fXScale, fYScale, fZScale ); |
614 | 0 | E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); |
615 | |
|
616 | 0 | xShapes2->SvxShape::setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX |
617 | 0 | , uno::Any(BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aM)) ); |
618 | 0 | } |
619 | 0 | catch( const uno::Exception& ) |
620 | 0 | { |
621 | 0 | TOOLS_WARN_EXCEPTION("chart2", "" ); |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | 0 | m_aCurrentPosWithoutAxes = m_aAvailablePosIncludingAxes; |
626 | 0 | m_aCurrentSizeWithoutAxes = m_aAvailableSizeIncludingAxes; |
627 | 0 | adjustPosAndSize_3d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); |
628 | 0 | } |
629 | | |
630 | | basegfx::B2IRectangle VDiagram::getCurrentRectangle() const |
631 | 0 | { |
632 | 0 | return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); |
633 | 0 | } |
634 | | |
635 | | void VDiagram::reduceToMinimumSize() |
636 | 0 | { |
637 | 0 | if( !m_xOuterGroupShape.is() ) |
638 | 0 | return; |
639 | | |
640 | 0 | awt::Size aMaxSize( m_aAvailableSizeIncludingAxes ); |
641 | 0 | awt::Point aMaxPos( m_aAvailablePosIncludingAxes ); |
642 | |
|
643 | 0 | sal_Int32 nNewWidth = std::round(aMaxSize.Width/2.2); |
644 | 0 | sal_Int32 nNewHeight = std::round(aMaxSize.Height/2.2); |
645 | 0 | awt::Size aNewSize( nNewWidth, nNewHeight ); |
646 | 0 | awt::Point aNewPos( aMaxPos ); |
647 | 0 | aNewPos.X += nNewWidth; |
648 | 0 | aNewPos.Y += nNewHeight; |
649 | |
|
650 | 0 | adjustPosAndSize( aNewPos, aNewSize ); |
651 | 0 | } |
652 | | |
653 | | ::basegfx::B2IRectangle VDiagram::adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect ) |
654 | 0 | { |
655 | 0 | awt::Point aNewPos = m_aCurrentPosWithoutAxes; |
656 | 0 | awt::Size aNewSize = m_aCurrentSizeWithoutAxes; |
657 | |
|
658 | 0 | basegfx::B2IRectangle aAvailableOuterRect = |
659 | 0 | BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes); |
660 | |
|
661 | 0 | sal_Int32 nDeltaWidth = aAvailableOuterRect.getWidth() - rConsumedOuterRect.getWidth(); |
662 | 0 | sal_Int32 nDeltaHeight = aAvailableOuterRect.getHeight() - rConsumedOuterRect.getHeight(); |
663 | 0 | if( (aNewSize.Width + nDeltaWidth) < aAvailableOuterRect.getWidth()/3 ) |
664 | 0 | nDeltaWidth = aAvailableOuterRect.getWidth()/3 - aNewSize.Width; |
665 | 0 | aNewSize.Width += nDeltaWidth; |
666 | |
|
667 | 0 | if( (aNewSize.Height + nDeltaHeight) < aAvailableOuterRect.getHeight()/3 ) |
668 | 0 | nDeltaHeight = aAvailableOuterRect.getHeight()/3 - aNewSize.Height; |
669 | 0 | aNewSize.Height += nDeltaHeight; |
670 | |
|
671 | 0 | sal_Int32 nDiffLeft = rConsumedOuterRect.getMinX() - aAvailableOuterRect.getMinX(); |
672 | 0 | sal_Int32 nDiffRight = aAvailableOuterRect.getMaxX() - rConsumedOuterRect.getMaxX(); |
673 | 0 | if( nDiffLeft >= 0 ) |
674 | 0 | aNewPos.X -= nDiffLeft; |
675 | 0 | else if( nDiffRight >= 0 ) |
676 | 0 | { |
677 | 0 | if( nDiffRight > -nDiffLeft ) |
678 | 0 | aNewPos.X += abs(nDiffLeft); |
679 | 0 | else if( nDiffRight > abs(nDeltaWidth) ) |
680 | 0 | aNewPos.X += nDiffRight; |
681 | 0 | else |
682 | 0 | aNewPos.X += abs(nDeltaWidth); |
683 | 0 | } |
684 | |
|
685 | 0 | sal_Int32 nDiffUp = rConsumedOuterRect.getMinY() - aAvailableOuterRect.getMinY(); |
686 | 0 | sal_Int32 nDiffDown = aAvailableOuterRect.getMaxY() - rConsumedOuterRect.getMaxY(); |
687 | 0 | if( nDiffUp >= 0 ) |
688 | 0 | aNewPos.Y -= nDiffUp; |
689 | 0 | else if( nDiffDown >= 0 ) |
690 | 0 | { |
691 | 0 | if( nDiffDown > -nDiffUp ) |
692 | 0 | aNewPos.Y += abs(nDiffUp); |
693 | 0 | else if( nDiffDown > abs(nDeltaHeight) ) |
694 | 0 | aNewPos.Y += nDiffDown; |
695 | 0 | else |
696 | 0 | aNewPos.Y += abs(nDeltaHeight); |
697 | 0 | } |
698 | |
|
699 | 0 | return adjustPosAndSize( aNewPos, aNewSize ); |
700 | 0 | } |
701 | | |
702 | | } //namespace chart |
703 | | |
704 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |