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_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive3d/sdrsphereprimitive3d.hxx>
28 #include <basegfx/polygon/b3dpolypolygontools.hxx>
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <basegfx/polygon/b3dpolygon.hxx>
31 #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx>
32 #include <basegfx/tools/canvastools.hxx>
33 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
34 #include <drawinglayer/attribute/sdrfillattribute.hxx>
35 #include <drawinglayer/attribute/sdrlineattribute.hxx>
36 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 using namespace com::sun::star;
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 namespace drawinglayer
45 {
46 	namespace primitive3d
47 	{
create3DDecomposition(const geometry::ViewInformation3D &) const48 		Primitive3DSequence SdrSpherePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
49 		{
50 			Primitive3DSequence aRetval;
51 			const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
52 			const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind()
53 				|| ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind());
54 
55 			// create unit geometry
56 			basegfx::B3DPolyPolygon aFill(basegfx::tools::createSphereFillPolyPolygonFromB3DRange(aUnitRange,
57 				getHorizontalSegments(), getVerticalSegments(), bCreateNormals));
58 
59 			// normal inversion
60 			if(!getSdrLFSAttribute().getFill().isDefault()
61 				&& bCreateNormals
62 				&& getSdr3DObjectAttribute().getNormalsInvert()
63 				&& aFill.areNormalsUsed())
64 			{
65 				// invert normals
66 				aFill = basegfx::tools::invertNormals(aFill);
67 			}
68 
69 			// texture coordinates
70 			if(!getSdrLFSAttribute().getFill().isDefault())
71 			{
72 				// handle texture coordinates X
73 				const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX());
74 				const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX());
75 				const bool bSphereX(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX());
76 
77 				// handle texture coordinates Y
78 				const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY());
79 				const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY());
80 				const bool bSphereY(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY());
81 
82 				if(bParallelX || bParallelY)
83 				{
84 					// apply parallel texture coordinates in X and/or Y
85 					const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill));
86 					aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY);
87 				}
88 
89 				if(bSphereX || bObjectSpecificX || bSphereY || bObjectSpecificY)
90 				{
91 					double fRelativeAngle(0.0);
92 
93 					if(bObjectSpecificX)
94 					{
95 						// Since the texture coordinates are (for historical reasons)
96 						// different from forced to sphere texture coordinates,
97 						// create a old version from it by rotating to old state before applying
98 						// the texture coordinates to emulate old behaviour
99 						fRelativeAngle = F_2PI * ((double)((getHorizontalSegments() >> 1L)  - 1L) / (double)getHorizontalSegments());
100 						basegfx::B3DHomMatrix aRot;
101 						aRot.rotate(0.0, fRelativeAngle, 0.0);
102 						aFill.transform(aRot);
103 					}
104 
105 					// apply spherical texture coordinates in X and/or Y
106 					const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill));
107 					const basegfx::B3DPoint aCenter(aRange.getCenter());
108 					aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter,
109 						bSphereX || bObjectSpecificX, bSphereY || bObjectSpecificY);
110 
111 					if(bObjectSpecificX)
112 					{
113 						// rotate back again
114 						basegfx::B3DHomMatrix aRot;
115 						aRot.rotate(0.0, -fRelativeAngle, 0.0);
116 						aFill.transform(aRot);
117 					}
118 				}
119 
120 				// transform texture coordinates to texture size
121 				basegfx::B2DHomMatrix aTexMatrix;
122 				aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY());
123 				aFill.transformTextureCoordiantes(aTexMatrix);
124 			}
125 
126 			// build vector of PolyPolygons
127 			::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector;
128 
129 			for(sal_uInt32 a(0L); a < aFill.count(); a++)
130 			{
131 				a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a)));
132 			}
133 
134 			if(!getSdrLFSAttribute().getFill().isDefault())
135 			{
136 				// add fill
137 				aRetval = create3DPolyPolygonFillPrimitives(
138 					a3DPolyPolygonVector,
139 					getTransform(),
140 					getTextureSize(),
141 					getSdr3DObjectAttribute(),
142 					getSdrLFSAttribute().getFill(),
143 					getSdrLFSAttribute().getFillFloatTransGradient());
144 			}
145 			else
146 			{
147 				// create simplified 3d hit test geometry
148                 aRetval = createHiddenGeometryPrimitives3D(
149 			        a3DPolyPolygonVector,
150 			        getTransform(),
151 			        getTextureSize(),
152 			        getSdr3DObjectAttribute());
153 			}
154 
155 			// add line
156 			if(!getSdrLFSAttribute().getLine().isDefault())
157 			{
158 				basegfx::B3DPolyPolygon aSphere(basegfx::tools::createSpherePolyPolygonFromB3DRange(aUnitRange, getHorizontalSegments(), getVerticalSegments()));
159 				const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(
160                     aSphere, getTransform(), getSdrLFSAttribute().getLine()));
161 				appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines);
162 			}
163 
164 			// add shadow
165 			if(!getSdrLFSAttribute().getShadow().isDefault()
166                 && aRetval.hasElements())
167 			{
168 				const Primitive3DSequence aShadow(createShadowPrimitive3D(
169                     aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
170 				appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow);
171 			}
172 
173 			return aRetval;
174 		}
175 
SdrSpherePrimitive3D(const basegfx::B3DHomMatrix & rTransform,const basegfx::B2DVector & rTextureSize,const attribute::SdrLineFillShadowAttribute3D & rSdrLFSAttribute,const attribute::Sdr3DObjectAttribute & rSdr3DObjectAttribute,sal_uInt32 nHorizontalSegments,sal_uInt32 nVerticalSegments)176 		SdrSpherePrimitive3D::SdrSpherePrimitive3D(
177 			const basegfx::B3DHomMatrix& rTransform,
178 			const basegfx::B2DVector& rTextureSize,
179 			const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute,
180 			const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute,
181 			sal_uInt32 nHorizontalSegments,
182 			sal_uInt32 nVerticalSegments)
183 		:	SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute),
184 			mnHorizontalSegments(nHorizontalSegments),
185 			mnVerticalSegments(nVerticalSegments)
186 		{
187 		}
188 
operator ==(const BasePrimitive3D & rPrimitive) const189 		bool SdrSpherePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
190 		{
191 			if(SdrPrimitive3D::operator==(rPrimitive))
192 			{
193 				const SdrSpherePrimitive3D& rCompare = static_cast< const SdrSpherePrimitive3D& >(rPrimitive);
194 
195 				return (getHorizontalSegments() == rCompare.getHorizontalSegments()
196 					&& getVerticalSegments() == rCompare.getVerticalSegments());
197 			}
198 
199 			return false;
200 		}
201 
getB3DRange(const geometry::ViewInformation3D &) const202 		basegfx::B3DRange SdrSpherePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const
203 		{
204 			// use defaut from sdrPrimitive3D which uses transformation expanded by line width/2
205 			// The parent implementation which uses the ranges of the decomposition would be more
206 			// corrcet, but for historical reasons it is necessary to do the old method: To get
207 			// the range of the non-transformed geometry and transform it then. This leads to different
208 			// ranges where the new method is more correct, but the need to keep the old behaviour
209 			// has priority here.
210 			return getStandard3DRange();
211 		}
212 
213 		// provide unique ID
214 		ImplPrimitrive3DIDBlock(SdrSpherePrimitive3D, PRIMITIVE3D_ID_SDRSPHEREPRIMITIVE3D)
215 
216 	} // end of namespace primitive3d
217 } // end of namespace drawinglayer
218 
219 //////////////////////////////////////////////////////////////////////////////
220 // eof
221