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_basegfx.hxx"
30 #include <osl/diagnose.h>
31 
32 #include <basegfx/curve/b2dcubicbezier.hxx>
33 
34 #include <basegfx/tools/debugplotter.hxx>
35 #include <boost/bind.hpp>
36 
37 
38 namespace basegfx
39 {
40     namespace
41     {
42         void outputHeader( const ::rtl::OString& rTitle,
43                            ::std::ostream* 		 pStm )
44         {
45             // output gnuplot setup
46             if( pStm )
47             {
48                 *pStm << "#!/usr/bin/gnuplot -persist" << ::std::endl <<
49                     "#" << ::std::endl <<
50                     "# automatically generated by basegfx, don't change!" << ::std::endl <<
51                     "#" << ::std::endl <<
52                     "#   --- " << (const sal_Char*)rTitle << " ---" << ::std::endl <<
53                     "#" << ::std::endl <<
54                     "set parametric" << ::std::endl <<
55                     "# set terminal postscript eps enhanced color " << ::std::endl <<
56                     "# set output \"plot.eps\"" << ::std::endl <<
57                     // This function plots a cubic bezier curve. P,q,r,s
58                     // are the control point elements of the corresponding
59                     // output coordinate component (i.e. x components for
60                     // the x plot, and y components for the y plot)
61                     "cubicBezier(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3" << ::std::endl <<
62                     // This function plots the derivative of a cubic
63                     // bezier curve. P,q,r,s are the control point
64                     // components of the _original_ curve
65                     "cubicBezDerivative(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2" << ::std::endl <<
66                     // Plot a line's component of a line between a and b
67                     // (where a and b should be the corresponding
68                     // components of the line's start and end point,
69                     // respectively)
70                     "line(p,q,r) = p*(1-t)+q*t" << ::std::endl <<
71                     // Plot a line's x component of a line in implicit
72                     // form ax + by + c = 0
73                     "implicitLineX(a,b,c,t) = a*-c + t*-b" << ::std::endl <<
74                     // Plot a line's y component of a line in implicit
75                     // form ax + by + c = 0
76                     "implicitLineY(a,b,c,t) = b*-c + t*a" << ::std::endl <<
77                     "pointmarkx(c,t) = c-0.03*t" << ::std::endl <<										 // hack for displaying single points in parametric form
78                     "pointmarky(c,t) = c+0.03*t" << ::std::endl <<										 // hack for displaying single points in parametric form
79                     "# end of setup" << ::std::endl;
80             }
81             else
82             {
83                 OSL_TRACE( "#!/usr/bin/gnuplot -persist\n",
84                            "#\n",
85                            "# automatically generated by basegfx, don't change!\n",
86                            "#\n",
87                            "#   --- %s ---\n",
88                            "#\n",
89                            "set parametric\n",
90                            // This function plots a cubic bezier curve. P,q,r,s
91                            // are the control point elements of the corresponding
92                            // output coordinate component (i.e. x components for
93                            // the x plot, and y components for the y plot)
94                            "cubicBezier(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3\n",
95                            // This function plots the derivative of a cubic
96                            // bezier curve. P,q,r,s are the control point
97                            // components of the _original_ curve
98                            "cubicBezDerivative(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2\n",
99                            // Plot a line's component of a line between a and b
100                            // (where a and b should be the corresponding
101                            // components of the line's start and end point,
102                            // respectively)
103                            "line(p,q,r) = p*(1-t)+q*t\n",
104                            // Plot a line's x component of a line in implicit
105                            // form ax + by + c = 0
106                            "implicitLineX(a,b,c,t) = a*-c + t*-b\n",
107                            // Plot a line's y component of a line in implicit
108                            // form ax + by + c = 0
109                            "implicitLineY(a,b,c,t) = b*-c + t*a\n",
110                            "pointmarkx(c,t) = c-0.03*t\n",										 // hack for displaying single points in parametric form
111                            "pointmarky(c,t) = c+0.03*t\n",										 // hack for displaying single points in parametric form
112                            "# end of setup\n",
113                            (const sal_Char*)rTitle );
114             }
115         }
116 
117         class Writer
118         {
119         public:
120             Writer( ::std::ostream* pStm ) :
121                 mpStream( pStm )
122             {
123             }
124 
125             void outputPoint( const ::std::pair< B2DPoint, ::rtl::OString >& rElem )
126             {
127                 if( mpStream )
128                     *mpStream << " " << rElem.first.getX() << "\t" << rElem.first.getY() << ::std::endl;
129                 else
130                     OSL_TRACE( " %f\t%f\n", rElem.first.getX(), rElem.first.getY() );
131             }
132 
133             void outputVector( const ::std::pair< B2DVector, ::rtl::OString >& rElem )
134             {
135                 if( mpStream )
136                     *mpStream << " " << rElem.first.getX() << "\t" << rElem.first.getY() << ::std::endl << ::std::endl;
137                 else
138                     OSL_TRACE( " %f\t%f\n\n", rElem.first.getX(), rElem.first.getY() );
139             }
140 
141             void outputRect( const ::std::pair< B2DRange, ::rtl::OString >& rElem )
142             {
143                 const double nX0( rElem.first.getMinX() );
144                 const double nY0( rElem.first.getMinY() );
145                 const double nX1( rElem.first.getMaxX() );
146                 const double nY1( rElem.first.getMaxY() );
147 
148                 if( mpStream )
149                     *mpStream << " "
150                               << nX0 << "\t" << nY0 << "\t"
151                               << nX1 << "\t" << nY0 << "\t"
152                               << nX1 << "\t" << nY1 << "\t"
153                               << nX0 << "\t" << nY1 << "\t"
154                               << nX0 << "\t" << nY0 << ::std::endl << ::std::endl;
155 
156                 else
157                     OSL_TRACE( " %f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n\n",
158                                nX0, nY0,
159                                nX1, nY0,
160                                nX1, nY1,
161                                nX0, nY1,
162                                nX0, nY0 );
163             }
164 
165         private:
166             ::std::ostream* 	mpStream;
167         };
168     }
169 
170     DebugPlotter::DebugPlotter( const sal_Char* pTitle ) :
171         maTitle( pTitle ),
172         maPoints(),
173         maVectors(),
174         maRanges(),
175         maPolygons(),
176         mpOutputStream(NULL)
177     {
178     }
179 
180     DebugPlotter::DebugPlotter( const sal_Char* pTitle,
181                                 ::std::ostream& rOutputStream ) :
182         maTitle( pTitle ),
183         maPoints(),
184         maVectors(),
185         maRanges(),
186         maPolygons(),
187         mpOutputStream(&rOutputStream)
188     {
189     }
190 
191     DebugPlotter::~DebugPlotter()
192     {
193         const bool bHavePoints( !maPoints.empty() );
194         const bool bHaveVectors( !maVectors.empty() );
195         const bool bHaveRanges( !maRanges.empty() );
196         const bool bHavePolygons( !maPolygons.empty() );
197 
198         if( bHavePoints ||
199             bHaveVectors ||
200             bHaveRanges ||
201             bHavePolygons )
202         {
203             outputHeader( maTitle, mpOutputStream );
204 
205             print( "\n\n# parametric primitive output\n"
206                    "plot [t=0:1] \\\n" );
207 
208             // output plot declarations for used entities
209             bool bNeedColon( false );
210             if( bHavePoints )
211             {
212                 print( " '-' using ($1):($2) title \"Points\" with points" );
213                 bNeedColon = true;
214             }
215             if( bHaveVectors )
216             {
217                 if( bNeedColon )
218                     print( ", \\\n" );
219 
220                 print( " '-' using ($1):($2) title \"Vectors\" with lp" );
221                 bNeedColon = true;
222             }
223             if( bHaveRanges )
224             {
225                 if( bNeedColon )
226                     print( ", \\\n" );
227 
228                 print( " '-' using ($1):($2) title \"Ranges\" with lines" );
229                 bNeedColon = true;
230             }
231             if( bHavePolygons )
232             {
233                 const ::std::size_t nSize( maPolygons.size() );
234                 for( ::std::size_t i=0; i<nSize; ++i )
235                 {
236                     if( maPolygons.at(i).first.areControlPointsUsed() )
237                     {
238                         const B2DPolygon& rCurrPoly( maPolygons.at(i).first );
239 
240                         const sal_uInt32 nCount( rCurrPoly.count() );
241                         for( sal_uInt32 k=0; k<nCount; ++k )
242                         {
243                             if( bNeedColon )
244                                 print( ", \\\n" );
245 
246                             const B2DPoint& rP0( rCurrPoly.getB2DPoint(k) );
247                             const B2DPoint& rP1( rCurrPoly.getNextControlPoint(k) );
248                             const B2DPoint& rP2( rCurrPoly.getPrevControlPoint((k + 1) % nCount) );
249                             const B2DPoint& rP3( k+1<nCount ? rCurrPoly.getB2DPoint(k+1) : rCurrPoly.getB2DPoint(k) );
250 
251                             if( mpOutputStream )
252                                 *mpOutputStream << "  cubicBezier("
253                                                 << rP0.getX() << ","
254                                     << rP1.getX() << ","
255                                     << rP2.getX() << ","
256                                     << rP3.getX() << ",t), \\\n   cubicBezier("
257                                     << rP0.getY() << ","
258                                     << rP1.getY() << ","
259                                     << rP2.getY() << ","
260                                     << rP3.getY() << ",t)";
261                             else
262                                 OSL_TRACE( "  cubicBezier(%f,%f,%f,%f,t), \\\n"
263                                            "   cubicBezier(%f,%f,%f,%f,t)",
264                                            rP0.getX(),
265                                            rP1.getX(),
266                                            rP2.getX(),
267                                            rP3.getX(),
268                                            rP0.getY(),
269                                            rP1.getY(),
270                                            rP2.getY(),
271                                            rP3.getY() );
272 
273                             bNeedColon = true;
274                         }
275                     }
276                     else
277                     {
278                         if( bNeedColon )
279                             print( ", \\\n" );
280 
281                         if( mpOutputStream )
282                             *mpOutputStream << " '-' using ($1):($2) title \"Polygon "
283                                             << (const sal_Char*)maPolygons.at(i).second << "\" with lp";
284                         else
285                             OSL_TRACE( " '-' using ($1):($2) title \"Polygon %s\" with lp",
286                                        (const sal_Char*)maPolygons.at(i).second );
287 
288                         bNeedColon = true;
289                     }
290                 }
291             }
292 
293             if( bHavePoints )
294             {
295                 Writer aWriter( mpOutputStream );
296 
297                 ::std::for_each( maPoints.begin(),
298                                  maPoints.end(),
299                                  ::boost::bind( &Writer::outputPoint,
300                                                 ::boost::ref( aWriter ),
301                                                 _1 ) );
302                 print( "e\n" );
303             }
304 
305             if( bHaveVectors )
306             {
307                 Writer aWriter( mpOutputStream );
308 
309                 ::std::for_each( maVectors.begin(),
310                                  maVectors.end(),
311                                  ::boost::bind( &Writer::outputVector,
312                                                 ::boost::ref( aWriter ),
313                                                 _1 ) );
314                 print( "e\n" );
315             }
316 
317             if( bHaveRanges )
318             {
319                 Writer aWriter( mpOutputStream );
320 
321                 ::std::for_each( maRanges.begin(),
322                                  maRanges.end(),
323                                  ::boost::bind( &Writer::outputRect,
324                                                 ::boost::ref( aWriter ),
325                                                 _1 ) );
326                 print( "e\n" );
327             }
328 
329             if( bHavePolygons )
330             {
331                 const ::std::size_t nSize( maPolygons.size() );
332                 for( ::std::size_t i=0; i<nSize; ++i )
333                 {
334                     if( !maPolygons.at(i).first.areControlPointsUsed() )
335                     {
336                         const B2DPolygon& rCurrPoly( maPolygons.at(i).first );
337 
338                         const sal_uInt32 nCount( rCurrPoly.count() );
339                         for( sal_uInt32 k=0; k<nCount; ++k )
340                         {
341                             const B2DPoint& rP( rCurrPoly.getB2DPoint(k) );
342 
343                             if( mpOutputStream )
344                                 *mpOutputStream << " " << rP.getX() << "," << rP.getY();
345                             else
346                                 OSL_TRACE( " %f,%f",
347                                            rP.getX(),
348                                            rP.getX() );
349                         }
350 
351                         print( "\ne\n" );
352                     }
353                 }
354             }
355         }
356     }
357 
358     void DebugPlotter::plot( const B2DPoint& rPoint,
359                              const sal_Char* pTitle )
360     {
361         maPoints.push_back( ::std::make_pair( rPoint,
362                                               ::rtl::OString( pTitle ) ) );
363     }
364 
365     void DebugPlotter::plot( const B2DVector&	rVec,
366                              const sal_Char* 	pTitle )
367     {
368         maVectors.push_back( ::std::make_pair( rVec,
369                                                ::rtl::OString( pTitle ) ) );
370     }
371 
372     void DebugPlotter::plot( const B2DCubicBezier&	rBezier,
373                              const sal_Char* 		pTitle )
374     {
375         B2DPolygon aPoly;
376         aPoly.append(rBezier.getStartPoint());
377 		aPoly.appendBezierSegment(rBezier.getControlPointA(), rBezier.getControlPointB(), rBezier.getEndPoint());
378         maPolygons.push_back( ::std::make_pair( aPoly,
379                                                 ::rtl::OString( pTitle ) ) );
380     }
381 
382     void DebugPlotter::plot( const B2DRange& rRange,
383                              const sal_Char* pTitle )
384     {
385         maRanges.push_back( ::std::make_pair( rRange,
386                                               ::rtl::OString( pTitle ) ) );
387     }
388 
389     void DebugPlotter::plot( const B2DPolygon&	rPoly,
390                              const sal_Char* 	pTitle )
391     {
392         maPolygons.push_back( ::std::make_pair( rPoly,
393                                                 ::rtl::OString( pTitle ) ) );
394     }
395 
396     void DebugPlotter::plot( const B2DPolyPolygon&	rPoly,
397                              const sal_Char* 		pTitle )
398     {
399         const ::rtl::OString aTitle( pTitle );
400         const sal_uInt32 nCount( rPoly.count() );
401         for( sal_uInt32 i=0; i<nCount; ++i )
402             maPolygons.push_back( ::std::make_pair( rPoly.getB2DPolygon( i ),
403                                                     aTitle ) );
404     }
405 
406     void DebugPlotter::print( const sal_Char* pStr )
407     {
408         if( mpOutputStream )
409             *mpOutputStream << pStr;
410         else
411             OSL_TRACE( pStr );
412     }
413 }
414