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