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 suppressed 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