1*09dbbe93SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*09dbbe93SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*09dbbe93SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*09dbbe93SAndrew Rist  * distributed with this work for additional information
6*09dbbe93SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*09dbbe93SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*09dbbe93SAndrew Rist  * "License"); you may not use this file except in compliance
9*09dbbe93SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*09dbbe93SAndrew Rist  *
11*09dbbe93SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*09dbbe93SAndrew Rist  *
13*09dbbe93SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*09dbbe93SAndrew Rist  * software distributed under the License is distributed on an
15*09dbbe93SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*09dbbe93SAndrew Rist  * KIND, either express or implied.  See the License for the
17*09dbbe93SAndrew Rist  * specific language governing permissions and limitations
18*09dbbe93SAndrew Rist  * under the License.
19*09dbbe93SAndrew Rist  *
20*09dbbe93SAndrew Rist  *************************************************************/
21*09dbbe93SAndrew Rist 
22*09dbbe93SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <rtl/instance.hxx>
28cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx>
29cdf0e10cSrcweir #include <hommatrixtemplate.hxx>
30cdf0e10cSrcweir #include <basegfx/vector/b3dvector.hxx>
31cdf0e10cSrcweir 
32cdf0e10cSrcweir namespace basegfx
33cdf0e10cSrcweir {
34cdf0e10cSrcweir     class Impl3DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 4 >
35cdf0e10cSrcweir     {
36cdf0e10cSrcweir     };
37cdf0e10cSrcweir 
38cdf0e10cSrcweir     namespace { struct IdentityMatrix : public rtl::Static< B3DHomMatrix::ImplType,
39cdf0e10cSrcweir                                                             IdentityMatrix > {}; }
40cdf0e10cSrcweir 
B3DHomMatrix()41cdf0e10cSrcweir 	B3DHomMatrix::B3DHomMatrix() :
42cdf0e10cSrcweir         mpImpl( IdentityMatrix::get() ) // use common identity matrix
43cdf0e10cSrcweir 	{
44cdf0e10cSrcweir 	}
45cdf0e10cSrcweir 
B3DHomMatrix(const B3DHomMatrix & rMat)46cdf0e10cSrcweir 	B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix& rMat) :
47cdf0e10cSrcweir         mpImpl(rMat.mpImpl)
48cdf0e10cSrcweir 	{
49cdf0e10cSrcweir 	}
50cdf0e10cSrcweir 
~B3DHomMatrix()51cdf0e10cSrcweir 	B3DHomMatrix::~B3DHomMatrix()
52cdf0e10cSrcweir 	{
53cdf0e10cSrcweir 	}
54cdf0e10cSrcweir 
operator =(const B3DHomMatrix & rMat)55cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator=(const B3DHomMatrix& rMat)
56cdf0e10cSrcweir 	{
57cdf0e10cSrcweir         mpImpl = rMat.mpImpl;
58cdf0e10cSrcweir 		return *this;
59cdf0e10cSrcweir 	}
60cdf0e10cSrcweir 
makeUnique()61cdf0e10cSrcweir     void B3DHomMatrix::makeUnique()
62cdf0e10cSrcweir     {
63cdf0e10cSrcweir         mpImpl.make_unique();
64cdf0e10cSrcweir     }
65cdf0e10cSrcweir 
get(sal_uInt16 nRow,sal_uInt16 nColumn) const66cdf0e10cSrcweir 	double B3DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
67cdf0e10cSrcweir 	{
68cdf0e10cSrcweir 		return mpImpl->get(nRow, nColumn);
69cdf0e10cSrcweir 	}
70cdf0e10cSrcweir 
set(sal_uInt16 nRow,sal_uInt16 nColumn,double fValue)71cdf0e10cSrcweir 	void B3DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
72cdf0e10cSrcweir 	{
73cdf0e10cSrcweir 		mpImpl->set(nRow, nColumn, fValue);
74cdf0e10cSrcweir 	}
75cdf0e10cSrcweir 
isLastLineDefault() const76cdf0e10cSrcweir 	bool B3DHomMatrix::isLastLineDefault() const
77cdf0e10cSrcweir 	{
78cdf0e10cSrcweir 		return mpImpl->isLastLineDefault();
79cdf0e10cSrcweir 	}
80cdf0e10cSrcweir 
isIdentity() const81cdf0e10cSrcweir 	bool B3DHomMatrix::isIdentity() const
82cdf0e10cSrcweir 	{
83cdf0e10cSrcweir 		if(mpImpl.same_object(IdentityMatrix::get()))
84cdf0e10cSrcweir 			return true;
85cdf0e10cSrcweir 
86cdf0e10cSrcweir 		return mpImpl->isIdentity();
87cdf0e10cSrcweir 	}
88cdf0e10cSrcweir 
identity()89cdf0e10cSrcweir 	void B3DHomMatrix::identity()
90cdf0e10cSrcweir 	{
91cdf0e10cSrcweir         mpImpl = IdentityMatrix::get();
92cdf0e10cSrcweir 	}
93cdf0e10cSrcweir 
isInvertible() const94cdf0e10cSrcweir 	bool B3DHomMatrix::isInvertible() const
95cdf0e10cSrcweir 	{
96cdf0e10cSrcweir 		return mpImpl->isInvertible();
97cdf0e10cSrcweir 	}
98cdf0e10cSrcweir 
invert()99cdf0e10cSrcweir 	bool B3DHomMatrix::invert()
100cdf0e10cSrcweir 	{
101cdf0e10cSrcweir 		Impl3DHomMatrix aWork(*mpImpl);
102cdf0e10cSrcweir 		sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
103cdf0e10cSrcweir 		sal_Int16 nParity;
104cdf0e10cSrcweir 
105cdf0e10cSrcweir 		if(aWork.ludcmp(pIndex, nParity))
106cdf0e10cSrcweir 		{
107cdf0e10cSrcweir 			mpImpl->doInvert(aWork, pIndex);
108cdf0e10cSrcweir 			delete[] pIndex;
109cdf0e10cSrcweir 
110cdf0e10cSrcweir 			return true;
111cdf0e10cSrcweir 		}
112cdf0e10cSrcweir 
113cdf0e10cSrcweir 		delete[] pIndex;
114cdf0e10cSrcweir 		return false;
115cdf0e10cSrcweir 	}
116cdf0e10cSrcweir 
isNormalized() const117cdf0e10cSrcweir 	bool B3DHomMatrix::isNormalized() const
118cdf0e10cSrcweir 	{
119cdf0e10cSrcweir 		return mpImpl->isNormalized();
120cdf0e10cSrcweir 	}
121cdf0e10cSrcweir 
normalize()122cdf0e10cSrcweir 	void B3DHomMatrix::normalize()
123cdf0e10cSrcweir 	{
124cdf0e10cSrcweir 		if(!const_cast<const B3DHomMatrix*>(this)->mpImpl->isNormalized())
125cdf0e10cSrcweir 			mpImpl->doNormalize();
126cdf0e10cSrcweir 	}
127cdf0e10cSrcweir 
determinant() const128cdf0e10cSrcweir 	double B3DHomMatrix::determinant() const
129cdf0e10cSrcweir 	{
130cdf0e10cSrcweir 		return mpImpl->doDeterminant();
131cdf0e10cSrcweir 	}
132cdf0e10cSrcweir 
trace() const133cdf0e10cSrcweir 	double B3DHomMatrix::trace() const
134cdf0e10cSrcweir 	{
135cdf0e10cSrcweir 		return mpImpl->doTrace();
136cdf0e10cSrcweir 	}
137cdf0e10cSrcweir 
transpose()138cdf0e10cSrcweir 	void B3DHomMatrix::transpose()
139cdf0e10cSrcweir 	{
140cdf0e10cSrcweir 		mpImpl->doTranspose();
141cdf0e10cSrcweir 	}
142cdf0e10cSrcweir 
operator +=(const B3DHomMatrix & rMat)143cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator+=(const B3DHomMatrix& rMat)
144cdf0e10cSrcweir 	{
145cdf0e10cSrcweir 		mpImpl->doAddMatrix(*rMat.mpImpl);
146cdf0e10cSrcweir 		return *this;
147cdf0e10cSrcweir 	}
148cdf0e10cSrcweir 
operator -=(const B3DHomMatrix & rMat)149cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat)
150cdf0e10cSrcweir 	{
151cdf0e10cSrcweir 		mpImpl->doSubMatrix(*rMat.mpImpl);
152cdf0e10cSrcweir 		return *this;
153cdf0e10cSrcweir 	}
154cdf0e10cSrcweir 
operator *=(double fValue)155cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator*=(double fValue)
156cdf0e10cSrcweir 	{
157cdf0e10cSrcweir 		const double fOne(1.0);
158cdf0e10cSrcweir 
159cdf0e10cSrcweir 		if(!fTools::equal(fOne, fValue))
160cdf0e10cSrcweir 			mpImpl->doMulMatrix(fValue);
161cdf0e10cSrcweir 
162cdf0e10cSrcweir 		return *this;
163cdf0e10cSrcweir 	}
164cdf0e10cSrcweir 
operator /=(double fValue)165cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator/=(double fValue)
166cdf0e10cSrcweir 	{
167cdf0e10cSrcweir 		const double fOne(1.0);
168cdf0e10cSrcweir 
169cdf0e10cSrcweir 		if(!fTools::equal(fOne, fValue))
170cdf0e10cSrcweir 			mpImpl->doMulMatrix(1.0 / fValue);
171cdf0e10cSrcweir 
172cdf0e10cSrcweir 		return *this;
173cdf0e10cSrcweir 	}
174cdf0e10cSrcweir 
operator *=(const B3DHomMatrix & rMat)175cdf0e10cSrcweir 	B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat)
176cdf0e10cSrcweir 	{
177cdf0e10cSrcweir 		if(!rMat.isIdentity())
178cdf0e10cSrcweir 			mpImpl->doMulMatrix(*rMat.mpImpl);
179cdf0e10cSrcweir 
180cdf0e10cSrcweir 		return *this;
181cdf0e10cSrcweir 	}
182cdf0e10cSrcweir 
operator ==(const B3DHomMatrix & rMat) const183cdf0e10cSrcweir 	bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const
184cdf0e10cSrcweir 	{
185cdf0e10cSrcweir 		if(mpImpl.same_object(rMat.mpImpl))
186cdf0e10cSrcweir 			return true;
187cdf0e10cSrcweir 
188cdf0e10cSrcweir 		return mpImpl->isEqual(*rMat.mpImpl);
189cdf0e10cSrcweir 	}
190cdf0e10cSrcweir 
operator !=(const B3DHomMatrix & rMat) const191cdf0e10cSrcweir 	bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const
192cdf0e10cSrcweir 	{
193cdf0e10cSrcweir         return !(*this == rMat);
194cdf0e10cSrcweir 	}
195cdf0e10cSrcweir 
rotate(double fAngleX,double fAngleY,double fAngleZ)196cdf0e10cSrcweir 	void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ)
197cdf0e10cSrcweir 	{
198cdf0e10cSrcweir 		if(!fTools::equalZero(fAngleX) || !fTools::equalZero(fAngleY) || !fTools::equalZero(fAngleZ))
199cdf0e10cSrcweir 		{
200cdf0e10cSrcweir 			if(!fTools::equalZero(fAngleX))
201cdf0e10cSrcweir 			{
202cdf0e10cSrcweir 				Impl3DHomMatrix aRotMatX;
203cdf0e10cSrcweir 				double fSin(sin(fAngleX));
204cdf0e10cSrcweir 				double fCos(cos(fAngleX));
205cdf0e10cSrcweir 
206cdf0e10cSrcweir 				aRotMatX.set(1, 1, fCos);
207cdf0e10cSrcweir 				aRotMatX.set(2, 2, fCos);
208cdf0e10cSrcweir 				aRotMatX.set(2, 1, fSin);
209cdf0e10cSrcweir 				aRotMatX.set(1, 2, -fSin);
210cdf0e10cSrcweir 
211cdf0e10cSrcweir 				mpImpl->doMulMatrix(aRotMatX);
212cdf0e10cSrcweir 			}
213cdf0e10cSrcweir 
214cdf0e10cSrcweir 			if(!fTools::equalZero(fAngleY))
215cdf0e10cSrcweir 			{
216cdf0e10cSrcweir 				Impl3DHomMatrix aRotMatY;
217cdf0e10cSrcweir 				double fSin(sin(fAngleY));
218cdf0e10cSrcweir 				double fCos(cos(fAngleY));
219cdf0e10cSrcweir 
220cdf0e10cSrcweir 				aRotMatY.set(0, 0, fCos);
221cdf0e10cSrcweir 				aRotMatY.set(2, 2, fCos);
222cdf0e10cSrcweir 				aRotMatY.set(0, 2, fSin);
223cdf0e10cSrcweir 				aRotMatY.set(2, 0, -fSin);
224cdf0e10cSrcweir 
225cdf0e10cSrcweir 				mpImpl->doMulMatrix(aRotMatY);
226cdf0e10cSrcweir 			}
227cdf0e10cSrcweir 
228cdf0e10cSrcweir 			if(!fTools::equalZero(fAngleZ))
229cdf0e10cSrcweir 			{
230cdf0e10cSrcweir 				Impl3DHomMatrix aRotMatZ;
231cdf0e10cSrcweir 				double fSin(sin(fAngleZ));
232cdf0e10cSrcweir 				double fCos(cos(fAngleZ));
233cdf0e10cSrcweir 
234cdf0e10cSrcweir 				aRotMatZ.set(0, 0, fCos);
235cdf0e10cSrcweir 				aRotMatZ.set(1, 1, fCos);
236cdf0e10cSrcweir 				aRotMatZ.set(1, 0, fSin);
237cdf0e10cSrcweir 				aRotMatZ.set(0, 1, -fSin);
238cdf0e10cSrcweir 
239cdf0e10cSrcweir 				mpImpl->doMulMatrix(aRotMatZ);
240cdf0e10cSrcweir 			}
241cdf0e10cSrcweir 		}
242cdf0e10cSrcweir 	}
243cdf0e10cSrcweir 
translate(double fX,double fY,double fZ)244cdf0e10cSrcweir 	void B3DHomMatrix::translate(double fX, double fY, double fZ)
245cdf0e10cSrcweir 	{
246cdf0e10cSrcweir 		if(!fTools::equalZero(fX) || !fTools::equalZero(fY) || !fTools::equalZero(fZ))
247cdf0e10cSrcweir 		{
248cdf0e10cSrcweir 			Impl3DHomMatrix aTransMat;
249cdf0e10cSrcweir 
250cdf0e10cSrcweir 			aTransMat.set(0, 3, fX);
251cdf0e10cSrcweir 			aTransMat.set(1, 3, fY);
252cdf0e10cSrcweir 			aTransMat.set(2, 3, fZ);
253cdf0e10cSrcweir 
254cdf0e10cSrcweir 			mpImpl->doMulMatrix(aTransMat);
255cdf0e10cSrcweir 		}
256cdf0e10cSrcweir 	}
257cdf0e10cSrcweir 
scale(double fX,double fY,double fZ)258cdf0e10cSrcweir 	void B3DHomMatrix::scale(double fX, double fY, double fZ)
259cdf0e10cSrcweir 	{
260cdf0e10cSrcweir 		const double fOne(1.0);
261cdf0e10cSrcweir 
262cdf0e10cSrcweir 		if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY) ||!fTools::equal(fOne, fZ))
263cdf0e10cSrcweir 		{
264cdf0e10cSrcweir 			Impl3DHomMatrix aScaleMat;
265cdf0e10cSrcweir 
266cdf0e10cSrcweir 			aScaleMat.set(0, 0, fX);
267cdf0e10cSrcweir 			aScaleMat.set(1, 1, fY);
268cdf0e10cSrcweir 			aScaleMat.set(2, 2, fZ);
269cdf0e10cSrcweir 
270cdf0e10cSrcweir 			mpImpl->doMulMatrix(aScaleMat);
271cdf0e10cSrcweir 		}
272cdf0e10cSrcweir 	}
273cdf0e10cSrcweir 
shearXY(double fSx,double fSy)274cdf0e10cSrcweir 	void B3DHomMatrix::shearXY(double fSx, double fSy)
275cdf0e10cSrcweir 	{
276cdf0e10cSrcweir 		// #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
277cdf0e10cSrcweir 		if(!fTools::equalZero(fSx) || !fTools::equalZero(fSy))
278cdf0e10cSrcweir 		{
279cdf0e10cSrcweir 			Impl3DHomMatrix aShearXYMat;
280cdf0e10cSrcweir 
281cdf0e10cSrcweir 			aShearXYMat.set(0, 2, fSx);
282cdf0e10cSrcweir 			aShearXYMat.set(1, 2, fSy);
283cdf0e10cSrcweir 
284cdf0e10cSrcweir 			mpImpl->doMulMatrix(aShearXYMat);
285cdf0e10cSrcweir 		}
286cdf0e10cSrcweir 	}
287cdf0e10cSrcweir 
shearYZ(double fSy,double fSz)288cdf0e10cSrcweir 	void B3DHomMatrix::shearYZ(double fSy, double fSz)
289cdf0e10cSrcweir 	{
290cdf0e10cSrcweir 		// #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
291cdf0e10cSrcweir 		if(!fTools::equalZero(fSy) || !fTools::equalZero(fSz))
292cdf0e10cSrcweir 		{
293cdf0e10cSrcweir 			Impl3DHomMatrix aShearYZMat;
294cdf0e10cSrcweir 
295cdf0e10cSrcweir 			aShearYZMat.set(1, 0, fSy);
296cdf0e10cSrcweir 			aShearYZMat.set(2, 0, fSz);
297cdf0e10cSrcweir 
298cdf0e10cSrcweir 			mpImpl->doMulMatrix(aShearYZMat);
299cdf0e10cSrcweir 		}
300cdf0e10cSrcweir 	}
301cdf0e10cSrcweir 
shearXZ(double fSx,double fSz)302cdf0e10cSrcweir 	void B3DHomMatrix::shearXZ(double fSx, double fSz)
303cdf0e10cSrcweir 	{
304cdf0e10cSrcweir 		// #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
305cdf0e10cSrcweir 		if(!fTools::equalZero(fSx) || !fTools::equalZero(fSz))
306cdf0e10cSrcweir 		{
307cdf0e10cSrcweir 			Impl3DHomMatrix aShearXZMat;
308cdf0e10cSrcweir 
309cdf0e10cSrcweir 			aShearXZMat.set(0, 1, fSx);
310cdf0e10cSrcweir 			aShearXZMat.set(2, 1, fSz);
311cdf0e10cSrcweir 
312cdf0e10cSrcweir 			mpImpl->doMulMatrix(aShearXZMat);
313cdf0e10cSrcweir 		}
314cdf0e10cSrcweir 	}
315cdf0e10cSrcweir 
frustum(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)316cdf0e10cSrcweir 	void B3DHomMatrix::frustum(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
317cdf0e10cSrcweir 	{
318cdf0e10cSrcweir 		const double fZero(0.0);
319cdf0e10cSrcweir 		const double fOne(1.0);
320cdf0e10cSrcweir 
321cdf0e10cSrcweir 		if(!fTools::more(fNear, fZero))
322cdf0e10cSrcweir 		{
323cdf0e10cSrcweir 			fNear = 0.001;
324cdf0e10cSrcweir 		}
325cdf0e10cSrcweir 
326cdf0e10cSrcweir 		if(!fTools::more(fFar, fZero))
327cdf0e10cSrcweir 		{
328cdf0e10cSrcweir 			fFar = fOne;
329cdf0e10cSrcweir 		}
330cdf0e10cSrcweir 
331cdf0e10cSrcweir 		if(fTools::equal(fNear, fFar))
332cdf0e10cSrcweir 		{
333cdf0e10cSrcweir 			fFar = fNear + fOne;
334cdf0e10cSrcweir 		}
335cdf0e10cSrcweir 
336cdf0e10cSrcweir 		if(fTools::equal(fLeft, fRight))
337cdf0e10cSrcweir 		{
338cdf0e10cSrcweir 			fLeft -= fOne;
339cdf0e10cSrcweir 			fRight += fOne;
340cdf0e10cSrcweir 		}
341cdf0e10cSrcweir 
342cdf0e10cSrcweir 		if(fTools::equal(fTop, fBottom))
343cdf0e10cSrcweir 		{
344cdf0e10cSrcweir 			fBottom -= fOne;
345cdf0e10cSrcweir 			fTop += fOne;
346cdf0e10cSrcweir 		}
347cdf0e10cSrcweir 
348cdf0e10cSrcweir 		Impl3DHomMatrix aFrustumMat;
349cdf0e10cSrcweir 
350cdf0e10cSrcweir 		aFrustumMat.set(0, 0, 2.0 * fNear / (fRight - fLeft));
351cdf0e10cSrcweir 		aFrustumMat.set(1, 1, 2.0 * fNear / (fTop - fBottom));
352cdf0e10cSrcweir 		aFrustumMat.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
353cdf0e10cSrcweir 		aFrustumMat.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
354cdf0e10cSrcweir 		aFrustumMat.set(2, 2, -fOne * ((fFar + fNear) / (fFar - fNear)));
355cdf0e10cSrcweir 		aFrustumMat.set(3, 2, -fOne);
356cdf0e10cSrcweir 		aFrustumMat.set(2, 3, -fOne * ((2.0 * fFar * fNear) / (fFar - fNear)));
357cdf0e10cSrcweir 		aFrustumMat.set(3, 3, fZero);
358cdf0e10cSrcweir 
359cdf0e10cSrcweir 		mpImpl->doMulMatrix(aFrustumMat);
360cdf0e10cSrcweir 	}
361cdf0e10cSrcweir 
ortho(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)362cdf0e10cSrcweir 	void B3DHomMatrix::ortho(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
363cdf0e10cSrcweir 	{
364cdf0e10cSrcweir 		if(fTools::equal(fNear, fFar))
365cdf0e10cSrcweir 		{
366cdf0e10cSrcweir 			fFar = fNear + 1.0;
367cdf0e10cSrcweir 		}
368cdf0e10cSrcweir 
369cdf0e10cSrcweir 		if(fTools::equal(fLeft, fRight))
370cdf0e10cSrcweir 		{
371cdf0e10cSrcweir 			fLeft -= 1.0;
372cdf0e10cSrcweir 			fRight += 1.0;
373cdf0e10cSrcweir 		}
374cdf0e10cSrcweir 
375cdf0e10cSrcweir 		if(fTools::equal(fTop, fBottom))
376cdf0e10cSrcweir 		{
377cdf0e10cSrcweir 			fBottom -= 1.0;
378cdf0e10cSrcweir 			fTop += 1.0;
379cdf0e10cSrcweir 		}
380cdf0e10cSrcweir 
381cdf0e10cSrcweir 		Impl3DHomMatrix aOrthoMat;
382cdf0e10cSrcweir 
383cdf0e10cSrcweir 		aOrthoMat.set(0, 0, 2.0 / (fRight - fLeft));
384cdf0e10cSrcweir 		aOrthoMat.set(1, 1, 2.0 / (fTop - fBottom));
385cdf0e10cSrcweir 		aOrthoMat.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
386cdf0e10cSrcweir 		aOrthoMat.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
387cdf0e10cSrcweir 		aOrthoMat.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
388cdf0e10cSrcweir 		aOrthoMat.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
389cdf0e10cSrcweir 
390cdf0e10cSrcweir 		mpImpl->doMulMatrix(aOrthoMat);
391cdf0e10cSrcweir 	}
392cdf0e10cSrcweir 
orientation(B3DPoint aVRP,B3DVector aVPN,B3DVector aVUV)393cdf0e10cSrcweir 	void B3DHomMatrix::orientation(B3DPoint aVRP, B3DVector aVPN, B3DVector aVUV)
394cdf0e10cSrcweir 	{
395cdf0e10cSrcweir 		Impl3DHomMatrix aOrientationMat;
396cdf0e10cSrcweir 
397cdf0e10cSrcweir 		// translate -VRP
398cdf0e10cSrcweir 		aOrientationMat.set(0, 3, -aVRP.getX());
399cdf0e10cSrcweir 		aOrientationMat.set(1, 3, -aVRP.getY());
400cdf0e10cSrcweir 		aOrientationMat.set(2, 3, -aVRP.getZ());
401cdf0e10cSrcweir 
402cdf0e10cSrcweir 		// build rotation
403cdf0e10cSrcweir 		aVUV.normalize();
404cdf0e10cSrcweir 		aVPN.normalize();
405cdf0e10cSrcweir 
406cdf0e10cSrcweir 		// build x-axis as peroendicular fron aVUV and aVPN
407cdf0e10cSrcweir 		B3DVector aRx(aVUV.getPerpendicular(aVPN));
408cdf0e10cSrcweir 		aRx.normalize();
409cdf0e10cSrcweir 
410cdf0e10cSrcweir 		// y-axis perpendicular to that
411cdf0e10cSrcweir 		B3DVector aRy(aVPN.getPerpendicular(aRx));
412cdf0e10cSrcweir 		aRy.normalize();
413cdf0e10cSrcweir 
414cdf0e10cSrcweir 		// the calculated normals are the line vectors of the rotation matrix,
415cdf0e10cSrcweir 		// set them to create rotation
416cdf0e10cSrcweir 		aOrientationMat.set(0, 0, aRx.getX());
417cdf0e10cSrcweir 		aOrientationMat.set(0, 1, aRx.getY());
418cdf0e10cSrcweir 		aOrientationMat.set(0, 2, aRx.getZ());
419cdf0e10cSrcweir 		aOrientationMat.set(1, 0, aRy.getX());
420cdf0e10cSrcweir 		aOrientationMat.set(1, 1, aRy.getY());
421cdf0e10cSrcweir 		aOrientationMat.set(1, 2, aRy.getZ());
422cdf0e10cSrcweir 		aOrientationMat.set(2, 0, aVPN.getX());
423cdf0e10cSrcweir 		aOrientationMat.set(2, 1, aVPN.getY());
424cdf0e10cSrcweir 		aOrientationMat.set(2, 2, aVPN.getZ());
425cdf0e10cSrcweir 
426cdf0e10cSrcweir 		mpImpl->doMulMatrix(aOrientationMat);
427cdf0e10cSrcweir 	}
428cdf0e10cSrcweir 
decompose(B3DTuple & rScale,B3DTuple & rTranslate,B3DTuple & rRotate,B3DTuple & rShear) const429cdf0e10cSrcweir 	bool B3DHomMatrix::decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const
430cdf0e10cSrcweir 	{
431cdf0e10cSrcweir 		// when perspective is used, decompose is not made here
432cdf0e10cSrcweir 		if(!mpImpl->isLastLineDefault())
433cdf0e10cSrcweir 			return false;
434cdf0e10cSrcweir 
435cdf0e10cSrcweir 		// If determinant is zero, decomposition is not possible
436cdf0e10cSrcweir 		if(0.0 == determinant())
437cdf0e10cSrcweir 			return false;
438cdf0e10cSrcweir 
439cdf0e10cSrcweir 		// isolate translation
440cdf0e10cSrcweir 		rTranslate.setX(mpImpl->get(0, 3));
441cdf0e10cSrcweir 		rTranslate.setY(mpImpl->get(1, 3));
442cdf0e10cSrcweir 		rTranslate.setZ(mpImpl->get(2, 3));
443cdf0e10cSrcweir 
444cdf0e10cSrcweir 		// correct translate values
445cdf0e10cSrcweir 		rTranslate.correctValues();
446cdf0e10cSrcweir 
447cdf0e10cSrcweir 		// get scale and shear
448cdf0e10cSrcweir 		B3DVector aCol0(mpImpl->get(0, 0), mpImpl->get(1, 0), mpImpl->get(2, 0));
449cdf0e10cSrcweir 		B3DVector aCol1(mpImpl->get(0, 1), mpImpl->get(1, 1), mpImpl->get(2, 1));
450cdf0e10cSrcweir 		B3DVector aCol2(mpImpl->get(0, 2), mpImpl->get(1, 2), mpImpl->get(2, 2));
451cdf0e10cSrcweir 		B3DVector aTemp;
452cdf0e10cSrcweir 
453cdf0e10cSrcweir 		// get ScaleX
454cdf0e10cSrcweir 		rScale.setX(aCol0.getLength());
455cdf0e10cSrcweir 		aCol0.normalize();
456cdf0e10cSrcweir 
457cdf0e10cSrcweir 		// get ShearXY
458cdf0e10cSrcweir 		rShear.setX(aCol0.scalar(aCol1));
459cdf0e10cSrcweir 
460cdf0e10cSrcweir 		if(fTools::equalZero(rShear.getX()))
461cdf0e10cSrcweir 		{
462cdf0e10cSrcweir 			rShear.setX(0.0);
463cdf0e10cSrcweir 		}
464cdf0e10cSrcweir 		else
465cdf0e10cSrcweir 		{
466cdf0e10cSrcweir 			aTemp.setX(aCol1.getX() - rShear.getX() * aCol0.getX());
467cdf0e10cSrcweir 			aTemp.setY(aCol1.getY() - rShear.getX() * aCol0.getY());
468cdf0e10cSrcweir 			aTemp.setZ(aCol1.getZ() - rShear.getX() * aCol0.getZ());
469cdf0e10cSrcweir 			aCol1 = aTemp;
470cdf0e10cSrcweir 		}
471cdf0e10cSrcweir 
472cdf0e10cSrcweir 		// get ScaleY
473cdf0e10cSrcweir 		rScale.setY(aCol1.getLength());
474cdf0e10cSrcweir 		aCol1.normalize();
475cdf0e10cSrcweir 
476cdf0e10cSrcweir 		const double fShearX(rShear.getX());
477cdf0e10cSrcweir 
478cdf0e10cSrcweir 		if(!fTools::equalZero(fShearX))
479cdf0e10cSrcweir 		{
480cdf0e10cSrcweir 			rShear.setX(rShear.getX() / rScale.getY());
481cdf0e10cSrcweir 		}
482cdf0e10cSrcweir 
483cdf0e10cSrcweir 		// get ShearXZ
484cdf0e10cSrcweir 		rShear.setY(aCol0.scalar(aCol2));
485cdf0e10cSrcweir 
486cdf0e10cSrcweir 		if(fTools::equalZero(rShear.getY()))
487cdf0e10cSrcweir 		{
488cdf0e10cSrcweir 			rShear.setY(0.0);
489cdf0e10cSrcweir 		}
490cdf0e10cSrcweir 		else
491cdf0e10cSrcweir 		{
492cdf0e10cSrcweir 			aTemp.setX(aCol2.getX() - rShear.getY() * aCol0.getX());
493cdf0e10cSrcweir 			aTemp.setY(aCol2.getY() - rShear.getY() * aCol0.getY());
494cdf0e10cSrcweir 			aTemp.setZ(aCol2.getZ() - rShear.getY() * aCol0.getZ());
495cdf0e10cSrcweir 			aCol2 = aTemp;
496cdf0e10cSrcweir 		}
497cdf0e10cSrcweir 
498cdf0e10cSrcweir 		// get ShearYZ
499cdf0e10cSrcweir 		rShear.setZ(aCol1.scalar(aCol2));
500cdf0e10cSrcweir 
501cdf0e10cSrcweir 		if(fTools::equalZero(rShear.getZ()))
502cdf0e10cSrcweir 		{
503cdf0e10cSrcweir 			rShear.setZ(0.0);
504cdf0e10cSrcweir 		}
505cdf0e10cSrcweir 		else
506cdf0e10cSrcweir 		{
507cdf0e10cSrcweir 			aTemp.setX(aCol2.getX() - rShear.getZ() * aCol1.getX());
508cdf0e10cSrcweir 			aTemp.setY(aCol2.getY() - rShear.getZ() * aCol1.getY());
509cdf0e10cSrcweir 			aTemp.setZ(aCol2.getZ() - rShear.getZ() * aCol1.getZ());
510cdf0e10cSrcweir 			aCol2 = aTemp;
511cdf0e10cSrcweir 		}
512cdf0e10cSrcweir 
513cdf0e10cSrcweir 		// get ScaleZ
514cdf0e10cSrcweir 		rScale.setZ(aCol2.getLength());
515cdf0e10cSrcweir 		aCol2.normalize();
516cdf0e10cSrcweir 
517cdf0e10cSrcweir 		const double fShearY(rShear.getY());
518cdf0e10cSrcweir 
519cdf0e10cSrcweir 		if(!fTools::equalZero(fShearY))
520cdf0e10cSrcweir 		{
521cdf0e10cSrcweir 			rShear.setY(rShear.getY() / rScale.getZ());
522cdf0e10cSrcweir 		}
523cdf0e10cSrcweir 
524cdf0e10cSrcweir 		const double fShearZ(rShear.getZ());
525cdf0e10cSrcweir 
526cdf0e10cSrcweir 		if(!fTools::equalZero(fShearZ))
527cdf0e10cSrcweir 		{
528cdf0e10cSrcweir 			rShear.setZ(rShear.getZ() / rScale.getZ());
529cdf0e10cSrcweir 		}
530cdf0e10cSrcweir 
531cdf0e10cSrcweir 		// correct shear values
532cdf0e10cSrcweir 		rShear.correctValues();
533cdf0e10cSrcweir 
534cdf0e10cSrcweir 		// Coordinate system flip?
535cdf0e10cSrcweir 		if(0.0 > aCol0.scalar(aCol1.getPerpendicular(aCol2)))
536cdf0e10cSrcweir 		{
537cdf0e10cSrcweir 			rScale = -rScale;
538cdf0e10cSrcweir 			aCol0 = -aCol0;
539cdf0e10cSrcweir 			aCol1 = -aCol1;
540cdf0e10cSrcweir 			aCol2 = -aCol2;
541cdf0e10cSrcweir 		}
542cdf0e10cSrcweir 
543cdf0e10cSrcweir 		// correct scale values
544cdf0e10cSrcweir 		rScale.correctValues(1.0);
545cdf0e10cSrcweir 
546cdf0e10cSrcweir 		// Get rotations
547cdf0e10cSrcweir         {
548cdf0e10cSrcweir             double fy=0;
549cdf0e10cSrcweir             double cy=0;
550cdf0e10cSrcweir 
551cdf0e10cSrcweir             if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 )
552cdf0e10cSrcweir                 || aCol0.getZ() > 1.0 )
553cdf0e10cSrcweir             {
554cdf0e10cSrcweir                 fy = -F_PI/2.0;
555cdf0e10cSrcweir                 cy = 0.0;
556cdf0e10cSrcweir             }
557cdf0e10cSrcweir             else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 )
558cdf0e10cSrcweir                 || aCol0.getZ() < -1.0 )
559cdf0e10cSrcweir             {
560cdf0e10cSrcweir                 fy = F_PI/2.0;
561cdf0e10cSrcweir                 cy = 0.0;
562cdf0e10cSrcweir             }
563cdf0e10cSrcweir             else
564cdf0e10cSrcweir             {
565cdf0e10cSrcweir                 fy = asin( -aCol0.getZ() );
566cdf0e10cSrcweir                 cy = cos(fy);
567cdf0e10cSrcweir             }
568cdf0e10cSrcweir 
569cdf0e10cSrcweir             rRotate.setY(fy);
570cdf0e10cSrcweir             if( ::basegfx::fTools::equalZero( cy ) )
571cdf0e10cSrcweir             {
572cdf0e10cSrcweir                 if( aCol0.getZ() > 0.0 )
573cdf0e10cSrcweir                     rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY()));
574cdf0e10cSrcweir                 else
575cdf0e10cSrcweir                     rRotate.setX(atan2(aCol1.getX(), aCol1.getY()));
576cdf0e10cSrcweir                 rRotate.setZ(0.0);
577cdf0e10cSrcweir             }
578cdf0e10cSrcweir             else
579cdf0e10cSrcweir             {
580cdf0e10cSrcweir                 rRotate.setX(atan2(aCol1.getZ(), aCol2.getZ()));
581cdf0e10cSrcweir                 rRotate.setZ(atan2(aCol0.getY(), aCol0.getX()));
582cdf0e10cSrcweir             }
583cdf0e10cSrcweir 
584cdf0e10cSrcweir             // corrcet rotate values
585cdf0e10cSrcweir             rRotate.correctValues();
586cdf0e10cSrcweir         }
587cdf0e10cSrcweir 
588cdf0e10cSrcweir 		return true;
589cdf0e10cSrcweir 	}
590cdf0e10cSrcweir } // end of namespace basegfx
591cdf0e10cSrcweir 
592cdf0e10cSrcweir // eof
593