blob: 43308cef41a1b586c882a3277149f764542fdc35 [file] [log] [blame]
/**************************************************************
*
* 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 << ", ";
}
}
}
}