xref: /AOO41X/main/xmloff/source/draw/shapeexport3.cxx (revision fe22d2cfc602815794415026f1317bd625db6f83)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_xmloff.hxx"
24 
25 #include <com/sun/star/drawing/HomogenMatrix.hpp>
26 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
27 #include <com/sun/star/drawing/ProjectionMode.hpp>
28 #include <com/sun/star/drawing/ShadeMode.hpp>
29 #include <com/sun/star/drawing/Direction3D.hpp>
30 #include <com/sun/star/drawing/Position3D.hpp>
31 #include <com/sun/star/drawing/CameraGeometry.hpp>
32 #include <com/sun/star/drawing/DoubleSequence.hpp>
33 #include <tools/gen.hxx>
34 #include <xmloff/shapeexport.hxx>
35 #include "sdpropls.hxx"
36 #include <tools/debug.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #include <xmloff/xmlexp.hxx>
39 #include <xmloff/xmluconv.hxx>
40 #include "xexptran.hxx"
41 #include <xmloff/xmltoken.hxx>
42 #include <basegfx/vector/b3dvector.hxx>
43 #include <xmloff/xmlnmspe.hxx>
44 #include <basegfx/polygon/b3dpolypolygon.hxx>
45 #include <basegfx/polygon/b3dpolypolygontools.hxx>
46 #include <basegfx/matrix/b3dhommatrix.hxx>
47 #include <basegfx/polygon/b2dpolypolygon.hxx>
48 #include <basegfx/polygon/b2dpolypolygontools.hxx>
49 
50 using ::rtl::OUString;
51 using ::rtl::OUStringBuffer;
52 
53 using namespace ::com::sun::star;
54 using namespace ::xmloff::token;
55 
56 
57 //////////////////////////////////////////////////////////////////////////////
58 
ImpExport3DSceneShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType,sal_Int32 nFeatures,awt::Point * pRefPoint)59 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
60 {
61     uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
62     if(xShapes.is() && xShapes->getCount())
63     {
64         uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
65         DBG_ASSERT( xPropSet.is(), "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
66         if( xPropSet.is() )
67         {
68             // Transformation
69             ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
70 
71             // 3d attributes
72             export3DSceneAttributes( xPropSet );
73 
74             // write 3DScene shape
75             sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
76             SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, sal_True);
77 
78             ImpExportDescription( xShape ); // #i68101#
79             ImpExportEvents( xShape );
80 
81             // write 3DSceneLights
82             export3DLamps( xPropSet );
83 
84             // #89764# if export of position is supressed for group shape,
85             // positions of contained objects should be written relative to
86             // the upper left edge of the group.
87             awt::Point aUpperLeft;
88 
89             if(!(nFeatures & SEF_EXPORT_POSITION))
90             {
91                 nFeatures |= SEF_EXPORT_POSITION;
92                 aUpperLeft = xShape->getPosition();
93                 pRefPoint = &aUpperLeft;
94             }
95 
96             // write members
97             exportShapes( xShapes, nFeatures, pRefPoint );
98         }
99     }
100 }
101 
102 //////////////////////////////////////////////////////////////////////////////
103 
ImpExport3DShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,sal_Int32,awt::Point *)104 void XMLShapeExport::ImpExport3DShape(
105     const uno::Reference< drawing::XShape >& xShape,
106     XmlShapeType eShapeType, sal_Int32 /* nFeatures = SEF_DEFAULT */, awt::Point* /*pRefPoint = NULL */)
107 {
108     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
109     if(xPropSet.is())
110     {
111         OUString aStr;
112         OUStringBuffer sStringBuffer;
113 
114         // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
115         uno::Any aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DTransformMatrix")));
116         drawing::HomogenMatrix xHomMat;
117         aAny >>= xHomMat;
118         SdXMLImExTransform3D aTransform;
119         aTransform.AddHomogenMatrix(xHomMat);
120         if(aTransform.NeedsAction())
121             mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
122 
123         switch(eShapeType)
124         {
125             case XmlShapeTypeDraw3DCubeObject:
126             {
127                 // minEdge
128                 aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DPosition")));
129                 drawing::Position3D aPosition3D;
130                 aAny >>= aPosition3D;
131                 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
132 
133                 // maxEdge
134                 aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSize")));
135                 drawing::Direction3D aDirection3D;
136                 aAny >>= aDirection3D;
137                 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
138 
139                 // transform maxEdge from distance to pos
140                 aDir3D = aPos3D + aDir3D;
141 
142                 // write minEdge
143                 if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
144                 {
145                     mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aPos3D);
146                     aStr = sStringBuffer.makeStringAndClear();
147                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
148                 }
149 
150                 // write maxEdge
151                 if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
152                 {
153                     mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aDir3D);
154                     aStr = sStringBuffer.makeStringAndClear();
155                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
156                 }
157 
158                 // write 3DCube shape
159                 // #123542# Do this *after* the attributes are added, else these will be lost since opening
160                 // the scope will clear the global attribute list at the exporter
161                 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, sal_True, sal_True);
162 
163                 break;
164             }
165             case XmlShapeTypeDraw3DSphereObject:
166             {
167                 // Center
168                 aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DPosition")));
169                 drawing::Position3D aPosition3D;
170                 aAny >>= aPosition3D;
171                 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
172 
173                 // Size
174                 aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSize")));
175                 drawing::Direction3D aDirection3D;
176                 aAny >>= aDirection3D;
177                 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
178 
179                 // write Center
180                 if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
181                 {
182                     mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aPos3D);
183                     aStr = sStringBuffer.makeStringAndClear();
184                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
185                 }
186 
187                 // write Size
188                 if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
189                 {
190                     mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aDir3D);
191                     aStr = sStringBuffer.makeStringAndClear();
192                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
193                 }
194 
195                 // write 3DSphere shape
196                 // #123542# Do this *after* the attributes are added, else these will be lost since opening
197                 // the scope will clear the global attribute list at the exporter
198                 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, sal_True, sal_True);
199 
200                 break;
201             }
202             case XmlShapeTypeDraw3DLatheObject:
203             case XmlShapeTypeDraw3DExtrudeObject:
204             {
205                 // write special 3DLathe/3DExtrude attributes, get 3D PolyPolygon as drawing::PolyPolygonShape3D
206                 aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DPolyPolygon3D")));
207                 drawing::PolyPolygonShape3D xPolyPolygon3D;
208                 aAny >>= xPolyPolygon3D;
209 
210                 // convert to 3D PolyPolygon
211                 const basegfx::B3DPolyPolygon aPolyPolygon3D(
212                     basegfx::tools::UnoPolyPolygonShape3DToB3DPolyPolygon(
213                         xPolyPolygon3D));
214 
215                 // convert to 2D PolyPolygon using identity 3D transformation (just grep X and Y)
216                 const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
217                 const basegfx::B2DPolyPolygon aPolyPolygon(
218                     basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(
219                         aPolyPolygon3D,
220                         aB3DHomMatrixFor2DConversion));
221 
222                 // get 2D range of it
223                 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
224 
225                 // export ViewBox
226                 SdXMLImExViewBox aViewBox(
227                     aPolyPolygonRange.getMinX(),
228                     aPolyPolygonRange.getMinY(),
229                     aPolyPolygonRange.getWidth(),
230                     aPolyPolygonRange.getHeight());
231 
232                 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
233 
234                 // prepare svg:d string
235                 const ::rtl::OUString aPolygonString(
236                     basegfx::tools::exportToSvgD(
237                         aPolyPolygon,
238                         true,           // bUseRelativeCoordinates
239                         false,          // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
240                         true));         // bHandleRelativeNextPointCompatible
241 
242                 // write point array
243                 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
244 
245                 if(eShapeType == XmlShapeTypeDraw3DLatheObject)
246                 {
247                     // write 3DLathe shape
248                     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, sal_True, sal_True);
249                 }
250                 else
251                 {
252                     // write 3DExtrude shape
253                     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, sal_True, sal_True);
254                 }
255                 break;
256             }
257             default:
258                 break;
259         }
260     }
261 }
262 
263 //////////////////////////////////////////////////////////////////////////////
264 
265 /** helper for chart that adds all attributes of a 3d scene element to the export */
export3DSceneAttributes(const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet> & xPropSet)266 void XMLShapeExport::export3DSceneAttributes( const com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet >& xPropSet )
267 {
268     OUString aStr;
269     OUStringBuffer sStringBuffer;
270 
271     // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
272     uno::Any aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DTransformMatrix")));
273     drawing::HomogenMatrix xHomMat;
274     aAny >>= xHomMat;
275     SdXMLImExTransform3D aTransform;
276     aTransform.AddHomogenMatrix(xHomMat);
277     if(aTransform.NeedsAction())
278         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
279 
280     // VRP, VPN, VUP
281     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DCameraGeometry")));
282     drawing::CameraGeometry aCamGeo;
283     aAny >>= aCamGeo;
284 
285     ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
286     if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
287     {
288         mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aVRP);
289         aStr = sStringBuffer.makeStringAndClear();
290         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
291     }
292 
293     ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
294     if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
295     {
296         mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aVPN);
297         aStr = sStringBuffer.makeStringAndClear();
298         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
299     }
300 
301     ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
302     if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
303     {
304         mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aVUP);
305         aStr = sStringBuffer.makeStringAndClear();
306         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
307     }
308 
309     // projection "D3DScenePerspective" drawing::ProjectionMode
310     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DScenePerspective")));
311     drawing::ProjectionMode xPrjMode;
312     aAny >>= xPrjMode;
313     if(xPrjMode == drawing::ProjectionMode_PARALLEL)
314         aStr = GetXMLToken(XML_PARALLEL);
315     else
316         aStr = GetXMLToken(XML_PERSPECTIVE);
317     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
318 
319     // distance
320     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneDistance")));
321     sal_Int32 nDistance = 0;
322     aAny >>= nDistance;
323     mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nDistance);
324     aStr = sStringBuffer.makeStringAndClear();
325     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
326 
327     // focalLength
328     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneFocalLength")));
329     sal_Int32 nFocalLength = 0;
330     aAny >>= nFocalLength;
331     mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nFocalLength);
332     aStr = sStringBuffer.makeStringAndClear();
333     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
334 
335     // shadowSlant
336     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneShadowSlant")));
337     sal_Int16 nShadowSlant = 0;
338     aAny >>= nShadowSlant;
339     mrExport.GetMM100UnitConverter().convertNumber(sStringBuffer, (sal_Int32)nShadowSlant);
340     aStr = sStringBuffer.makeStringAndClear();
341     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, aStr);
342 
343     // shadeMode
344     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneShadeMode")));
345     drawing::ShadeMode xShadeMode;
346     if(aAny >>= xShadeMode)
347     {
348         if(xShadeMode == drawing::ShadeMode_FLAT)
349             aStr = GetXMLToken(XML_FLAT);
350         else if(xShadeMode == drawing::ShadeMode_PHONG)
351             aStr = GetXMLToken(XML_PHONG);
352         else if(xShadeMode == drawing::ShadeMode_SMOOTH)
353             aStr = GetXMLToken(XML_GOURAUD);
354         else
355             aStr = GetXMLToken(XML_DRAFT);
356     }
357     else
358     {
359         // ShadeMode enum not there, write default
360         aStr = GetXMLToken(XML_GOURAUD);
361     }
362     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
363 
364     // ambientColor
365     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneAmbientColor")));
366     sal_Int32 aColTemp = 0;
367     Color aAmbientColor;
368     aAny >>= aColTemp; aAmbientColor.SetColor(aColTemp);
369     mrExport.GetMM100UnitConverter().convertColor(sStringBuffer, aAmbientColor);
370     aStr = sStringBuffer.makeStringAndClear();
371     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
372 
373     // lightingMode
374     aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("D3DSceneTwoSidedLighting")));
375     sal_Bool bTwoSidedLighting = false;
376     aAny >>= bTwoSidedLighting;
377     mrExport.GetMM100UnitConverter().convertBool(sStringBuffer, bTwoSidedLighting);
378     aStr = sStringBuffer.makeStringAndClear();
379     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
380 }
381 
382 /** helper for chart that exports all lamps from the propertyset */
export3DLamps(const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet> & xPropSet)383 void XMLShapeExport::export3DLamps( const com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet >& xPropSet )
384 {
385     // write lamps 1..8 as content
386     OUString aStr;
387     OUStringBuffer sStringBuffer;
388 
389     const OUString aColorPropName(RTL_CONSTASCII_USTRINGPARAM("D3DSceneLightColor") );
390     const OUString aDirectionPropName(RTL_CONSTASCII_USTRINGPARAM("D3DSceneLightDirection") );
391     const OUString aLightOnPropName(RTL_CONSTASCII_USTRINGPARAM("D3DSceneLightOn") );
392 
393     OUString aPropName;
394     OUString aIndexStr;
395     sal_Int32 aColTemp = 0;
396     Color aLightColor;
397     ::basegfx::B3DVector aLightDirection;
398     drawing::Direction3D xLightDir;
399     sal_Bool bLightOnOff = false;
400     for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
401     {
402         aIndexStr = OUString::valueOf( nLamp );
403 
404         // lightcolor
405         aPropName = aColorPropName;
406         aPropName += aIndexStr;
407         xPropSet->getPropertyValue( aPropName ) >>= aColTemp;
408         aLightColor.SetColor(aColTemp);
409         mrExport.GetMM100UnitConverter().convertColor(sStringBuffer, aLightColor);
410         aStr = sStringBuffer.makeStringAndClear();
411         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
412 
413         // lightdirection
414         aPropName = aDirectionPropName;
415         aPropName += aIndexStr;
416         xPropSet->getPropertyValue(aPropName) >>= xLightDir;
417         aLightDirection = ::basegfx::B3DVector(xLightDir.DirectionX, xLightDir.DirectionY, xLightDir.DirectionZ);
418         mrExport.GetMM100UnitConverter().convertB3DVector(sStringBuffer, aLightDirection);
419         aStr = sStringBuffer.makeStringAndClear();
420         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
421 
422         // lighton
423         aPropName = aLightOnPropName;
424         aPropName += aIndexStr;
425         xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
426         mrExport.GetMM100UnitConverter().convertBool(sStringBuffer, bLightOnOff);
427         aStr = sStringBuffer.makeStringAndClear();
428         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
429 
430         // specular
431         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
432             nLamp == 1 ? XML_TRUE : XML_FALSE);
433 
434         // write light entry
435         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, sal_True, sal_True);
436     }
437 }
438 
439 //////////////////////////////////////////////////////////////////////////////
440