1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 #include "VDiagram.hxx"
31 #include "PropertyMapper.hxx"
32 #include "ViewDefines.hxx"
33 #include "Stripe.hxx"
34 #include "macros.hxx"
35 #include "ObjectIdentifier.hxx"
36 #include "DiagramHelper.hxx"
37 #include "BaseGFXHelper.hxx"
38 #include "CommonConverters.hxx"
39 #include "ChartTypeHelper.hxx"
40 #include "ThreeDHelper.hxx"
41 #include <editeng/unoprnms.hxx>
42 #include <tools/color.hxx>
43 #include <tools/debug.hxx>
44 #include <com/sun/star/drawing/FillStyle.hpp>
45 #include <com/sun/star/drawing/LineStyle.hpp>
46 #include <com/sun/star/drawing/ProjectionMode.hpp>
47 #include <com/sun/star/drawing/ShadeMode.hpp>
48 #include <com/sun/star/lang/XUnoTunnel.hpp>
49 #include <com/sun/star/lang/XTypeProvider.hpp>
50 // header for class SvxShape
51 #include <svx/unoshape.hxx>
52 // header for class E3dScene
53 #include <svx/scene3d.hxx>
54 #include <svx/e3dsceneupdater.hxx>
55 
56 //.............................................................................
57 namespace chart
58 {
59 //.............................................................................
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::chart2;
62 
63 VDiagram::VDiagram(
64     const uno::Reference< XDiagram > & xDiagram
65     , const drawing::Direction3D& rPreferredAspectRatio
66     , sal_Int32 nDimension, sal_Bool bPolar )
67     : m_xLogicTarget(NULL)
68 	, m_xFinalTarget(NULL)
69     , m_xShapeFactory(NULL)
70     , m_pShapeFactory(NULL)
71     , m_xOuterGroupShape(NULL)
72     , m_xCoordinateRegionShape(NULL)
73     , m_xWall2D(NULL)
74     , m_nDimensionCount(nDimension)
75     , m_bPolar(bPolar)
76     , m_xDiagram(xDiagram)
77     , m_aPreferredAspectRatio(rPreferredAspectRatio)
78     , m_xAspectRatio3D()
79     , m_fXAnglePi(0)
80     , m_fYAnglePi(0)
81     , m_fZAnglePi(0)
82     , m_bRightAngledAxes(sal_False)
83 {
84     if( m_nDimensionCount == 3)
85     {
86         uno::Reference< beans::XPropertySet > xSourceProp( m_xDiagram, uno::UNO_QUERY );
87         ThreeDHelper::getRotationAngleFromDiagram( xSourceProp, m_fXAnglePi, m_fYAnglePi, m_fZAnglePi );
88         if( ChartTypeHelper::isSupportingRightAngledAxes(
89                 DiagramHelper::getChartTypeByIndex( m_xDiagram, 0 ) ) )
90         {
91             if(xSourceProp.is())
92                 xSourceProp->getPropertyValue(C2U( "RightAngledAxes" )) >>= m_bRightAngledAxes;
93             if( m_bRightAngledAxes )
94             {
95                 ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fXAnglePi, m_fYAnglePi );
96                 m_fZAnglePi=0.0;
97             }
98         }
99     }
100 }
101 
102 VDiagram::~VDiagram()
103 {
104     delete m_pShapeFactory;
105 }
106 
107 void VDiagram::init(
108                 const uno::Reference< drawing::XShapes >& xLogicTarget
109 			  , const uno::Reference< drawing::XShapes >& xFinalTarget
110               , const uno::Reference< lang::XMultiServiceFactory >& xFactory )
111 {
112     DBG_ASSERT(xLogicTarget.is()&&xFinalTarget.is()&&xFactory.is(),"no proper initialization parameters");
113 
114     m_xLogicTarget  = xLogicTarget;
115     m_xFinalTarget  = xFinalTarget;
116     m_xShapeFactory = xFactory;
117     m_pShapeFactory = new ShapeFactory(xFactory);
118 }
119 
120 void VDiagram::createShapes( const awt::Point& rPos, const awt::Size& rSize )
121 {
122     m_aAvailablePosIncludingAxes = rPos;
123     m_aAvailableSizeIncludingAxes = rSize;
124 
125     if( m_nDimensionCount == 3 )
126         createShapes_3d();
127     else
128         createShapes_2d();
129 }
130 
131 ::basegfx::B2IRectangle VDiagram::adjustPosAndSize( const awt::Point& rPos, const awt::Size& rSize )
132 {
133     ::basegfx::B2IRectangle aAllowedRect( BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) );
134     ::basegfx::B2IRectangle aNewInnerRect( BaseGFXHelper::makeRectangle(rPos,rSize) );
135     aNewInnerRect.intersect( aAllowedRect );
136 
137     if( m_nDimensionCount == 3 )
138         aNewInnerRect = adjustPosAndSize_3d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) );
139     else
140         aNewInnerRect = adjustPosAndSize_2d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) );
141 
142     return aNewInnerRect;
143 }
144 
145 ::basegfx::B2IRectangle VDiagram::adjustPosAndSize_2d( const awt::Point& rPos, const awt::Size& rAvailableSize )
146 {
147     m_aCurrentPosWithoutAxes = rPos;
148     m_aCurrentSizeWithoutAxes = rAvailableSize;
149     if( m_aPreferredAspectRatio.DirectionX > 0 && m_aPreferredAspectRatio.DirectionY > 0)
150     {
151         //do not change aspect ratio
152         awt::Size  aAspectRatio( static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME),
153                                  static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME ));
154         m_aCurrentSizeWithoutAxes = awt::Size( ShapeFactory::calculateNewSizeRespectingAspectRatio(
155                         rAvailableSize, aAspectRatio ) );
156         //center diagram position
157         m_aCurrentPosWithoutAxes = awt::Point( ShapeFactory::calculateTopLeftPositionToCenterObject(
158             rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ) );
159 
160     }
161 
162     if( m_xWall2D.is() )
163     {
164         m_xWall2D->setSize( m_aCurrentSizeWithoutAxes);
165         m_xWall2D->setPosition(m_aCurrentPosWithoutAxes);
166     }
167 
168     return ::basegfx::B2IRectangle( BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes) );
169 }
170 
171 void VDiagram::createShapes_2d()
172 {
173     DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is(),"is not proper initialized");
174     if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is()))
175         return;
176 
177     //create group shape
178     uno::Reference< drawing::XShapes > xOuterGroup_Shapes = m_pShapeFactory->createGroup2D(m_xLogicTarget);
179     m_xOuterGroupShape = uno::Reference<drawing::XShape>( xOuterGroup_Shapes, uno::UNO_QUERY );
180 
181     uno::Reference< drawing::XShapes > xGroupForWall( m_pShapeFactory->createGroup2D(xOuterGroup_Shapes,C2U("PlotAreaExcludingAxes")) );
182 
183     //create independent group shape as container for datapoints and such things
184     {
185         uno::Reference< drawing::XShapes > xShapes = m_pShapeFactory->createGroup2D(xOuterGroup_Shapes,C2U("testonly;CooContainer=XXX_CID"));
186         m_xCoordinateRegionShape = uno::Reference<drawing::XShape>( xShapes, uno::UNO_QUERY );
187     }
188 
189     //---------------------------
190     bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram );
191 
192     //add back wall
193     {
194         m_xWall2D = uno::Reference< drawing::XShape >(
195 			m_xShapeFactory->createInstance( C2U(
196             "com.sun.star.drawing.RectangleShape" ) ), uno::UNO_QUERY );
197         //m_xWall2D->setPosition(m_aAvailablePosIncludingAxes);
198         //m_xWall2D->setSize(m_aAvailableSizeIncludingAxes);
199         xGroupForWall->add(m_xWall2D);
200         uno::Reference< beans::XPropertySet > xProp( m_xWall2D, uno::UNO_QUERY );
201         if( xProp.is())
202 	    {
203 		    try
204 		    {
205                 DBG_ASSERT( m_xDiagram.is(), "Invalid Diagram model" );
206                 if( m_xDiagram.is() )
207                 {
208                     uno::Reference< beans::XPropertySet > xWallProp( m_xDiagram->getWall());
209                     if( xWallProp.is())
210                         PropertyMapper::setMappedProperties( xProp, xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties() );
211                 }
212                 if( !bAddFloorAndWall )
213                 {
214                     //we always need this object as dummy object for correct scene dimensions
215                     //but it should not be visible in this case:
216                     ShapeFactory::makeShapeInvisible( m_xWall2D );
217                 }
218                 else
219                 {
220                     //CID for selection handling
221                     rtl::OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) );//@todo read CID from model
222                     xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ), uno::makeAny( aWallCID ) );
223                 }
224             }
225 		    catch( uno::Exception& e )
226 		    {
227                 ASSERT_EXCEPTION( e );
228             }
229 	    }
230 
231     }
232 
233     //---------------------------
234     //position and size for diagram
235     adjustPosAndSize_2d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes );
236 }
237 
238 E3dScene* lcl_getE3dScene( const uno::Reference< drawing::XShape >& xShape )
239 {
240     E3dScene* pRet=NULL;
241     uno::Reference< lang::XUnoTunnel > xUnoTunnel( xShape, uno::UNO_QUERY );
242     uno::Reference< lang::XTypeProvider > xTypeProvider( xShape, uno::UNO_QUERY );
243     if(xUnoTunnel.is()&&xTypeProvider.is())
244     {
245         SvxShape* pSvxShape = reinterpret_cast<SvxShape*>(xUnoTunnel->getSomething( SvxShape::getUnoTunnelId() ));
246         if(pSvxShape)
247         {
248             SdrObject* pObj = pSvxShape->GetSdrObject();
249             if( pObj && pObj->ISA(E3dScene) )
250                 pRet = (E3dScene*)pObj;
251         }
252     }
253     return pRet;
254 }
255 
256 void lcl_setLightSources(
257     const uno::Reference< beans::XPropertySet > & xSource,
258     const uno::Reference< beans::XPropertySet > & xDest )
259 {
260     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ),
261                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 )));
262     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ),
263                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 )));
264     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ),
265                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 )));
266     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ),
267                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 )));
268     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ),
269                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 )));
270     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ),
271                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 )));
272     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ),
273                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 )));
274     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ),
275                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 )));
276 
277     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1 ),
278                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1 )));
279     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ),
280                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 )));
281     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3 ),
282                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3 )));
283     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4 ),
284                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4 )));
285     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5 ),
286                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5 )));
287     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6 ),
288                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6 )));
289     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7 ),
290                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7 )));
291     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8 ),
292                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8 )));
293 
294     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_1 ),
295                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_1 )));
296     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ),
297                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 )));
298     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_3 ),
299                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_3 )));
300     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_4 ),
301                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_4 )));
302     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_5 ),
303                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_5 )));
304     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_6 ),
305                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_6 )));
306     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_7 ),
307                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_7 )));
308     xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_8 ),
309                              xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_8 )));
310 }
311 
312 namespace
313 {
314 
315 void lcl_ensureScaleValue( double& rfScale )
316 {
317     DBG_ASSERT(rfScale>0, "calculation error for automatic 3D height in chart");
318     if( rfScale<0 )
319         rfScale = 1.0;
320     else if( rfScale<0.2 )
321         rfScale = 0.2;
322     else if( rfScale>5.0 )
323         rfScale = 5.0;
324 }
325 
326 }
327 
328 void VDiagram::adjustAspectRatio3d( const awt::Size& rAvailableSize )
329 {
330     DBG_ASSERT(m_xAspectRatio3D.is(), "created shape offers no XPropertySet");
331 	if( m_xAspectRatio3D.is())
332 	{
333 		try
334 		{
335             double fScaleX = m_aPreferredAspectRatio.DirectionX;
336             double fScaleY = m_aPreferredAspectRatio.DirectionY;
337             double fScaleZ = m_aPreferredAspectRatio.DirectionZ;
338 
339             //normalize scale factors
340             {
341                 double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ );
342                 fScaleX/=fMax;
343                 fScaleY/=fMax;
344                 fScaleZ/=fMax;
345             }
346 
347             if( fScaleX<0 || fScaleY<0 || fScaleZ<0 )
348             {
349                 //calculate automatic 3D aspect ratio that fits good into the given 2D area
350                 double fW = rAvailableSize.Width;
351                 double fH = rAvailableSize.Height;
352 
353 //                 double cx = fabs(cos(m_fXAnglePi));
354                 double sx = fabs(sin(m_fXAnglePi));
355 //                 double cy = fabs(cos(m_fYAnglePi));
356                 double sy = fabs(sin(m_fYAnglePi));
357                 double cz = fabs(cos(m_fZAnglePi));
358                 double sz = fabs(sin(m_fZAnglePi));
359 
360                 if(m_bRightAngledAxes)
361                 {
362                     //base equations:
363                     //fH*zoomfactor == sx*fScaleZ + fScaleY;
364                     //fW*zoomfactor == sy*fScaleZ + fScaleX;
365 
366                     if( fScaleX>0 && fScaleZ>0 )
367                     {
368                         //calculate fScaleY:
369                         if( !::basegfx::fTools::equalZero(fW) )
370                         {
371                             fScaleY = (fH/fW)*(sy*fScaleZ+fScaleX)-(sx*fScaleZ);
372                             lcl_ensureScaleValue( fScaleY );
373                         }
374                         else
375                             fScaleY = 1.0;//looking from top or bottom the height is irrelevant
376                     }
377                     else if( fScaleY>0 && fScaleZ>0 )
378                     {
379                         //calculate fScaleX:
380                         if( !::basegfx::fTools::equalZero(fH) )
381                         {
382                             fScaleX = (fW/fH)*(sx*fScaleZ+fScaleY)-(sy*fScaleZ);
383                             lcl_ensureScaleValue(fScaleX);
384                         }
385                         else
386                             fScaleX = 1.0;//looking from top or bottom hieght is irrelevant
387                     }
388                     else
389                     {
390                         //todo
391                         DBG_ASSERT(false, "not implemented yet");
392 
393                         if( fScaleX<0 )
394                             fScaleX = 1.0;
395                         if( fScaleY<0 )
396                             fScaleY = 1.0;
397                         if( fScaleZ<0 )
398                             fScaleZ = 1.0;
399                     }
400                 }
401                 else
402                 {
403                     //base equations:
404                     //fH*zoomfactor == cz*fScaleY + sz*fScaleX;
405                     //fW*zoomfactor == cz*fScaleX + sz*fScaleY;
406                     //==>  fScaleY*(fH*sz-fW*cz) == fScaleX*(fW*sz-fH*cz);
407                     if( fScaleX>0 && fScaleZ>0 )
408                     {
409                         //calculate fScaleY:
410                         double fDivide = fH*sz-fW*cz;
411                         if( !::basegfx::fTools::equalZero(fDivide) )
412                         {
413                             fScaleY = fScaleX*(fW*sz-fH*cz) / fDivide;
414                             lcl_ensureScaleValue(fScaleY);
415                         }
416                         else
417                             fScaleY = 1.0;//looking from top or bottom the height is irrelevant
418 
419                         /*
420                         //fW*zoomfactor == fScaleX*cy*cz + fScaleY*sz*cy + fScaleZ*sy*cx;
421                         //fH*zoomfactor == fScaleY*cx*cz + fScaleX*sz*cy + fScaleZ*sx*cz;
422                         //==> fScaleY*(sz*cy*fH -cx*cz*fW) =  fScaleX*(sz*cy*fW - cy*cz*fH) + fScaleZ*(sx*cz*fW - sy*cx*fH);
423                         double fDivide = sz*cy*fH -cx*cz*fW;
424                         if( !::basegfx::fTools::equalZero(fDivide) )
425                         {
426                             fScaleY = ( fScaleX*(sz*cy*fW - cy*cz*fH)
427                                 + fScaleZ*(sx*cz*fW - sy*cx*fH) ) / fDivide;
428                             lcl_ensureScaleValue(fScaleY);
429                         }
430                         else
431                             fScaleY = 1.0;//looking from top or bottom hieght is irrelevant
432                         */
433                     }
434                     else if( fScaleY>0 && fScaleZ>0 )
435                     {
436                         //calculate fScaleX:
437                         double fDivide = fW*sz-fH*cz;
438                         if( !::basegfx::fTools::equalZero(fDivide) )
439                         {
440                             fScaleX = fScaleY*(fH*sz-fW*cz) / fDivide;
441                             lcl_ensureScaleValue(fScaleX);
442                         }
443                         else
444                             fScaleX = 1.0;//looking from top or bottom hieght is irrelevant
445                     }
446                     else
447                     {
448                         //todo
449                         DBG_ASSERT(false, "not implemented yet");
450 
451                         if( fScaleX<0 )
452                             fScaleX = 1.0;
453                         if( fScaleY<0 )
454                             fScaleY = 1.0;
455                         if( fScaleZ<0 )
456                             fScaleZ = 1.0;
457                     }
458                 }
459             }
460 
461             //normalize scale factors
462             {
463                 double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ );
464                 fScaleX/=fMax;
465                 fScaleY/=fMax;
466                 fScaleZ/=fMax;
467             }
468 
469             // identity matrix
470             ::basegfx::B3DHomMatrix aResult;
471             aResult.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
472                             -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
473                             -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 );
474             aResult.scale( fScaleX, fScaleY, fScaleZ );
475             aResult.translate( FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
476                             FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
477                             FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 );
478 
479             // To get the 3D aspect ratio's effect on the 2D scene size, the scene's 2D size needs to be adapted to
480             // 3D content changes here. The tooling class remembers the current 3D transformation stack
481             // and in it's destructor, calculates a new 2D SnapRect for the scene and it's modified 3D geometry.
482             E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape ));
483 
484             m_xAspectRatio3D->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX )
485                 , uno::makeAny(BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aResult )) );
486         }
487         catch( uno::Exception& e )
488 		{
489             ASSERT_EXCEPTION( e );
490         }
491     }
492 }
493 
494 ::basegfx::B2IRectangle VDiagram::adjustPosAndSize_3d( const awt::Point& rPos, const awt::Size& rAvailableSize )
495 {
496     adjustAspectRatio3d( rAvailableSize );
497 
498     //do not change aspect ratio of 3D scene with 2D bound rect
499     m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio(
500                     rAvailableSize, m_xOuterGroupShape->getSize() );
501     m_xOuterGroupShape->setSize( m_aCurrentSizeWithoutAxes );
502 
503     //center diagram position
504     m_aCurrentPosWithoutAxes= ShapeFactory::calculateTopLeftPositionToCenterObject(
505          rPos, rAvailableSize, m_aCurrentSizeWithoutAxes );
506     m_xOuterGroupShape->setPosition(m_aCurrentPosWithoutAxes);
507 
508     return ::basegfx::B2IRectangle( BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes) );
509 }
510 
511 void VDiagram::createShapes_3d()
512 {
513     DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is(),"is not proper initialized");
514     if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is()))
515         return;
516 
517     //create shape
518     m_xOuterGroupShape = uno::Reference< drawing::XShape >(
519 			m_xShapeFactory->createInstance( C2U(
520             "com.sun.star.drawing.Shape3DSceneObject" ) ), uno::UNO_QUERY );
521     ShapeFactory::setShapeName( m_xOuterGroupShape, C2U("PlotAreaExcludingAxes") );
522     m_xLogicTarget->add(m_xOuterGroupShape);
523 
524     uno::Reference< drawing::XShapes > xOuterGroup_Shapes =
525             uno::Reference<drawing::XShapes>( m_xOuterGroupShape, uno::UNO_QUERY );
526 
527 
528     //-------------------------------------------------------------------------
529     //create additional group to manipulate the aspect ratio of the whole diagram:
530     xOuterGroup_Shapes = m_pShapeFactory->createGroup3D( xOuterGroup_Shapes, rtl::OUString() );
531 
532     m_xAspectRatio3D = uno::Reference< beans::XPropertySet >( xOuterGroup_Shapes, uno::UNO_QUERY );
533 
534     //---------------------------
535 
536     bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram );
537 
538     const bool bDoubleSided = false;
539     const bool bFlatNormals = true;
540 
541     //add walls
542     {
543         uno::Reference< beans::XPropertySet > xWallProp( NULL );
544         if( m_xDiagram.is() )
545             xWallProp=uno::Reference< beans::XPropertySet >( m_xDiagram->getWall());
546 
547         rtl::OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) );//@todo read CID from model
548         if( !bAddFloorAndWall )
549             aWallCID = rtl::OUString();
550         uno::Reference< drawing::XShapes > xWallGroup_Shapes( m_pShapeFactory->createGroup3D( xOuterGroup_Shapes, aWallCID ) );
551 
552         CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) );
553         CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) );
554 
555         //add left wall
556         {
557             short nRotatedTexture = ( CuboidPlanePosition_Front==eBackWallPos ) ? 3 : 1;
558             double xPos = 0.0;
559             if( CuboidPlanePosition_Right==eLeftWallPos )
560                 xPos = FIXED_SIZE_FOR_3D_CHART_VOLUME;
561             Stripe aStripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0)
562                 , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME)
563                 , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) );
564             if( CuboidPlanePosition_Right==eLeftWallPos )
565             {
566                 nRotatedTexture = ( CuboidPlanePosition_Front==eBackWallPos ) ? 2 : 0;
567                 aStripe = Stripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0)
568                     , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0)
569                     , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) );
570             }
571             aStripe.InvertNormal(true);
572 
573             uno::Reference< drawing::XShape > xShape =
574                 m_pShapeFactory->createStripe( xWallGroup_Shapes, aStripe
575                     , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture, bFlatNormals );
576             if( !bAddFloorAndWall )
577             {
578                 //we always need this object as dummy object for correct scene dimensions
579                 //but it should not be visible in this case:
580                 ShapeFactory::makeShapeInvisible( xShape );
581             }
582         }
583         //add back wall
584         {
585             short nRotatedTexture = 0;
586             double zPos = 0.0;
587             if( CuboidPlanePosition_Front==eBackWallPos )
588                     zPos = FIXED_SIZE_FOR_3D_CHART_VOLUME;
589             Stripe aStripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos)
590                 , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0)
591                 , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) );
592             if( CuboidPlanePosition_Front==eBackWallPos )
593             {
594                 aStripe = Stripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos)
595                 , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0)
596                 , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) );
597                 nRotatedTexture = 3;
598             }
599             aStripe.InvertNormal(true);
600 
601             uno::Reference< drawing::XShape > xShape =
602                 m_pShapeFactory->createStripe(xWallGroup_Shapes, aStripe
603                     , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture, bFlatNormals );
604             if( !bAddFloorAndWall )
605             {
606                 //we always need this object as dummy object for correct scene dimensions
607                 //but it should not be visible in this case:
608                 ShapeFactory::makeShapeInvisible( xShape );
609             }
610         }
611     }
612 
613     try
614     {
615         uno::Reference< beans::XPropertySet > xSourceProp( m_xDiagram, uno::UNO_QUERY_THROW );
616         uno::Reference< beans::XPropertySet > xDestProp( m_xOuterGroupShape, uno::UNO_QUERY_THROW );
617 
618         //perspective
619         {
620             //ignore distance and focal length from file format and model comcpletely
621             //use vrp only to indicate the distance of the camera and thus influence the perspecitve
622             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_DISTANCE ), uno::makeAny(
623                                         static_cast<sal_Int32>(ThreeDHelper::getCameraDistance( xSourceProp ))));
624             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_PERSPECTIVE ),
625                                         xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_PERSPECTIVE )));
626         }
627 
628         //light
629         {
630             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_SHADE_MODE ),
631                                         xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_SHADE_MODE )));
632             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ),
633                                         xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR )));
634             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING ),
635                                         xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING )));
636             lcl_setLightSources( xSourceProp, xDestProp );
637         }
638 
639         //rotation
640         {
641             //set diagrams rotation is set exclusively vie the transformation matrix
642             //don't set a camera at all!
643             //the cameras rotation is incorporated into this matrix
644 
645             ::basegfx::B3DHomMatrix aEffectiveTranformation;
646             aEffectiveTranformation.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);
647 
648             if(!m_bRightAngledAxes)
649                 aEffectiveTranformation.rotate(m_fXAnglePi,m_fYAnglePi,m_fZAnglePi);
650             else
651                 aEffectiveTranformation.shearXY(m_fYAnglePi,-m_fXAnglePi);
652 
653             //#i98497# 3D charts are rendered with wrong size
654             E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape ));
655             xDestProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ),
656                     uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aEffectiveTranformation ) ) );
657         }
658     }
659     catch( const uno::Exception & ex )
660     {
661         ASSERT_EXCEPTION( ex );
662     }
663 
664     //add floor plate
665     {
666         uno::Reference< beans::XPropertySet > xFloorProp( NULL );
667         if( m_xDiagram.is() )
668             xFloorProp=uno::Reference< beans::XPropertySet >( m_xDiagram->getFloor());
669 
670         Stripe aStripe( drawing::Position3D(0,0,0)
671             , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME)
672             , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) );
673         aStripe.InvertNormal(true);
674 
675         uno::Reference< drawing::XShape > xShape =
676             m_pShapeFactory->createStripe(xOuterGroup_Shapes, aStripe
677                 , xFloorProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, 0, bFlatNormals );
678 
679         CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) );
680         if( !bAddFloorAndWall || (CuboidPlanePosition_Bottom!=eBottomPos) )
681         {
682             //we always need this object as dummy object for correct scene dimensions
683             //but it should not be visible in this case:
684             ShapeFactory::makeShapeInvisible( xShape );
685         }
686         else
687         {
688             rtl::OUString aFloorCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, rtl::OUString() ) );//@todo read CID from model
689             ShapeFactory::setShapeName( xShape, aFloorCID );
690         }
691     }
692     //---------------------------
693 
694     //create an additional scene for the smaller inner coordinate region:
695     {
696         uno::Reference< drawing::XShapes > xShapes = m_pShapeFactory->createGroup3D( xOuterGroup_Shapes,C2U("testonly;CooContainer=XXX_CID") );
697         m_xCoordinateRegionShape = uno::Reference< drawing::XShape >( xShapes, uno::UNO_QUERY );
698 
699         uno::Reference< beans::XPropertySet > xShapeProp( m_xCoordinateRegionShape, uno::UNO_QUERY );
700         DBG_ASSERT(xShapeProp.is(), "created shape offers no XPropertySet");
701 	    if( xShapeProp.is())
702 	    {
703 		    try
704 		    {
705                 double fXScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME;
706                 double fYScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME;
707                 double fZScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME;
708 
709                 ::basegfx::B3DHomMatrix aM;
710                 aM.translate(GRID_TO_WALL_DISTANCE/fXScale, GRID_TO_WALL_DISTANCE/fYScale, GRID_TO_WALL_DISTANCE/fZScale);
711                 aM.scale( fXScale, fYScale, fZScale );
712                 E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape ));
713                 xShapeProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX )
714                     , uno::makeAny(BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aM)) );
715     	    }
716 		    catch( uno::Exception& e )
717 		    {
718                 ASSERT_EXCEPTION( e );
719             }
720 	    }
721     }
722 
723     m_aCurrentPosWithoutAxes = m_aAvailablePosIncludingAxes;
724     m_aCurrentSizeWithoutAxes = m_aAvailableSizeIncludingAxes;
725     adjustPosAndSize_3d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes );
726 }
727 
728 uno::Reference< drawing::XShapes > VDiagram::getCoordinateRegion()
729 {
730     return uno::Reference<drawing::XShapes>( m_xCoordinateRegionShape, uno::UNO_QUERY );
731 }
732 
733 ::basegfx::B2IRectangle VDiagram::getCurrentRectangle()
734 {
735     return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes);
736 }
737 
738 void VDiagram::reduceToMimimumSize()
739 {
740     if( m_xOuterGroupShape.is() )
741     {
742         awt::Size aMaxSize( m_aAvailableSizeIncludingAxes );
743         awt::Point aMaxPos( m_aAvailablePosIncludingAxes );
744 
745         sal_Int32 nNewWidth = aMaxSize.Width/3;
746         sal_Int32 nNewHeight = aMaxSize.Height/3;
747         awt::Size aNewSize( nNewWidth, nNewHeight );
748         awt::Point aNewPos( aMaxPos );
749         aNewPos.X += nNewWidth;
750         aNewPos.Y += nNewHeight;
751 
752         adjustPosAndSize( aNewPos, aNewSize );
753     }
754 }
755 
756 ::basegfx::B2IRectangle VDiagram::adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect )
757 {
758     awt::Point aNewPos( m_aCurrentPosWithoutAxes );
759     awt::Size aNewSize( m_aCurrentSizeWithoutAxes );
760 
761     ::basegfx::B2IRectangle rAvailableOuterRect(
762         BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) );
763 
764     sal_Int32 nDeltaWidth = static_cast<sal_Int32>(rAvailableOuterRect.getWidth() - rConsumedOuterRect.getWidth());
765     sal_Int32 nDeltaHeight = static_cast<sal_Int32>(rAvailableOuterRect.getHeight() - rConsumedOuterRect.getHeight());
766     if( (aNewSize.Width + nDeltaWidth) < rAvailableOuterRect.getWidth()/3 )
767         nDeltaWidth = static_cast<sal_Int32>(rAvailableOuterRect.getWidth()/3 - aNewSize.Width);
768     aNewSize.Width += nDeltaWidth;
769 
770     if( (aNewSize.Height + nDeltaHeight) < rAvailableOuterRect.getHeight()/3 )
771         nDeltaHeight = static_cast<sal_Int32>(rAvailableOuterRect.getHeight()/3 - aNewSize.Height);
772     aNewSize.Height += nDeltaHeight;
773 
774     sal_Int32 nDiffLeft = rConsumedOuterRect.getMinX() - rAvailableOuterRect.getMinX();
775     sal_Int32 nDiffRight = rAvailableOuterRect.getMaxX() - rConsumedOuterRect.getMaxX();
776     if( nDiffLeft >= 0 )
777         aNewPos.X -= nDiffLeft;
778     else if( nDiffRight >= 0 )
779     {
780         if( nDiffRight > -nDiffLeft )
781             aNewPos.X += abs(nDiffLeft);
782         else if( nDiffRight > abs(nDeltaWidth) )
783             aNewPos.X += nDiffRight;
784         else
785             aNewPos.X += abs(nDeltaWidth);
786     }
787 
788     sal_Int32 nDiffUp = rConsumedOuterRect.getMinY() - rAvailableOuterRect.getMinY();
789     sal_Int32 nDiffDown = rAvailableOuterRect.getMaxY() - rConsumedOuterRect.getMaxY();
790     if( nDiffUp >= 0 )
791         aNewPos.Y -= nDiffUp;
792     else if( nDiffDown >= 0 )
793     {
794         if( nDiffDown > -nDiffUp )
795             aNewPos.Y += abs(nDiffUp);
796         else if( nDiffDown > abs(nDeltaHeight) )
797             aNewPos.Y += nDiffDown;
798         else
799             aNewPos.Y += abs(nDeltaHeight);
800     }
801 
802     return adjustPosAndSize( aNewPos, aNewSize );
803 }
804 
805 //.............................................................................
806 } //namespace chart
807 //.............................................................................
808 
809