teespline.pas

来自「Delphi TeeChartPro.6.01的源代码」· PAS 代码 · 共 522 行 · 第 1/2 页

PAS
522
字号
        Matrix[I]^[I-1]:=1/6;
        Matrix[I]^[I]:=2/3;
        Matrix[I]^[I+1]:=1/6;
      end;

      Matrix[1]^[1]:=1;
      Matrix[FNoVertices]^[FNoVertices]:=1;

      I:=3;
      while I<FNoVertices-1 do
      begin
        if (Abs(FVertexList^[I].X-FVertexList^[I-1].X)<MinLimit) and
           (Abs(FVertexList^[I+1].X-FVertexList^[I].X)<MinLimit) and
           (Abs(FVertexList^[I].Y-FVertexList^[I-1].Y)<MinLimit) and
           (Abs(FVertexList^[I+1].Y-FVertexList^[I].Y)<MinLimit) then
        begin
          for J:=I-1 to I+1 do
          begin
            Matrix[J]^[J-1]:=0;
            Matrix[J]^[J]:=1;
            Matrix[J]^[J+1]:=0;
          end;

          Inc(I,2);
        end
        else Inc(I);
      end;
    end;
  end;


var I,J      : integer;
    Vertex2D : TVertex;
begin
  if FNoPoints>1 then
  begin
    ClearVertexList;
    FNoVertices:=0;

    for i:=1 to FNoPoints do
        if Knuckle[I] then Inc(FNoVertices,3)
                      else Inc(FNoVertices,1);

    GetMem(FVertexList,(FNoVertices+2)*SizeOf(TVertex));

    J:=0;
    for i:=1 to FNoPoints do
    begin
      Vertex2D:=Point[I];
      if Knuckle[I] then
      begin
        FVertexList^[J+1]:=Vertex2D;
        FVertexList^[J+2]:=Vertex2D;
        Inc(J,2);
      end;
      FVertexList^[J+1]:=FPointList^[I];
      Inc(J);
    end;

    if Interpolated then
    begin
      for i:=1 to FNoVertices do
      begin
        GetMem(Matrix[I],FNoVertices*SizeOf(TDatatype));
        FillChar(Matrix[I]^,FNoVertices*SizeOf(TDatatype),0);
      end;

      FillMatrix;
      Finterpolate;

      for i:=1 to FNoVertices do
      begin
        FreeMem(Matrix[I],FNoVertices*SizeOf(TDatatype));
        Matrix[I]:=nil;
      end;
    end;
  end;
  FBuild:=true;
  FPhantomPoints;
end;

procedure TBSpline.FInterpolate;
var I,J,K  : Integer;
    Factor : TDataType;
    Tmp    : P2DVertexList;
begin
  if (FNoVertices<MaxInterpolatedVertices) and (FNoVertices>2) then
  begin
    GetMem(Tmp,(FNoVertices+2)*SizeOf(TVertex));

    for i:=1 to FNoVertices do
      for J:=I+1 to FNoVertices do
      begin
        factor:=Matrix[J]^[I]/Matrix[I]^[I];
        for K:=1 to FNoVertices do
            Matrix[J]^[K]:=Matrix[J]^[K]-factor*Matrix[I]^[K];
        FVertexList^[J].x:=FVertexList^[J].x-factor*FVertexList^[J-1].x;
        FVertexList^[J].y:=FVertexList^[J].y-factor*FVertexList^[J-1].y;
      end;

    Tmp^[FNoVertices].x:=FVertexList^[FNoVertices].x/Matrix[FNoVertices]^[FNoVertices];
    Tmp^[FNoVertices].y:=FVertexList^[FNoVertices].y/Matrix[FNoVertices]^[FNoVertices];

    for I:=FNoVertices-1 downto 1 do
    begin
      Tmp^[I].x:=(1/Matrix[I]^[I])*(FVertexList^[I].x-Matrix[I]^[I+1]*Tmp^[I+1].x);
      Tmp^[I].y:=(1/Matrix[I]^[I])*(FVertexList^[I].y-Matrix[I]^[I+1]*Tmp^[I+1].y);
    end;

    ClearVertexList;
    FVertexList:=Tmp;
  end;
end;

procedure TBSpline.AddPoint(const X,Y:Double);
var Vertex : TVertex;
begin
  if FNoPoints=FCapacity then FSetCapacity(FCapacity+VerticesIncrement);
  Inc(FNoPoints);
  Vertex.X:=X;
  Vertex.Y:=Y;
  Point[FNoPoints]:=Vertex;
  Build:=false;
end;

procedure TBSpline.ClearVertexList;
begin
  if Assigned(FVertexList) then
  begin
    FreeMem(FVertexList,(FNoVertices+2)*SizeOf(TVertex));
    FVertexList:=nil;
  end;
end;

procedure TBSpline.Clear;
begin
  if NumberOfVertices>0 then ClearVertexList;
  FNoPoints:=0;
  FNoVertices:=0;
  Build:=False;
  FSetCapacity(0);
  FInterpolated:=False;
  FFragments:=100;
end;

procedure TBSpline.FPhantomPoints;
var I : integer;
begin
  if NumberOfVertices>1 then
  begin
    I:=0;
    FVertexList^[I].X:=2*FVertexList^[I+1].X-FVertexList^[I+2].X;
    FVertexList^[I].Y:=2*FVertexList^[I+1].Y-FVertexList^[I+2].Y;
    FVertexList^[NumberOfVertices+1].X:=2*FVertexList^[NumberOfVertices].X-FVertexList^[NumberOfVertices-1].X;
    FVertexList^[NumberOfVertices+1].Y:=2*FVertexList^[NumberOfVertices].Y-FVertexList^[NumberOfVertices-1].Y;
  end;
end;

function TBSpline.Value(const Parameter:TDataType):TVertex;
var c,S,E : integer;
    Dist  : TDataType;
    Mix   : TDataType;
    Mid   : TDataType;
begin
  result.X:=0;
  result.Y:=0;

  if FNoPoints<2 then Exit;

  if not FBuild then Rebuild;

  Mid:=(NumberOfVertices-1)*Parameter+1;
  S:=Trunc(Mid-1);
  if S<0 then S:=0;
  E:=S+3;
  if S>FNovertices+1 then S:=FNovertices+1;

  for c:=S to E do
  begin
    dist:=Abs(C-Mid);
    if dist<2 then
    begin
      if dist<1 then mix:=4/6-dist*dist+0.5*dist*dist*dist
                else mix:=(2-dist)*(2-dist)*(2-dist)/6;
      result.x:=Result.x+FVertexList^[c].x*mix;
      result.y:=Result.y+FVertexList^[c].y*mix;
    end;
  end;
end;

{ TSmoothingFunction }
constructor TSmoothingFunction.Create(AOwner: TComponent);
begin
  inherited;
  CanUsePeriod:=False;
  SingleSource:=True;
  FInterpolate:=True;
  FFactor:=4;
  InternalSetPeriod(1);
end;

procedure TSmoothingFunction.AddPoints(Source: TChartSeries);
var BSpline : TBSpline;
    t       : Integer;
    tmpList : TChartValueList;
begin
  BSpline:=TBSpline.Create;
  try
    ParentSeries.Clear;
    if Source.Count>0 then
    begin
      tmpList:=ValueList(Source);
      With Source do
      for t:=0 to Count-1 do
      begin
        BSpline.AddPoint(XValues.Value[t],tmpList.Value[t]);
        BSpline.Knuckle[t]:=False;
      end;
      BSpline.Interpolated:=Interpolate;
      BSpline.Fragments:=Source.Count*Factor;

      with BSpline do
      for t:=0 to Fragments do
          with Value(t/Fragments) do
               if ParentSeries.YMandatory then ParentSeries.AddXY(X,Y)
                                          else ParentSeries.AddXY(Y,X);
    end;
  finally
    BSpline.Free;
  end;
end;

procedure TSmoothingFunction.SetFactor(const Value: Integer);
begin
  if FFactor<>Value then
  begin
    FFactor:=Math.Max(1,Value);
    Recalculate;
  end;
end;

procedure TSmoothingFunction.SetInterpolate(const Value: Boolean);
begin
  if FInterpolate<>Value then
  begin
    FInterpolate:=Value;
    Recalculate;
  end;
end;

class function TSmoothingFunction.GetEditorClass: String;
begin
  result:='TSmoothFuncEditor';
end;

initialization
  RegisterTeeFunction( TSmoothingFunction, @TeeMsg_FunctionSmooth, @TeeMsg_GalleryExtended );
finalization
  UnRegisterTeeFunctions([TSmoothingFunction]);
end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?