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_svx.hxx"
26 
27 #include <svx/sdr/contact/viewcontactofe3dpolygon.hxx>
28 #include <svx/polygn3d.hxx>
29 #include <drawinglayer/primitive3d/sdrpolypolygonprimitive3d.hxx>
30 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
31 #include <svx/sdr/primitive3d/sdrattributecreator3d.hxx>
32 #include <basegfx/polygon/b3dpolygon.hxx>
33 #include <basegfx/polygon/b3dpolypolygontools.hxx>
34 
35 //////////////////////////////////////////////////////////////////////////////
36 
37 namespace sdr
38 {
39 	namespace contact
40 	{
ViewContactOfE3dPolygon(E3dPolygonObj & rPolygon)41 		ViewContactOfE3dPolygon::ViewContactOfE3dPolygon(E3dPolygonObj& rPolygon)
42 		:	ViewContactOfE3d(rPolygon)
43 		{
44 		}
45 
~ViewContactOfE3dPolygon()46 		ViewContactOfE3dPolygon::~ViewContactOfE3dPolygon()
47 		{
48 		}
49 
createViewIndependentPrimitive3DSequence() const50 		drawinglayer::primitive3d::Primitive3DSequence ViewContactOfE3dPolygon::createViewIndependentPrimitive3DSequence() const
51 		{
52 			drawinglayer::primitive3d::Primitive3DSequence xRetval;
53 			const SfxItemSet& rItemSet = GetE3dPolygonObj().GetMergedItemSet();
54 			const bool bSuppressFill(GetE3dPolygonObj().GetLineOnly());
55 			const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
56 				drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, bSuppressFill));
57 
58 			// get extrude geometry
59 			basegfx::B3DPolyPolygon aPolyPolygon3D(GetE3dPolygonObj().GetPolyPolygon3D());
60 			const basegfx::B3DPolyPolygon aPolyNormals3D(GetE3dPolygonObj().GetPolyNormals3D());
61 			const basegfx::B2DPolyPolygon aPolyTexture2D(GetE3dPolygonObj().GetPolyTexture2D());
62             const bool bNormals(aPolyNormals3D.count() && aPolyNormals3D.count() == aPolyPolygon3D.count());
63             const bool bTexture(aPolyTexture2D.count() && aPolyTexture2D.count() == aPolyPolygon3D.count());
64 
65 			if(bNormals || bTexture)
66 			{
67 				for(sal_uInt32 a(0L); a < aPolyPolygon3D.count(); a++)
68 				{
69 					basegfx::B3DPolygon aCandidate3D(aPolyPolygon3D.getB3DPolygon(a));
70 					basegfx::B3DPolygon aNormals3D;
71 					basegfx::B2DPolygon aTexture2D;
72 
73 					if(bNormals)
74 					{
75 						aNormals3D = aPolyNormals3D.getB3DPolygon(a);
76 					}
77 
78 					if(bTexture)
79 					{
80 						aTexture2D = aPolyTexture2D.getB2DPolygon(a);
81 					}
82 
83 					for(sal_uInt32 b(0L); b < aCandidate3D.count(); b++)
84 					{
85                         if(bNormals)
86                         {
87                             sal_uInt32 nNormalCount = aNormals3D.count();
88                             if( b < nNormalCount )
89                                 aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(b));
90                             else if( nNormalCount > 0 )
91                                 aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(0));
92                         }
93                         if(bTexture)
94                         {
95                             sal_uInt32 nTextureCount = aTexture2D.count();
96                             if( b < nTextureCount )
97                                 aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(b));
98                             else if( nTextureCount > 0 )
99                                 aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(0));
100                         }
101 					}
102 
103 					aPolyPolygon3D.setB3DPolygon(a, aCandidate3D);
104 				}
105 			}
106 
107 			// get 3D Object Attributes
108 			drawinglayer::attribute::Sdr3DObjectAttribute* pSdr3DObjectAttribute = drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet);
109 
110 			// calculate texture size
111 			basegfx::B2DVector aTextureSize(1.0, 1.0);
112 
113 			if(bTexture)
114 			{
115                 // #i98314#
116                 // create texture size from object's size
117                 const basegfx::B3DRange aObjectRange(basegfx::tools::getRange(aPolyPolygon3D));
118 
119                 double fWidth(0.0);
120                 double fHeight(0.0);
121 
122                 // this is a polygon object, so Width/Height and/or Depth may be zero (e.g. left
123                 // wall of chart). Take this into account
124                 if(basegfx::fTools::equalZero(aObjectRange.getWidth()))
125                 {
126                     // width is zero, use height and depth
127                     fWidth = aObjectRange.getHeight();
128                     fHeight = aObjectRange.getDepth();
129                 }
130                 else if(basegfx::fTools::equalZero(aObjectRange.getHeight()))
131                 {
132                     // height is zero, use width and depth
133                     fWidth = aObjectRange.getWidth();
134                     fHeight = aObjectRange.getDepth();
135                 }
136                 else
137                 {
138                     // use width and height
139                     fWidth = aObjectRange.getWidth();
140                     fHeight = aObjectRange.getHeight();
141                 }
142 
143                 if(basegfx::fTools::lessOrEqual(fWidth, 0.0) ||basegfx::fTools::lessOrEqual(fHeight, 0.0))
144                 {
145                     // no texture; fallback to very small size
146 				    aTextureSize.setX(0.01);
147 				    aTextureSize.setY(0.01);
148                 }
149                 else
150                 {
151 				    aTextureSize.setX(fWidth);
152 				    aTextureSize.setY(fHeight);
153                 }
154 			}
155 
156 			// #i98295#
157 			// unfortunately, this SdrObject type which allows a free 3d geometry definition was defined
158 			// wrong topologically in relation to it's plane normal and 3D visibility when it was invented
159 			// a long time ago. Since the API allows creation of this SDrObject type, it is not possible to
160 			// simply change this definition. Only the chart should use it, and at least this object type
161 			// only exists at Runtime (is not saved and/or loaded in any FileFormat). Still someone external
162 			// may have used it in it's API. To not risk wrong 3D lightings, i have to switch the orientation
163 			// of the polygon here
164 			aPolyPolygon3D.flip();
165 
166 			// create primitive and add
167 			const basegfx::B3DHomMatrix aWorldTransform;
168 			const drawinglayer::primitive3d::Primitive3DReference xReference(
169 				new drawinglayer::primitive3d::SdrPolyPolygonPrimitive3D(
170 					aPolyPolygon3D, aWorldTransform, aTextureSize, aAttribute, *pSdr3DObjectAttribute));
171             xRetval = drawinglayer::primitive3d::Primitive3DSequence(&xReference, 1);
172 
173 			// delete 3D Object Attributes
174 			delete pSdr3DObjectAttribute;
175 
176 			return xRetval;
177 		}
178 	} // end of namespace contact
179 } // end of namespace sdr
180 
181 //////////////////////////////////////////////////////////////////////////////
182 // eof
183