/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basegfx.hxx" #include "testtools.hxx" #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <algorithm> namespace basegfx { namespace testtools { Plotter::Plotter( ::std::ostream& rOutputStream ) : mrOutputStream(rOutputStream), maPoints(), mbFirstElement( true ) { // output gnuplot setup. We switch gnuplot to parametric // mode, therefore every plot has at least _two_ // functions: one for the x and one for the y value, both // depending on t. mrOutputStream << "#!/usr/bin/gnuplot -persist" << ::std::endl << "#" << ::std::endl << "# automatically generated by basegfx::testtools::Plotter, don't change!" << ::std::endl << "#" << ::std::endl << "set parametric" << ::std::endl // This function plots a cubic bezier curve. P,q,r,s // are the control point elements of the corresponding // output coordinate component (i.e. x components for // the x plot, and y components for the y plot) << "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 // This function plots the derivative of a cubic // bezier curve. P,q,r,s are the control point // components of the _original_ curve << "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 // Plot a line's x component of a line in implicit // form ax + by + c = 0 << "implicitLineX(a,b,c,t) = a*-c + t*-b" << ::std::endl // Plot a line's y component of a line in implicit // form ax + by + c = 0 << "implicitLineY(a,b,c,t) = b*-c + t*a" << ::std::endl // Plot a line's component of a line between a and b // (where a and b should be the corresponding // components of the line's start and end point, // respectively) << "line(a,b,t) = a*(1-t) + b*t" << ::std::endl << ::std::endl << "# end of setup" << ::std::endl << ::std::endl // Start the actual plot line << "plot [t=0:1] "; } namespace { class PointWriter { public: PointWriter( ::std::ostream& rOutputStream ) : mrOutputStream( rOutputStream ) { } void operator()( const B2DPoint& rPoint ) const { mrOutputStream << rPoint.getX() << "\t" << rPoint.getY() << ::std::endl; mrOutputStream << "e" << ::std::endl; } private: ::std::ostream& mrOutputStream; }; } Plotter::~Plotter() { // End the plot line mrOutputStream << ::std::endl; // write stored data points. Cannot write before, since // this is an inline dataset, which must be after the plot <...> // line ::std::for_each( maPoints.begin(), maPoints.end(), PointWriter(mrOutputStream) ); } void Plotter::plot( const B2DPolygon& rPoly ) { const sal_uInt32 pointCount( rPoly.count() ); if( pointCount < 1 ) return; if( pointCount == 1 ) { plot( rPoly.getB2DPoint(0) ); return; } sal_uInt32 i; for( i=0; i<pointCount-1; ++i ) { if(rPoly.isNextControlPointUsed(i) || rPoly.isPrevControlPointUsed(i + 1)) { const B2DCubicBezier aBezierPlot( rPoly.getB2DPoint(i), rPoly.getNextControlPoint(i), rPoly.getPrevControlPoint(i + 1), rPoly.getB2DPoint(i + 1)); plot(aBezierPlot); } else { plot( rPoly.getB2DPoint(i), rPoly.getB2DPoint(i+1) ); } } } void Plotter::plot( const B2DPolyPolygon& rPolyPoly ) { const sal_uInt32 nPolyCount( rPolyPoly.count() ); sal_uInt32 i; for( i=0; i<nPolyCount; ++i ) { plot( rPolyPoly.getB2DPolygon(i) ); } } void Plotter::plot( const B2DPoint& rPoint ) { maPoints.push_back( rPoint ); writeSeparator(); mrOutputStream << "'-' using ($1):($2) title \"Point " << maPoints.size() << "\" with points"; } void Plotter::plot( const B2DRange& rRect ) { // TODO: do that also as a data file plot. maPoints must // then become polymorph, but WTF. // decompose into four lines plot( B2DPoint(rRect.getMinX(), rRect.getMinY()), B2DPoint(rRect.getMaxX(), rRect.getMinY()) ); plot( B2DPoint(rRect.getMaxX(), rRect.getMinY()), B2DPoint(rRect.getMaxX(), rRect.getMaxY()) ); plot( B2DPoint(rRect.getMaxX(), rRect.getMaxY()), B2DPoint(rRect.getMinX(), rRect.getMaxY()) ); plot( B2DPoint(rRect.getMinX(), rRect.getMaxY()), B2DPoint(rRect.getMinX(), rRect.getMinY()) ); } void Plotter::plot( const B2DPoint& rStartPoint, const B2DPoint& rEndPoint ) { writeSeparator(); mrOutputStream << "line(" << rStartPoint.getX() << "," << rEndPoint.getX() << ",t), " << "line(" << rStartPoint.getY() << "," << rEndPoint.getY() << ",t)"; } void Plotter::plot( const B2DCubicBezier& rCurve ) { writeSeparator(); mrOutputStream << "cubicBezier(" << rCurve.getStartPoint().getX() << "," << rCurve.getControlPointA().getX() << "," << rCurve.getControlPointB().getX() << "," << rCurve.getEndPoint().getX() << ",t), " << "cubicBezier(" << rCurve.getStartPoint().getY() << "," << rCurve.getControlPointA().getY() << "," << rCurve.getControlPointB().getY() << "," << rCurve.getEndPoint().getY() << ",t)"; } void Plotter::writeSeparator() { if( mbFirstElement ) { mbFirstElement = false; } else { mrOutputStream << ", "; } } } }