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