Monday, February 26, 2018

DELPHI - How make Catmull-Rom spline (interpolation)

function TForm1.GetCatmull_RomProc( _iT : double; _p0, _p1, _p2, _p3 : double ) : double;
begin
  result := 0.5 * ( ( 2 * _p1 ) +
                    ( ( ( -1 * _p0 ) + _p2 ) * _iT ) +
                    ( ( ( 2 * _p0 ) - ( 5 * _p1 ) + ( 4 * _p2 ) - _p3 ) * _iT * _iT ) +
                    ( ( ( - 1 * _p0 ) + ( 3 * _p1 ) - ( 3 * _p2 ) + _p3 ) * _iT * _iT * _iT )
                  );
end;

{ ---------------------------------------------------------------------------
  Catmull-Rom interpolation curve.
  -------------------------------------------------------------------------- }
procedure TForm1.Catmull_Rom;
var
  j, i, iIndex : integer;
  iNumSegmentsCount : integer;
  iT, i1_T, iP0, iP1, iP2, iP3 : double;
  iNewX, iNewY : double;
  pSerieLine : TLineSeries;
  iValue : extended;
  pNewX, pNewY : TVariable;
begin
  pNewX := TVariable.Create;
  pNewY := TVariable.Create;

  for i := 0 to pX.Count - 1 do
    begin
      pX.CopyTo( pNewX );
      pY.CopyTo( pNewY );
    end;

  { first and last point again }
  pNewX.InsertValue( 0, pNewx.GetValue( 0 ) );
  pNewY.InsertValue( 0, pNewy.GetValue( 0 ) );

  pNewX.InsertValue( pNewX.Count - 1, pNewx.GetValue( pNewX.Count - 1 ) );
  pNewY.InsertValue( pNewY.Count - 1, pNewy.GetValue( pNewY.Count - 1 ) );

  pSerieLine := TLineSeries( Chart1.Series[1] );
  pSerieLine.Clear;

  { draw count of cubic curves }
  for iIndex := 0 to pNewX.Count - 4 do
    begin

       { every curve generate from I parts }
       for i := 0 to giDetail - 1 do
         begin
           iT := i / (giDetail-1);
           i1_T := 1 - iT;

           iNewX := GetCatmull_RomProc( iT, pNewx.GetValue( iIndex ), 
                                        pNewx.GetValue( iIndex + 1 ),
                                        pNewx.GetValue( iIndex + 2 ), 
                                        pNewx.GetValue( iIndex + 3 )
                                      );

           iNewY := GetCatmull_RomProc( iT, pNewy.GetValue( iIndex ), 
                                        pNewy.GetValue( iIndex + 1 ),
                                        pNewy.GetValue( iIndex + 2 ), 
                                        pNewy.GetValue( iIndex + 3 )
                                      );

           pSerieLine.AddXY( iNewX, iNewY );
         end;

  end;

  pNewX.Free;
  pNewY.Free;
end;

1 comment:

  1. Look also very good, but it does not compile either.

    ReplyDelete