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 "VCartesianGrid.hxx"
21 #include "Tickmarks.hxx"
22 #include <PlottingPositionHelper.hxx>
23 #include <ShapeFactory.hxx>
24 #include <ObjectIdentifier.hxx>
25 #include <CommonConverters.hxx>
26 #include <AxisHelper.hxx>
27 #include <VLineProperties.hxx>
28 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
29 #include <com/sun/star/drawing/LineStyle.hpp>
30 #include <com/sun/star/chart2/XTransformation.hpp>
31 
32 #include <memory>
33 #include <vector>
34 
35 namespace chart
36 {
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::chart2;
39 using ::com::sun::star::uno::Reference;
40 using ::com::sun::star::uno::Sequence;
41 
42 namespace {
43 
44 struct GridLinePoints
45 {
46     Sequence< double > P0;
47     Sequence< double > P1;
48     Sequence< double > P2;
49 
50     GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex
51         , CuboidPlanePosition eLeftWallPos=CuboidPlanePosition_Left
52         , CuboidPlanePosition eBackWallPos=CuboidPlanePosition_Back
53         , CuboidPlanePosition eBottomPos=CuboidPlanePosition_Bottom );
54     void update( double fScaledTickValue );
55 
56     sal_Int32 m_nDimensionIndex;
57 };
58 
59 }
60 
GridLinePoints(const PlottingPositionHelper * pPosHelper,sal_Int32 nDimensionIndex,CuboidPlanePosition eLeftWallPos,CuboidPlanePosition eBackWallPos,CuboidPlanePosition eBottomPos)61 GridLinePoints::GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex
62                 , CuboidPlanePosition eLeftWallPos
63                 , CuboidPlanePosition eBackWallPos
64                 , CuboidPlanePosition eBottomPos )
65                 : P0(3)
66                 , P1(3)
67                 , P2(3)
68                 , m_nDimensionIndex(nDimensionIndex)
69 {
70     double MinX = pPosHelper->getLogicMinX();
71     double MinY = pPosHelper->getLogicMinY();
72     double MinZ = pPosHelper->getLogicMinZ();
73     double MaxX = pPosHelper->getLogicMaxX();
74     double MaxY = pPosHelper->getLogicMaxY();
75     double MaxZ = pPosHelper->getLogicMaxZ();
76 
77     pPosHelper->doLogicScaling( &MinX,&MinY,&MinZ );
78     pPosHelper->doLogicScaling( &MaxX,&MaxY,&MaxZ );
79 
80     if(!pPosHelper->isMathematicalOrientationX())
81     {
82         double fHelp = MinX;
83         MinX = MaxX;
84         MaxX = fHelp;
85     }
86     if(!pPosHelper->isMathematicalOrientationY())
87     {
88         double fHelp = MinY;
89         MinY = MaxY;
90         MaxY = fHelp;
91     }
92     if(pPosHelper->isMathematicalOrientationZ())//z axis in draw is reverse to mathematical
93     {
94         double fHelp = MinZ;
95         MinZ = MaxZ;
96         MaxZ = fHelp;
97     }
98     bool bSwapXY = pPosHelper->isSwapXAndY();
99 
100     //P0: point on 'back' wall, not on 'left' wall
101     //P1: point on both walls
102     //P2: point on 'left' wall not on 'back' wall
103 
104     P0[0]=P1[0]=P2[0]= (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MinX : MaxX;
105     P0[1]=P1[1]=P2[1]= (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MinY : MaxY;
106     P0[2]=P1[2]=P2[2]= (eBackWallPos == CuboidPlanePosition_Back) ? MinZ : MaxZ;
107 
108     if(m_nDimensionIndex==0)
109     {
110         P0[1]= (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MaxY : MinY;
111         P2[2]= (eBackWallPos == CuboidPlanePosition_Back) ? MaxZ : MinZ;
112         if( eBottomPos != CuboidPlanePosition_Bottom && !bSwapXY )
113             P2=P1;
114     }
115     else if(m_nDimensionIndex==1)
116     {
117         P0[0]= (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MaxX : MinX;
118         P2[2]= (eBackWallPos == CuboidPlanePosition_Back) ? MaxZ : MinZ;
119         if( eBottomPos != CuboidPlanePosition_Bottom && bSwapXY )
120             P2=P1;
121     }
122     else if(m_nDimensionIndex==2)
123     {
124         P0[0]= (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MaxX : MinX;
125         P2[1]= (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MaxY : MinY;
126         if( eBottomPos != CuboidPlanePosition_Bottom )
127         {
128             if( !bSwapXY )
129                 P0=P1;
130             else
131                 P2=P1;
132         }
133     }
134 }
135 
update(double fScaledTickValue)136 void GridLinePoints::update( double fScaledTickValue )
137 {
138     P0[m_nDimensionIndex] = P1[m_nDimensionIndex] = P2[m_nDimensionIndex] = fScaledTickValue;
139 }
140 
addLine2D(drawing::PointSequenceSequence & rPoints,sal_Int32 nIndex,const GridLinePoints & rScaledLogicPoints,const Reference<XTransformation> & xTransformation)141 static void addLine2D( drawing::PointSequenceSequence& rPoints, sal_Int32 nIndex
142              , const GridLinePoints& rScaledLogicPoints
143              , const Reference< XTransformation > & xTransformation
144               )
145 {
146     drawing::Position3D aPA = SequenceToPosition3D( xTransformation->transform( rScaledLogicPoints.P0 ) );
147     drawing::Position3D aPB = SequenceToPosition3D( xTransformation->transform( rScaledLogicPoints.P1 ) );
148 
149     rPoints[nIndex].realloc(2);
150     rPoints[nIndex][0].X = static_cast<sal_Int32>(aPA.PositionX);
151     rPoints[nIndex][0].Y = static_cast<sal_Int32>(aPA.PositionY);
152     rPoints[nIndex][1].X = static_cast<sal_Int32>(aPB.PositionX);
153     rPoints[nIndex][1].Y = static_cast<sal_Int32>(aPB.PositionY);
154 }
155 
addLine3D(drawing::PolyPolygonShape3D & rPoints,sal_Int32 nIndex,const GridLinePoints & rBasePoints,const Reference<XTransformation> & xTransformation)156 static void addLine3D( drawing::PolyPolygonShape3D& rPoints, sal_Int32 nIndex
157             , const GridLinePoints& rBasePoints
158             , const Reference< XTransformation > & xTransformation )
159 {
160     drawing::Position3D aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P0 ) );
161     AddPointToPoly( rPoints, aPoint, nIndex );
162     aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P1 ) );
163     AddPointToPoly( rPoints, aPoint, nIndex );
164     aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P2 ) );
165     AddPointToPoly( rPoints, aPoint, nIndex );
166 }
167 
VCartesianGrid(sal_Int32 nDimensionIndex,sal_Int32 nDimensionCount,const Sequence<Reference<beans::XPropertySet>> & rGridPropertiesList)168 VCartesianGrid::VCartesianGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount
169                                , const Sequence< Reference< beans::XPropertySet > > & rGridPropertiesList )
170             : VAxisOrGridBase( nDimensionIndex, nDimensionCount )
171             , m_aGridPropertiesList( rGridPropertiesList )
172 {
173     m_pPosHelper = new PlottingPositionHelper();
174 }
175 
~VCartesianGrid()176 VCartesianGrid::~VCartesianGrid()
177 {
178     delete m_pPosHelper;
179     m_pPosHelper = nullptr;
180 }
181 
fillLinePropertiesFromGridModel(std::vector<VLineProperties> & rLinePropertiesList,const Sequence<Reference<beans::XPropertySet>> & rGridPropertiesList)182 void VCartesianGrid::fillLinePropertiesFromGridModel( std::vector<VLineProperties>& rLinePropertiesList
183                                      , const Sequence< Reference< beans::XPropertySet > > & rGridPropertiesList )
184 {
185     rLinePropertiesList.clear();
186     if( !rGridPropertiesList.hasElements() )
187         return;
188 
189     VLineProperties aLineProperties;
190     for( const auto & rxPropSet : rGridPropertiesList )
191     {
192         if(!AxisHelper::isGridVisible( rxPropSet ))
193             aLineProperties.LineStyle <<= drawing::LineStyle_NONE;
194         else
195             aLineProperties.initFromPropertySet( rxPropSet );
196         rLinePropertiesList.push_back(aLineProperties);
197     }
198 };
199 
createShapes()200 void VCartesianGrid::createShapes()
201 {
202     if(!m_aGridPropertiesList.hasElements())
203         return;
204     //somehow equal to axis tickmarks
205 
206     //create named group shape
207     Reference< drawing::XShapes > xGroupShape_Shapes(
208         createGroupShape( m_xLogicTarget, m_aCID ) );
209 
210     if(!xGroupShape_Shapes.is())
211         return;
212 
213     std::vector<VLineProperties> aLinePropertiesList;
214     fillLinePropertiesFromGridModel( aLinePropertiesList, m_aGridPropertiesList );
215 
216     //create all scaled tickmark values
217     std::unique_ptr< TickFactory > apTickFactory( createTickFactory() );
218     TickFactory& aTickFactory = *apTickFactory;
219     TickInfoArraysType aAllTickInfos;
220     aTickFactory.getAllTicks( aAllTickInfos );
221 
222     //create tick mark line shapes
223 
224     if(aAllTickInfos.empty())//no tickmarks at all
225         return;
226 
227     TickInfoArraysType::iterator aDepthIter             = aAllTickInfos.begin();
228     const TickInfoArraysType::const_iterator aDepthEnd  = aAllTickInfos.end();
229 
230     sal_Int32 nLinePropertiesCount = aLinePropertiesList.size();
231     for( sal_Int32 nDepth=0
232         ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount
233         ; ++aDepthIter, nDepth++ )
234     {
235         if( !aLinePropertiesList[nDepth].isLineVisible() )
236             continue;
237 
238         Reference< drawing::XShapes > xTarget( xGroupShape_Shapes );
239         if( nDepth > 0 )
240         {
241             xTarget.set( createGroupShape( m_xLogicTarget
242                 , ObjectIdentifier::addChildParticle( m_aCID, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_SUBGRID, nDepth-1 ) )
243                 ) );
244             if(!xTarget.is())
245                 xTarget.set( xGroupShape_Shapes );
246         }
247 
248         if(m_nDimension==2)
249         {
250 
251             GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex );
252 
253             sal_Int32 nPointCount = (*aDepthIter).size();
254             drawing::PointSequenceSequence aPoints(nPointCount);
255 
256             sal_Int32 nRealPointCount = 0;
257             for (auto const& tick : *aDepthIter)
258             {
259                 if( !tick.bPaintIt )
260                     continue;
261                 aGridLinePoints.update( tick.fScaledTickValue );
262                 addLine2D( aPoints, nRealPointCount, aGridLinePoints, m_pPosHelper->getTransformationScaledLogicToScene() );
263                 nRealPointCount++;
264             }
265             aPoints.realloc(nRealPointCount);
266             m_pShapeFactory->createLine2D( xTarget, aPoints, &aLinePropertiesList[nDepth] );
267 
268             //prepare polygon for handle shape:
269             drawing::PointSequenceSequence aHandlesPoints(1);
270             sal_Int32 nOldHandleCount = aHandlesPoints[0].getLength();
271             aHandlesPoints[0].realloc(nOldHandleCount+nRealPointCount);
272             for( sal_Int32 nN = 0; nN<nRealPointCount; nN++)
273                 aHandlesPoints[0][nOldHandleCount+nN] = aPoints[nN][1];
274 
275             //create handle shape:
276             VLineProperties aHandleLineProperties;
277             aHandleLineProperties.LineStyle    <<= drawing::LineStyle_NONE;
278             Reference< drawing::XShape > xHandleShape =
279                 m_pShapeFactory->createLine2D( xTarget, aHandlesPoints, &aHandleLineProperties );
280             ::chart::ShapeFactory::setShapeName( xHandleShape, "HandlesOnly" );
281         }
282         else //if(2!=m_nDimension)
283         {
284             GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex, m_eLeftWallPos, m_eBackWallPos, m_eBottomPos );
285 
286             sal_Int32 nPointCount = (*aDepthIter).size();
287             drawing::PolyPolygonShape3D aPoints;
288             aPoints.SequenceX.realloc(nPointCount);
289             aPoints.SequenceY.realloc(nPointCount);
290             aPoints.SequenceZ.realloc(nPointCount);
291 
292             sal_Int32 nRealPointCount = 0;
293             sal_Int32 nPolyIndex = 0;
294             for (auto const& tick : *aDepthIter)
295             {
296                 if( !tick.bPaintIt )
297                 {
298                     ++nPolyIndex;
299                     continue;
300                 }
301 
302                 aGridLinePoints.update( tick.fScaledTickValue );
303                 addLine3D( aPoints, nPolyIndex, aGridLinePoints, m_pPosHelper->getTransformationScaledLogicToScene() );
304                 nRealPointCount+=3;
305                 ++nPolyIndex;
306             }
307             aPoints.SequenceX.realloc(nRealPointCount);
308             aPoints.SequenceY.realloc(nRealPointCount);
309             aPoints.SequenceZ.realloc(nRealPointCount);
310             m_pShapeFactory->createLine3D( xTarget, aPoints, aLinePropertiesList[nDepth] );
311         }
312     }
313 }
314 
315 } //namespace chart
316 
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
318