1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_slideshow.hxx"
30 
31 #include <canvas/debug.hxx>
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <basegfx/point/b2dpoint.hxx>
34 #include <basegfx/polygon/b2dpolygon.hxx>
35 #include <basegfx/matrix/b2dhommatrixtools.hxx>
36 #include "snakewipe.hxx"
37 #include "transitiontools.hxx"
38 
39 
40 namespace slideshow {
41 namespace internal {
42 
43 SnakeWipe::SnakeWipe( sal_Int32 nElements, bool diagonal, bool flipOnYAxis )
44     : m_sqrtElements( static_cast<sal_Int32>(
45                           sqrt( static_cast<double>(nElements) ) ) ),
46       m_elementEdge( 1.0 / m_sqrtElements ),
47       m_diagonal(diagonal),
48       m_flipOnYAxis(flipOnYAxis)
49 {
50 }
51 
52 ::basegfx::B2DPolyPolygon SnakeWipe::calcSnake( double t ) const
53 {
54     ::basegfx::B2DPolyPolygon res;
55     const double area = (t * m_sqrtElements * m_sqrtElements);
56     const sal_Int32 line_ = (static_cast<sal_Int32>(area) / m_sqrtElements);
57     const double line = ::basegfx::pruneScaleValue(
58         static_cast<double>(line_) / m_sqrtElements );
59     const double col = ::basegfx::pruneScaleValue(
60         (area - (line_ * m_sqrtElements)) / m_sqrtElements );
61 
62     if (! ::basegfx::fTools::equalZero( line )) {
63         ::basegfx::B2DPolygon poly;
64         poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
65         poly.append( ::basegfx::B2DPoint( 0.0, line ) );
66         poly.append( ::basegfx::B2DPoint( 1.0, line ) );
67         poly.append( ::basegfx::B2DPoint( 1.0, 0.0 ) );
68         poly.setClosed(true);
69         res.append(poly);
70     }
71     if (! ::basegfx::fTools::equalZero( col ))
72     {
73         double offset = 0.0;
74         if ((line_ & 1) == 1) {
75             // odd line: => right to left
76             offset = (1.0 - col);
77         }
78         ::basegfx::B2DPolygon poly;
79         poly.append( ::basegfx::B2DPoint( offset, line ) );
80         poly.append( ::basegfx::B2DPoint( offset,
81                                           line + m_elementEdge ) );
82         poly.append( ::basegfx::B2DPoint( offset + col,
83                                           line + m_elementEdge ) );
84         poly.append( ::basegfx::B2DPoint( offset + col, line ) );
85         poly.setClosed(true);
86         res.append(poly);
87     }
88 
89     return res;
90 }
91 
92 ::basegfx::B2DPolyPolygon SnakeWipe::calcHalfDiagonalSnake(
93     double t, bool in ) const
94 {
95     ::basegfx::B2DPolyPolygon res;
96 
97     if (in) {
98         const double sqrtArea2 = sqrt( t * m_sqrtElements * m_sqrtElements );
99         const double edge = ::basegfx::pruneScaleValue(
100             static_cast<double>( static_cast<sal_Int32>(sqrtArea2) ) /
101             m_sqrtElements );
102 
103         ::basegfx::B2DPolygon poly;
104         if (! ::basegfx::fTools::equalZero( edge )) {
105             poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
106             poly.append( ::basegfx::B2DPoint( 0.0, edge ) );
107             poly.append( ::basegfx::B2DPoint( edge, 0.0 ) );
108             poly.setClosed(true);
109             res.append(poly);
110         }
111         const double a = (M_SQRT1_2 / m_sqrtElements);
112         const double d = (sqrtArea2 - static_cast<sal_Int32>(sqrtArea2));
113         const double len = (t * M_SQRT2 * d);
114         const double height = ::basegfx::pruneScaleValue( M_SQRT1_2 / m_sqrtElements );
115         poly.clear();
116         poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
117         poly.append( ::basegfx::B2DPoint( 0.0, height ) );
118         poly.append( ::basegfx::B2DPoint( len + a, height ) );
119         poly.append( ::basegfx::B2DPoint( len + a, 0.0 ) );
120         poly.setClosed(true);
121         ::basegfx::B2DHomMatrix aTransform;
122 
123         if ((static_cast<sal_Int32>(sqrtArea2) & 1) == 1)
124         {
125             // odd line
126             aTransform = basegfx::tools::createRotateB2DHomMatrix(M_PI_2 + M_PI_4);
127             aTransform.translate(edge + m_elementEdge, 0.0);
128         }
129         else
130         {
131             aTransform = basegfx::tools::createTranslateB2DHomMatrix(-a, 0.0);
132             aTransform.rotate( -M_PI_4 );
133             aTransform.translate( 0.0, edge );
134         }
135 
136         poly.transform( aTransform );
137         res.append(poly);
138     }
139     else // out
140     {
141         const double sqrtArea2 = sqrt( t * m_sqrtElements * m_sqrtElements );
142         const double edge = ::basegfx::pruneScaleValue(
143             static_cast<double>( static_cast<sal_Int32>(sqrtArea2) ) /
144             m_sqrtElements );
145 
146         ::basegfx::B2DPolygon poly;
147         if (! ::basegfx::fTools::equalZero( edge )) {
148             poly.append( ::basegfx::B2DPoint( 0.0, 1.0 ) );
149             poly.append( ::basegfx::B2DPoint( edge, 1.0 ) );
150             poly.append( ::basegfx::B2DPoint( 1.0, edge ) );
151             poly.append( ::basegfx::B2DPoint( 1.0, 0.0 ) );
152             poly.setClosed(true);
153             res.append(poly);
154         }
155         const double a = (M_SQRT1_2 / m_sqrtElements);
156         const double d = (sqrtArea2 - static_cast<sal_Int32>(sqrtArea2));
157         const double len = ((1.0 - t) * M_SQRT2 * d);
158         const double height = ::basegfx::pruneScaleValue( M_SQRT1_2 / m_sqrtElements );
159         poly.clear();
160         poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
161         poly.append( ::basegfx::B2DPoint( 0.0, height ) );
162         poly.append( ::basegfx::B2DPoint( len + a, height ) );
163         poly.append( ::basegfx::B2DPoint( len + a, 0.0 ) );
164         poly.setClosed(true);
165         ::basegfx::B2DHomMatrix aTransform;
166 
167         if ((static_cast<sal_Int32>(sqrtArea2) & 1) == 1)
168         {
169             // odd line
170             aTransform = basegfx::tools::createTranslateB2DHomMatrix(0.0, -height);
171             aTransform.rotate( M_PI_2 + M_PI_4 );
172             aTransform.translate( 1.0, edge );
173         }
174         else
175         {
176             aTransform = basegfx::tools::createRotateB2DHomMatrix(-M_PI_4);
177             aTransform.translate( edge, 1.0 );
178         }
179         poly.transform( aTransform );
180         res.append(poly);
181     }
182 
183     return res;
184 }
185 
186 ::basegfx::B2DPolyPolygon SnakeWipe::operator () ( double t )
187 {
188     ::basegfx::B2DPolyPolygon res;
189     if (m_diagonal)
190     {
191         if (t >= 0.5) {
192             res.append( calcHalfDiagonalSnake( 1.0, true ) );
193             res.append( calcHalfDiagonalSnake( 2.0 * (t - 0.5), false ) );
194         }
195         else
196             res.append( calcHalfDiagonalSnake( 2.0 * t, true ) );
197     }
198     else
199         res = calcSnake(t);
200 
201     return m_flipOnYAxis ? flipOnYAxis(res) : res;
202 }
203 
204 ::basegfx::B2DPolyPolygon ParallelSnakesWipe::operator () ( double t )
205 {
206     ::basegfx::B2DPolyPolygon res;
207     if (m_diagonal)
208     {
209         OSL_ASSERT( m_opposite );
210         ::basegfx::B2DPolyPolygon half(
211             calcHalfDiagonalSnake( t, false /* out */ ) );
212         // flip on x axis and rotate 90 degrees:
213         basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleB2DHomMatrix(1.0, -1.0));
214         aTransform.translate( -0.5, 0.5 );
215         aTransform.rotate( M_PI_2 );
216         aTransform.translate( 0.5, 0.5 );
217         half.transform( aTransform );
218         half.flip();
219         res.append( half );
220 
221         // rotate 180 degrees:
222         aTransform = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5);
223         aTransform.rotate( M_PI );
224         aTransform.translate( 0.5, 0.5 );
225         half.transform( aTransform );
226         res.append( half );
227     }
228     else
229     {
230         ::basegfx::B2DPolyPolygon half( calcSnake( t / 2.0 ) );
231         // rotate 90 degrees:
232         basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5));
233         aTransform.rotate( M_PI_2 );
234         aTransform.translate( 0.5, 0.5 );
235         half.transform( aTransform );
236         res.append( flipOnYAxis(half) );
237         res.append( m_opposite ? flipOnXAxis(half) : half );
238     }
239 
240     return m_flipOnYAxis ? flipOnYAxis(res) : res;
241 }
242 
243 }
244 }
245