21#include <osl/diagnose.h>
22#include <com/sun/star/drawing/Position3D.hpp>
37typedef std::pair< double, double > tPointType;
38typedef std::vector< tPointType > tPointVecType;
39typedef tPointVecType::size_type lcl_tSizeType;
41class lcl_SplineCalculation
55 lcl_SplineCalculation( tPointVecType && rSortedPoints,
56 double fY1FirstDerivation,
57 double fYnFirstDerivation );
65 explicit lcl_SplineCalculation( tPointVecType && rSortedPoints);
73 double GetInterpolatedValue(
double x );
112 void CalculatePeriodic();
115lcl_SplineCalculation::lcl_SplineCalculation(
116 tPointVecType && rSortedPoints,
117 double fY1FirstDerivation,
118 double fYnFirstDerivation )
120 m_fYp1( fY1FirstDerivation ),
121 m_fYpN( fYnFirstDerivation ),
129lcl_SplineCalculation::lcl_SplineCalculation(
130 tPointVecType && rSortedPoints)
141void lcl_SplineCalculation::Calculate()
148 std::vector< double >
u( n );
151 if( std::isinf(
m_fYp1 ) )
161 u[ 0 ] = ( 3.0 / xDiff ) *
165 for( lcl_tSizeType i = 1;
i <
n; ++
i )
172 double sig = ( p_i.first - p_im1.first ) /
173 ( p_ip1.first - p_im1.first );
178 ( ( p_ip1.second - p_i.second ) /
179 ( p_ip1.first - p_i.first ) ) -
180 ( ( p_i.second - p_im1.second ) /
181 ( p_i.first - p_im1.first ) );
183 ( 6.0 *
u[
i ] / ( p_ip1.first - p_im1.first )
184 - sig * u[ i - 1 ] ) /
p;
192 if( ! std::isinf(
m_fYpN ) )
196 un = ( 3.0 / xDiff ) *
205 for( lcl_tSizeType k = n; k > 0; --k )
211void lcl_SplineCalculation::CalculatePeriodic()
221 std::vector< double >
u( n + 1, 0.0 );
227 std::vector< double > Adiag( n + 1, 0.0 );
230 std::vector< double > Aupper( n + 1, 0.0 );
233 std::vector< double > Ddiag( n+1, 0.0 );
236 std::vector< double > Rright( n-1, 0.0 );
239 std::vector< double > Rupper( n, 0.0 );
248 double xDiff2p1 = xDiff2 + xDiff1;
249 double xDiff0p2 = xDiff0 + xDiff2;
250 double xDiff1p0 = xDiff1 + xDiff0;
251 double fFactor = 1.5 / (xDiff0*xDiff1 + xDiff1*xDiff2 + xDiff2*xDiff0);
255 m_aSecDerivY[ 1 ] = fFactor * (yDiff1*xDiff2p1 - yDiff0*xDiff0p2);
256 m_aSecDerivY[ 2 ] = fFactor * (yDiff2*xDiff0p2 - yDiff1*xDiff1p0);
257 m_aSecDerivY[ 3 ] = fFactor * (yDiff0*xDiff1p0 - yDiff2*xDiff2p1);
265 double fHelp = 3.0 * (
m_aPoints[ 0 ].second -
m_aPoints[ 1 ].second) / (xDiff0*xDiff1);
278 double xDiff_im1 =1.0;
279 double yDiff_i = 1.0;
280 double yDiff_im1 = 1.0;
282 for( lcl_tSizeType i=1;
i<
n; ++
i )
288 Adiag[
i ] = 2 * (xDiff_im1 + xDiff_i);
289 Aupper[
i ] = xDiff_i;
290 u [
i ] = 3 * (yDiff_i - yDiff_im1);
296 Adiag[
n ] = 2 * (xDiff_im1 + xDiff_i);
297 Aupper[
n ] = xDiff_i;
298 u [
n ] = 3 * (yDiff_i - yDiff_im1);
302 Rupper[1] = Aupper[1] / Ddiag[1];
303 Rright[1] = Aupper[
n] / Ddiag[1];
304 for( lcl_tSizeType i=2;
i<=
n-2; ++
i )
306 Ddiag[
i] = Adiag[
i] - Aupper[
i-1 ] * Rupper[
i-1 ];
307 Rupper[
i ] = Aupper[
i ] / Ddiag[
i ];
308 Rright[
i ] = - Rright[
i-1 ] * Aupper[
i-1 ] / Ddiag[
i ];
310 Ddiag[
n-1 ] = Adiag[
n-1 ] - Aupper[
n-2 ] * Rupper[
n-2 ];
311 Rupper[
n-1 ] = ( Aupper[
n-1 ] - Aupper[
n-2 ] * Rright[
n-2] ) / Ddiag[ n-1 ];
313 for ( lcl_tSizeType i=1;
i<=
n-2; ++
i )
315 fSum += Ddiag[
i ] * Rright[
i ] * Rright[
i ];
317 Ddiag[
n ] = Adiag[
n ] - fSum - Ddiag[
n-1 ] * Rupper[
n-1 ] * Rupper[
n-1 ];
320 for ( lcl_tSizeType i=2;
i<=
n-1; ++
i )
322 u[
i ] -=
u[
i-1 ]* Rupper[
i-1 ];
325 for ( lcl_tSizeType i=1;
i<=
n-2; ++
i )
327 fSum += Rright[
i ] *
u[
i ];
329 u[
n ] =
u[
n ] - fSum - Rupper[
n - 1] *
u[
n-1 ];
332 for ( lcl_tSizeType i=1;
i<=
n; ++
i )
334 u[
i ] =
u[
i] / Ddiag[
i ];
340 for ( lcl_tSizeType i=n-2;
i>=1; --
i)
349 for( lcl_tSizeType i = 0;
i <=
n ; ++
i )
356double lcl_SplineCalculation::GetInterpolatedValue(
double x )
358 OSL_PRECOND( (
m_aPoints[ 0 ].first <= x ) &&
360 "Trying to extrapolate" );
387 OSL_ENSURE(
m_nKHigh <= n,
"Out of Bounds" );
392 OSL_ENSURE( h != 0,
"Bad input to GetInterpolatedValue()" );
407bool createParameterT(
const tPointVecType& rUniquePoints,
double* t)
410 bool bIsSuccessful =
true;
411 const lcl_tSizeType
n = rUniquePoints.size() - 1;
413 double fDenominator = 0.0;
414 for (lcl_tSizeType i=1;
i<=
n ; ++
i)
416 double dx = rUniquePoints[
i].first - rUniquePoints[
i-1].first;
417 double dy = rUniquePoints[
i].second - rUniquePoints[
i-1].second;
418 if (dx == 0 && dy == 0)
420 bIsSuccessful =
false;
425 fDenominator += sqrt(std::hypot(dx, dy));
428 if (fDenominator == 0.0)
430 bIsSuccessful =
false;
434 for (lcl_tSizeType j=1; j<=
n ; ++j)
436 double fNumerator = 0.0;
437 for (lcl_tSizeType i=1;
i<=j ; ++
i)
439 double dx = rUniquePoints[
i].first - rUniquePoints[
i-1].first;
440 double dy = rUniquePoints[
i].second - rUniquePoints[
i-1].second;
441 fNumerator += sqrt(std::hypot(dx, dy));
443 t[j] = fNumerator / fDenominator;
448 double fPrevious = 0.0;
449 for (lcl_tSizeType i=1;
i <=
n && bIsSuccessful ; ++
i)
451 if (fPrevious >= t[i])
453 bIsSuccessful =
false;
461 return bIsSuccessful;
464void createKnotVector(
const lcl_tSizeType n,
const sal_uInt32 p,
const double* t,
double* u)
466 for (lcl_tSizeType j = 0; j <=
p; ++j)
470 for (lcl_tSizeType j = 1; j <=
n-
p; ++j )
473 for (lcl_tSizeType i = j;
i <= j+
p-1; ++
i)
480 for (lcl_tSizeType j = n+1; j <=
n+1+
p; ++j)
486void applyNtoParameterT(
const lcl_tSizeType i,
const double tk,
const sal_uInt32 p,
const double* u,
double* rowN)
494 for (sal_uInt32 s = 1; s <=
p; ++s)
497 double fLeftFactor = 0.0;
498 double fRightFactor = (
u[
i+1] - tk ) / ( u[i+1]- u[i-s+1] );
500 rowN[
p-s] = fRightFactor * rowN[
p-s+1];
503 for (sal_uInt32 j = s-1; j>=1 ; --j)
505 fLeftFactor = ( tk -
u[
i-j] ) / ( u[i-j+s] - u[i-j] ) ;
506 fRightFactor = (
u[
i-j+s+1] - tk ) / ( u[i-j+s+1] - u[i-j+1] );
508 rowN[
p-j] = fLeftFactor * rowN[
p-j] + fRightFactor * rowN[
p-j+1];
512 fLeftFactor = ( tk -
u[
i] ) / ( u[i+s] - u[i] );
514 rowN[
p] = fLeftFactor * rowN[
p];
522void SplineCalculater::CalculateCubicSplines(
523 const std::vector<std::vector<css::drawing::Position3D>>& rInput
524 , std::vector<std::vector<css::drawing::Position3D>>& rResult
525 , sal_uInt32 nGranularity )
527 OSL_PRECOND( nGranularity > 0,
"Granularity is invalid" );
529 sal_uInt32 nOuterCount = rInput.size();
531 rResult.resize(nOuterCount);
533 auto pSequence = rResult.data();
538 for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter )
540 if( rInput[nOuter].
size() <= 1 )
543 sal_uInt32 nMaxIndexPoints = rInput[nOuter].size()-1;
544 const css::drawing::Position3D* pOld = rInput[nOuter].data();
546 std::vector < double > aParameter(nMaxIndexPoints+1);
554 tPointVecType aInputX;
555 aInputX.resize(nMaxIndexPoints+1);
556 tPointVecType aInputY;
557 aInputY.resize(nMaxIndexPoints+1);
558 tPointVecType aInputZ;
559 aInputZ.resize(nMaxIndexPoints+1);
560 for (sal_uInt32 nN=0;nN<=nMaxIndexPoints; nN++ )
562 aInputX[ nN ].first=aParameter[nN];
563 aInputX[ nN ].second=pOld[ nN ].PositionX;
564 aInputY[ nN ].first=aParameter[nN];
565 aInputY[ nN ].second=pOld[ nN ].PositionY;
566 aInputZ[ nN ].first=aParameter[nN];
567 aInputZ[ nN ].second=pOld[ nN ].PositionZ;
572 std::unique_ptr<lcl_SplineCalculation> aSplineX;
573 std::unique_ptr<lcl_SplineCalculation> aSplineY;
578 if( pOld[ 0 ].PositionX == pOld[nMaxIndexPoints].PositionX &&
579 pOld[ 0 ].PositionY == pOld[nMaxIndexPoints].PositionY &&
580 pOld[ 0 ].PositionZ == pOld[nMaxIndexPoints].PositionZ &&
581 nMaxIndexPoints >=2 )
583 aSplineX = std::make_unique<lcl_SplineCalculation>(std::move(aInputX));
584 aSplineY = std::make_unique<lcl_SplineCalculation>(std::move(aInputY));
588 double fXDerivation = std::numeric_limits<double>::infinity();
589 double fYDerivation = std::numeric_limits<double>::infinity();
590 aSplineX = std::make_unique<lcl_SplineCalculation>(std::move(aInputX), fXDerivation, fXDerivation);
591 aSplineY = std::make_unique<lcl_SplineCalculation>(std::move(aInputY), fYDerivation, fYDerivation);
595 pSequence[nOuter].resize( nMaxIndexPoints*nGranularity + 1);
597 css::drawing::Position3D* pNew = pSequence[nOuter].data();
599 sal_uInt32 nNewPointIndex = 0;
601 for( sal_uInt32 ni = 0; ni < nMaxIndexPoints; ni++ )
604 pNew[nNewPointIndex].PositionX = pOld[ni].PositionX;
605 pNew[nNewPointIndex].PositionY = pOld[ni].PositionY;
606 pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ;
610 double fInc = ( aParameter[ ni+1 ] - aParameter[ni] ) /
static_cast< double >( nGranularity );
611 for(sal_uInt32 nj = 1; nj < nGranularity; nj++)
613 double fParam = aParameter[ni] + ( fInc *
static_cast< double >( nj ) );
615 pNew[nNewPointIndex].PositionX = aSplineX->GetInterpolatedValue( fParam );
616 pNew[nNewPointIndex].PositionY = aSplineY->GetInterpolatedValue( fParam );
618 pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ;
623 pNew[nNewPointIndex] = pOld[nMaxIndexPoints];
627void SplineCalculater::CalculateBSplines(
628 const std::vector<std::vector<css::drawing::Position3D>>& rInput
629 , std::vector<std::vector<css::drawing::Position3D>>& rResult
630 , sal_uInt32 nResolution
631 , sal_uInt32 nDegree )
637 OSL_ASSERT( nResolution > 1 );
638 OSL_ASSERT( nDegree >= 1 );
641 sal_uInt32
p = std::min<sal_uInt32>(nDegree, 15);
643 sal_Int32 nOuterCount = rInput.size();
645 rResult.resize(nOuterCount);
647 auto pSequence = rResult.data();
652 for( sal_Int32 nOuter = 0; nOuter < nOuterCount; ++nOuter )
654 if( rInput[nOuter].
size() <= 1 )
660 lcl_tSizeType nMaxIndexPoints = rInput[nOuter].size()-1;
661 const css::drawing::Position3D* pOld = rInput[nOuter].data();
662 double fZCoordinate = pOld[0].PositionZ;
663 tPointVecType aPointsIn;
664 aPointsIn.resize(nMaxIndexPoints+1);
665 for (lcl_tSizeType
i = 0;
i <= nMaxIndexPoints; ++
i )
667 aPointsIn[
i ].first = pOld[
i].PositionX;
668 aPointsIn[
i ].second = pOld[
i].PositionY;
670 aPointsIn.erase( std::unique( aPointsIn.begin(), aPointsIn.end()),
675 const lcl_tSizeType
n = aPointsIn.size() - 1;
680 std::vector<double>
t(
n + 1);
681 if (!createParameterT(aPointsIn,
t.data()))
686 lcl_tSizeType
m =
n +
p + 1;
687 std::vector<double>
u(
m + 1);
688 createKnotVector(
n,
p,
t.data(),
u.data());
695 std::vector<std::vector<double>> aMatN(
n + 1, std::vector<double>(
p + 1));
696 std::vector<lcl_tSizeType> aShift(
n + 1);
701 for (lcl_tSizeType k = 1; k<=
n-1; ++k)
708 while (
u[
i] >
t[k] ||
t[k] >=
u[
i+1])
716 applyNtoParameterT(
i,
t[k],
p,
u.data(), aMatN[k].data());
724 double fDivisor = 1.0;
725 double fEliminate = 1.0;
726 bool bIsSuccessful =
true;
727 for (c = 0 ; c <=
n && bIsSuccessful; ++c)
731 while ( r <
n && aMatN[r][c-aShift[r]] == 0 )
735 if (aMatN[r][c-aShift[r]] == 0.0)
738 bIsSuccessful =
false;
745 std::swap( aMatN[r], aMatN[c] );
746 std::swap( aPointsIn[r], aPointsIn[c] );
747 std::swap( aShift[r], aShift[c] );
751 fDivisor = aMatN[c][c-aShift[c]];
752 for (sal_uInt32
i = 0;
i <=
p; ++
i)
754 aMatN[c][
i] /= fDivisor;
756 aPointsIn[c].first /= fDivisor;
757 aPointsIn[c].second /= fDivisor;
762 for ( r = c+1; r <
n && aShift[r]<=c ; ++r)
764 fEliminate = aMatN[r][0];
765 if (fEliminate != 0.0)
767 for (sal_uInt32
i = 1;
i <=
p; ++
i)
769 aMatN[r][
i-1] = aMatN[r][
i] - fEliminate * aMatN[c][
i];
772 aPointsIn[r].first -= fEliminate * aPointsIn[c].first;
773 aPointsIn[r].second -= fEliminate * aPointsIn[c].second;
782 for (lcl_tSizeType cc =
n; cc >= 1; --cc )
789 while ( r !=0 && cc-r <
p )
791 fEliminate = aMatN[r][ cc - aShift[r] ];
792 if ( fEliminate != 0.0)
795 aMatN[r][cc - aShift[r]] = 0.0;
796 aPointsIn[r].first -= fEliminate * aPointsIn[cc].first;
797 aPointsIn[r].second -= fEliminate * aPointsIn[cc].second;
806 lcl_tSizeType nNewSize = nResolution *
n + 1;
807 pSequence[nOuter].resize(nNewSize);
808 css::drawing::Position3D* pNew = pSequence[nOuter].data();
809 pNew[0].PositionX = aPointsIn[0].first;
810 pNew[0].PositionY = aPointsIn[0].second;
811 pNew[0].PositionZ = fZCoordinate;
812 pNew[nNewSize -1 ].PositionX = aPointsIn[
n].first;
813 pNew[nNewSize -1 ].PositionY = aPointsIn[
n].second;
814 pNew[nNewSize -1 ].PositionZ = fZCoordinate;
815 std::vector<double> aP(
m + 1);
816 lcl_tSizeType nLow = 0;
817 for ( lcl_tSizeType nTIndex = 0; nTIndex <=
n-1; ++nTIndex)
819 for (sal_uInt32 nResolutionStep = 1;
820 nResolutionStep <= nResolution && ( nTIndex !=
n-1 || nResolutionStep != nResolution);
823 lcl_tSizeType nNewIndex = nTIndex * nResolution + nResolutionStep;
824 double ux =
t[nTIndex] + nResolutionStep * (
t[nTIndex+1] -
t[nTIndex]) /nResolution;
828 while (
u[nLow] <= ux)
835 for (lcl_tSizeType
i = nLow-
p;
i <= nLow; ++
i)
837 aP[
i] = aPointsIn[
i].first;
839 for (sal_uInt32 lcl_Degree = 1; lcl_Degree <=
p; ++lcl_Degree)
841 for (lcl_tSizeType
i = nLow;
i >= nLow + lcl_Degree -
p; --
i)
843 double fFactor = ( ux -
u[
i] ) / (
u[
i+
p+1-lcl_Degree] -
u[
i]);
844 aP[
i] = (1 - fFactor)* aP[
i-1] + fFactor * aP[
i];
847 pNew[nNewIndex].PositionX = aP[nLow];
850 for (lcl_tSizeType
i = nLow -
p;
i <= nLow; ++
i)
852 aP[
i] = aPointsIn[
i].second;
854 for (sal_uInt32 lcl_Degree = 1; lcl_Degree <=
p; ++lcl_Degree)
856 for (lcl_tSizeType
i = nLow;
i >= nLow +lcl_Degree -
p; --
i)
858 double fFactor = ( ux -
u[
i] ) / (
u[
i+
p+1-lcl_Degree] -
u[
i]);
859 aP[
i] = (1 - fFactor)* aP[
i-1] + fFactor * aP[
i];
862 pNew[nNewIndex].PositionY = aP[nLow];
863 pNew[nNewIndex].PositionZ = fZCoordinate;
tPointVecType m_aPoints
a copy of the points given in the CTOR
std::vector< double > m_aSecDerivY
the result of the Calculate() method
double m_fLastInterpolatedValue