QGIS/external/qwt-6.3.0/qwt_spline_basis.cpp
Juergen E. Fischer 33fc476d89 * replace external qwtpolar with qwt 6.3
* require qwt >=6.2 (and fallback to internal 6.3 if system's qwt doesn't suffice)
* debian doesn't have qwt for Qt6 and won't have it for trixie
2025-07-23 07:11:51 +10:00

271 lines
6.9 KiB
C++

/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_spline_basis.h"
#include "qwt_spline_parametrization.h"
#include <qpainterpath.h>
#if 0
static QPolygonF qwtBasisUniformKnots( const QPolygonF& points )
{
const int n = points.size();
if ( n < 3 )
return points;
QVector< double > u( n - 2 );
QVector< double > kx( n - 2 );
QVector< double > ky( n - 2 );
u[n - 3] = 4.0;
kx[n - 3] = 6.0 * points[n - 2].x() - points[n - 1].x();
ky[n - 3] = 6.0 * points[n - 2].y() - points[n - 1].y();
for ( int i = n - 4; i >= 0; i-- )
{
u[i] = 4.0 - 1.0 / u[i + 1];
kx[i] = 6.0 * points[i + 1].x() - kx[i + 1] / u[i + 1];
ky[i] = 6.0 * points[i + 1].y() - ky[i + 1] / u[i + 1];
}
QVector< QPointF > knots( n );
knots[0] = points[0];
for ( int i = 1; i < n - 1; i++ )
{
knots[i].rx() = ( kx[i - 1] - knots[i - 1].x() ) / u[i - 1];
knots[i].ry() = ( ky[i - 1] - knots[i - 1].y() ) / u[i - 1];
}
knots[n - 1] = points[n - 1];
return knots;
}
#endif
#if 0
static inline void qwtSplineBezierControlPoints( const QwtSplineParametrization* param,
const QPointF& p1, const QPointF& p2, const QPointF& p3, const QPointF& p4,
QPointF& cp1, QPointF& cp2 )
{
const double t1 = param->valueIncrement( p1, p2 );
const double t2 = param->valueIncrement( p2, p3 );
const double t3 = param->valueIncrement( p3, p4 );
const double t123 = t1 + t2 + t3;
cp1 = ( t2 + t3 ) / t123 * p2 + t1 / t123 * p3;
cp2 = ( t3 * p2 + ( t1 + t2 ) * p3 ) / t123;
}
#endif
static QPainterPath qwtSplineBasisPathUniform( const QPolygonF& points,
QwtSpline::BoundaryType boundaryType )
{
const int n = points.size();
const QPointF* pd = points.constData();
QPainterPath path;
QPointF cp1 = ( 2.0 * pd[0] + pd[1] ) / 3.0;;
if ( boundaryType == QwtSpline::ConditionalBoundaries )
{
path.moveTo( pd[0] );
}
else
{
const QPointF cpN = ( pd[n - 1] + 2.0 * pd[0] ) / 3.0;
path.moveTo( 0.5 * ( cpN + cp1 ) );
}
for ( int i = 1; i < n - 1; i++ )
{
const QPointF cp2 = ( pd[i - 1] + 2.0 * pd[i] ) / 3.0;
const QPointF cp3 = ( 2.0 * pd[i] + pd[i + 1] ) / 3.0;
path.cubicTo( cp1, cp2, 0.5 * ( cp2 + cp3 ) );
cp1 = cp3;
}
if ( boundaryType == QwtSpline::ConditionalBoundaries )
{
const QPointF cp2 = ( pd[n - 2] + 2.0 * pd[n - 1] ) / 3.0;
path.cubicTo( cp1, cp2, pd[n - 1] );
}
else
{
const QPointF cp2 = ( pd[n - 2] + 2.0 * pd[n - 1] ) / 3.0;
const QPointF cp3 = ( 2.0 * pd[n - 1] + pd[0] ) / 3.0;
path.cubicTo( cp1, cp2, 0.5 * ( cp2 + cp3 ) );
if ( boundaryType == QwtSpline::ClosedPolygon )
{
const QPointF cp4 = ( pd[n - 1] + 2.0 * pd[0] ) / 3.0;
const QPointF cp5 = ( 2.0 * pd[0] + pd[1] ) / 3.0;
path.cubicTo( cp3, cp4, 0.5 * ( cp4 + cp5 ) );
}
}
return path;
}
static QPainterPath qwtSplineBasisPath( const QPolygonF& points,
const QwtSplineParametrization* param,
QwtSpline::BoundaryType boundaryType )
{
const int n = points.size();
const QPointF* pd = points.constData();
QPointF p0;
double t1 = param->valueIncrement( pd[0], pd[1] );
double t2 = param->valueIncrement( pd[1], pd[2] );
double t0;
if ( boundaryType == QwtSpline::ConditionalBoundaries )
t0 = t1;
else
t0 = param->valueIncrement( pd[n - 1], pd[0] );
double t012 = t0 + t1 + t2;
QPointF cp1 = ( ( t1 + t2 ) * pd[0] + t0 * pd[1] ) / t012;
if ( boundaryType == QwtSpline::ConditionalBoundaries )
{
p0 = pd[0];
}
else
{
const double tN = param->valueIncrement( pd[n - 2], pd[n - 1] );
const QPointF cpN = ( t1 * pd[n - 1] + ( tN + t0 ) * pd[0] ) / ( tN + t0 + t1 );
p0 = ( t1 * cpN + t0 * cp1 ) / ( t0 + t1 );
}
QPainterPath path;
path.moveTo( p0 );
for ( int i = 1; i < n - 2; i++ )
{
const double t3 = param->valueIncrement( pd[i + 1], pd[i + 2] );
const double t123 = t1 + t2 + t3;
const QPointF cp2 = ( t2 * pd[i - 1] + ( t0 + t1 ) * pd[i] ) / t012;
const QPointF cp3 = ( ( t2 + t3 ) * pd[i] + t1 * pd[i + 1] ) / t123;
const QPointF p2 = ( t2 * cp2 + t1 * cp3 ) / ( t1 + t2 );
path.cubicTo( cp1, cp2, p2 );
cp1 = cp3;
t0 = t1;
t1 = t2;
t2 = t3;
t012 = t123;
}
{
double t3;
if ( boundaryType == QwtSpline::ConditionalBoundaries )
t3 = t2;
else
t3 = param->valueIncrement( pd[n - 1], pd[0] );
const double t123 = t1 + t2 + t3;
const QPointF cp2 = ( t2 * pd[n - 3] + ( t0 + t1 ) * pd[n - 2] ) / t012;
const QPointF cp3 = ( ( t2 + t3 ) * pd[n - 2] + t1 * pd[n - 1] ) / t123;
const QPointF p2 = ( t2 * cp2 + t1 * cp3 ) / ( t1 + t2 );
path.cubicTo( cp1, cp2, p2 );
cp1 = cp3;
t0 = t1;
t1 = t2;
t2 = t3;
t012 = t123;
}
const QPointF cp2 = ( t2 * pd[n - 2] + ( t0 + t1 ) * pd[n - 1] ) / t012;
if ( boundaryType == QwtSpline::ConditionalBoundaries )
{
path.cubicTo( cp1, cp2, pd[n - 1] );
}
else
{
const double t3 = param->valueIncrement( pd[0], pd[1] );
const double t123 = t1 + t2 + t3;
const QPointF cp3 = ( t2 + t3 ) / t123 * pd[n - 1] + t1 / t123 * pd[0];
const QPointF cp4 = ( t3 * pd[n - 1] + ( t1 + t2 ) * pd[0] ) / t123;
const QPointF pN = ( t2 * cp2 + t1 * cp3 ) / ( t1 + t2 );
path.cubicTo( cp1, cp2, pN );
path.cubicTo( cp3, cp4, p0 );
}
return path;
}
//! Constructor
QwtSplineBasis::QwtSplineBasis()
{
}
//! Destructor
QwtSplineBasis::~QwtSplineBasis()
{
}
//! The locality is always 2
uint QwtSplineBasis::locality() const
{
return 2;
}
/*!
Approximates a polygon piecewise with cubic Bezier curves
and returns them as QPainterPath.
\param points Control points
\return Painter path, that can be rendered by QPainter
*/
QPainterPath QwtSplineBasis::painterPath( const QPolygonF& points ) const
{
if ( points.size() < 4 )
return QPainterPath();
QPainterPath path;
switch( parametrization()->type() )
{
case QwtSplineParametrization::ParameterUniform:
{
path = qwtSplineBasisPathUniform( points, boundaryType() );
break;
}
default:
{
path = qwtSplineBasisPath( points, parametrization(), boundaryType() );
}
}
return path;
}