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