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