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