我的图形系统现欲增加BSpline、BezierCurve、NURBSpline几种曲线,要求能够实现以地图数据(Double类型)的存储、地图坐标转画布坐标、画布坐标转地图坐标、图形的绘制、图形的点选、取得图形的最大矩形、向Polyline图形的转换。
急!!恳请各位高手帮忙!!

解决方案 »

  1.   

    我找到了NURBS曲线的实现算法,经修改,形成TAnyNurbs类。我的实现代码如下:unit AnyNurbs;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      AnyFramework, AnyXYs, Any32, AnyGlobalConsts, AnyDevice;type
      TAnyNurbsFrameData=class(TAnyShapeFrameData)
      private
        FPoints: TMapPointList;
        FDegree: Integer;
        function B(HighIndex, i, k:Integer; t:Double):Double;
        function tknot(HighIndex, i:Integer):Double;
        function NURBS(HighIndex, k:Integer; t:Double):TAny2DPoint;
        function Pt_Mul(const Pt:TAny2DPoint; S:Double):TAny2DPoint;
        procedure Pt_Add(var Pt:TAny2DPoint; const V:TAny2DPoint);
        procedure DoPartBoundsChanged(Sender:TObject);
      public
        constructor Create; override;
        destructor Destroy; override;
        function GetAdvanceBoundsRect:TAnyRect;
        procedure CopyFrom(Source: TAnyShapeFrameData); override;
        procedure ForwardSynchronize(OldBounds, NewBounds:TAnyBounds); override;
        procedure DefaultBackwardSynchronize; override;
        property Points:TMapPointList read FPoints;
        property Degree:Integer read FDegree write FDegree;
      end;  TAnyNurbsSelector=class(TAnySingleSelector)
      private
        HotPoint:TAnyHotPointInst;
        PartIndex, PointIndex:Integer;
      protected
        function GetHotPoint(X, Y: Integer):TAnyHotPointInst; override;
        function GetHotPoint2(const PartIndex, PointIndex:Integer):TAnyHotPointInst;
        procedure DoPointDragMove(Sender:TObject; X, Y, W:Integer;
          mX, mY, mW: Double); virtual;
        procedure SetShape(const Value: TAnyCustomShape); override;
        procedure SetShareData(const Value: TAnyShareData); override;
      public
        constructor Create; override;
        destructor Destroy; override;
        procedure Draw; override;
        procedure FitToShape; override;
      end;
      
      TAnyNurbs=class(TAnySingleShape)
      private
        function GetLocalData: TAnyNurbsFrameData;
        function GetPoints: TMapPointList;
        procedure DoOnBackwardSynchronize(Sender:TObject);
        procedure DrawShape(Data:TAnyNurbsFrameData);
      protected
        function GetFrameDataClass:TAnyShapeFrameDataClass; override;
        function GetSingleSelectorClass:TAnySingleSelectorClass; override;
        function GetRMCenter: TAny2DPoint; override;
        procedure InternalDraw; override;
        procedure TrackDraw(const IsClear:Boolean); override;
        property LocalData:TAnyNurbsFrameData read GetLocalData;
      public
        //------------------------------------------------------------------------//
        constructor Create; override;
        procedure Assign(Source:TAnyShape); override;
        //------------------------------------------------------------------------//
        class function ClassID:Byte; override;
        //------------------------------------------------------------------------//
        procedure dxfWrite(var F: TextFile); override;
        procedure LoadFromStream(Stream:TStream); override;
        procedure SaveToStream(Stream:TStream); override;
        //------------------------------------------------------------------------//
        function SelectedAt(X, Y, W: Double):Boolean; override;
        //------------------------------------------------------------------------//
        {点集列表,相对于父图元}
        property Points:TMapPointList read GetPoints;
        //------------------------------------------------------------------------//
      end;var
      NurbsClassIndex:Integer;
      
    implementationuses
      GraphicsTools, StreamIOAPIs, U_Form_CustomConfig;
      
    { TAnyNurbsFrameData }function TAnyNurbsFrameData.B(HighIndex, i, k: Integer;
      t: Double): Double;
    var
      b1, b2, dt:Double;
    begin
    if (k = 1) then
        begin
    if ((tknot(HighIndex, i) <= t) and (t < tknot(HighIndex, i + 1))) then
    Result:=1
    else
    Result:=0;
          Exit;
    end; b1 := B(HighIndex, i, k - 1, t);
    dt := (tknot(HighIndex, i + k - 1) - tknot(HighIndex, i));
    if (dt > 0.00001) then
    b1 :=b1 / dt
    else
    b1 := 0; b2 := B(HighIndex, i + 1, k - 1, t);
    dt := (tknot(HighIndex, i + k) - tknot(HighIndex, i + 1));
    if (dt > 0.000001) then
    b2 := b2 / dt
    else
    b2 := 0; Result := ((t - tknot(HighIndex, i)) * b1 + (tknot(HighIndex, i + k) - t) * b2);
    end;procedure TAnyNurbsFrameData.CopyFrom(Source: TAnyShapeFrameData);
    var
      ANurbsFrameData:TAnyNurbsFrameData;
    begin
      inherited CopyFrom(Source);
      if Source is TAnyNurbsFrameData then
      begin
        ANurbsFrameData:=TAnyNurbsFrameData(Source);
        Points.CopyFrom(ANurbsFrameData.Points);
      end;
    end;constructor TAnyNurbsFrameData.Create;
    begin
      inherited;
      FPoints:=TMapPointList.Create;
      FPoints.OnBoundsChanged:=DoPartBoundsChanged;
      FDegree:=4;
    end;procedure TAnyNurbsFrameData.DefaultBackwardSynchronize;
    var
      BRect:TAnyRect;
    begin
      BRect:=GetAdvanceBoundsRect;
      Self.SetMapBounds(BRect, False);
    end;destructor TAnyNurbsFrameData.Destroy;
    begin
      FPoints.Free;
      inherited Destroy;
    end;procedure TAnyNurbsFrameData.DoPartBoundsChanged(Sender: TObject);
    begin
      BackwardSynchronize;
    end;procedure TAnyNurbsFrameData.ForwardSynchronize(OldBounds,
      NewBounds: TAnyBounds);
    var
      i:Integer;
      XScale, YScale:Double;
    begin
      if OldBounds.Width=0 then
        XScale:=1
      else
        XScale:=NewBounds.Width/OldBounds.Width;
      if OldBounds.Height=0 then
        YScale:=1
      else
        YScale:=NewBounds.Height/OldBounds.Height;
      for i:=0 to Points.Count-1 do
        with Points.Items[i]^ do
        begin
          X:=NewBounds.XMin+XScale*(X-OldBounds.XMin);
          Y:=NewBounds.YMin+YScale*(Y-OldBounds.YMin);
        end;
    end;function TAnyNurbsFrameData.GetAdvanceBoundsRect: TAnyRect;
    var
      i:Integer;
      n:Integer;
      pt:TAny2DPoint;
    begin
      if Points.Count=0 then
      begin
        Result:=GeoRect(0, 0, 0, 0);
        Exit;
      end;
      n:=Points.Count-1;
      pt := NURBS(n, Degree, 0);
      Result:=GeoRect(pt.X, pt.Y, pt.X, pt.Y);
      for i:=1 to (n - Degree + 2) * 10 do
      begin
        pt := NURBS(n, Degree, i / 10);
        if Result.XMin>pt.X then
          Result.XMin:=pt.X;
        if Result.YMin>pt.Y then
          Result.YMin:=pt.Y;
        if Result.XMax<pt.X then
          Result.XMax:=pt.X;
        if Result.YMax<pt.Y then
          Result.YMax:=pt.Y;
      end;
    end;function TAnyNurbsFrameData.NURBS(HighIndex, k:Integer; t:Double): TAny2DPoint;
    var
      i:Integer;
      ws, ww:Double;
      rt:TAny2DPoint;
    begin
      ws := 0;
      rt := Geo2DPoint(0, 0);
      for i:=0 to HighIndex do
      begin
        ww := B(HighIndex, i, k, t);
        ws := ws + ww;
        Pt_Add(rt, Pt_Mul(Points.Items[i]^, ww));
      end;
      Result:=rt;
    end;
      

  2.   

    procedure TAnyNurbsFrameData.Pt_Add(var Pt: TAny2DPoint;
      const V: TAny2DPoint);
    begin
      Pt.X := Pt.X+V.X;
      Pt.Y := Pt.Y+V.Y;
    end;function TAnyNurbsFrameData.Pt_Mul(const Pt: TAny2DPoint;
      S: Double): TAny2DPoint;
    begin
      Result.X := Pt.X*S;
      Result.Y := Pt.Y*S;
    end;
    function TAnyNurbsFrameData.tknot(HighIndex, i: Integer): Double;
    begin
      if (i < Degree) then
      begin
        Result:=0;
        Exit;
      end;
      if (i > HighIndex) then
        Result:=(HighIndex - Degree + 2.00001)
      else
        Result:=(i - Degree + 1);
    end;{ TAnyNurbsSelector }constructor TAnyNurbsSelector.Create;
    begin
      inherited Create;
      HotPoint:=CreatePoint(crSizeAll, DoPointDragMove);
    end;destructor TAnyNurbsSelector.Destroy;
    begin
      HotPoint.Free;
      inherited Destroy;
    end;procedure TAnyNurbsSelector.DoPointDragMove(Sender: TObject; X, Y,
      W: Integer; mX, mY, mW: Double);
    var
      Pt:TAny2DPoint;
      TrackData:TAnyNurbsFrameData;
    begin
      Shape.ClearTrackFrame;
      TrackData:=TAnyNurbsFrameData(Shape.TrackData);
      Pt:=GetHotPointCenter(X, Y);
      TrackData.Points.EditXY(PointIndex, Pt.X, Pt.Y);
      Shape.DrawTrackFrame;
    end;procedure TAnyNurbsSelector.Draw;
    var
      i:Integer;
      ACanvas:TAnyMapCanvas;
    begin
      inherited;
      with TAnyNurbs(Shape) do
      begin
        ACanvas:=MapCanvas;    HotPoint.Center:=ParentClientToMap(Points.Items[0]^);
        ACanvas.Pen.Width:=1;
        ACanvas.Pen.Color:=clBlue;
        ACanvas.MoveTo(HotPoint.Center);
        HotPoint.Draw;    for i:=1 to Points.Count-1 do
        begin
          HotPoint.Center:=ParentClientToMap(Points.Items[i]^);
          ACanvas.Pen.Width:=1;
          ACanvas.Pen.Color:=clBlue;
          ACanvas.LineTo(HotPoint.Center);
          HotPoint.Draw;
        end;
      end;
    end;procedure TAnyNurbsSelector.FitToShape;
    begin
      //不处理,绘制时计算//
    end;function TAnyNurbsSelector.GetHotPoint(X, Y: Integer): TAnyHotPointInst;
    var
      i:Integer;
    begin
      with TAnyNurbs(Shape) do
      begin
        for i:=0 to Points.Count-1 do
        begin
          HotPoint.Center:=ParentClientToMap(Points.Items[i]^);
          if HotPoint.SelectedAt1(X, Y) then
          begin
            PartIndex:=0;
            PointIndex:=i;
            Result:=HotPoint;
            Exit;
          end;
        end;
      end;
      Result:=nil;
    end;function TAnyNurbsSelector.GetHotPoint2(const PartIndex,
      PointIndex: Integer): TAnyHotPointInst;
    begin
      HotPoint.Center:=TAnyNurbs(Shape).Points.Items[PointIndex]^;
      Result:=HotPoint;
    end;procedure TAnyNurbsSelector.SetShape(const Value: TAnyCustomShape);
    begin
      inherited SetShape(Value);
      if Shape<>nil then FitToShape;
    end;procedure TAnyNurbsSelector.SetShareData(const Value: TAnyShareData);
    begin
      inherited SetShareData(Value);
      HotPoint.Share:=ShareData.HotPoint;
    end;{ TAnyNurbs }procedure TAnyNurbs.Assign(Source: TAnyShape);
    begin
      inherited Assign(Source);
      if Source is TAnyNurbs then
        Points.Assign(TAnyNurbs(Source).Points);
    end;class function TAnyNurbs.ClassID: Byte;
    begin
      Result:=ID_CLASS_NURBS;
    end;constructor TAnyNurbs.Create;
    begin
      inherited Create;
      FrameData.OnBackwardSynchronize:=DoOnBackwardSynchronize;
    end;procedure TAnyNurbs.DoOnBackwardSynchronize(Sender: TObject);
    var
      BRect:TAnyRect;
    begin
      BRect:=LocalData.GetAdvanceBoundsRect;
      InternalSetMapBounds(BRect.XMin, BRect.YMin,
        BRect.XMax-BRect.XMin, BRect.YMax-BRect.YMin, False);
    end;procedure TAnyNurbs.DrawShape(Data: TAnyNurbsFrameData);
    var
      i:Integer;
      n:Integer;
      pt_s, pt_e:TAny2DPoint;
    begin
      n:=Data.Points.Count-1;
      if n<0 then Exit;
      with MapCanvas do
      begin
        pt_s := Parent.ClientToMap(Data.NURBS(n, Data.Degree, 0));
        MoveTo(pt_s.X, pt_s.Y);
        for i:=1 to (n - Data.Degree + 2) * 10 do
        begin
          pt_e := Parent.ClientToMap(Data.NURBS(n, Data.Degree, i / 10));
          LineTo(pt_e.X, pt_e.Y);
        end;
      end;
    end;procedure TAnyNurbs.dxfWrite(var F: TextFile);
    begin
      inherited;end;function TAnyNurbs.GetFrameDataClass: TAnyShapeFrameDataClass;
    begin
      Result:=TAnyNurbsFrameData;
    end;function TAnyNurbs.GetLocalData: TAnyNurbsFrameData;
    begin
      Result:=TAnyNurbsFrameData(FrameData);
    end;function TAnyNurbs.GetPoints: TMapPointList;
    begin
      Result:=TAnyNurbsFrameData(FrameData).Points;
    end;function TAnyNurbs.GetRMCenter: TAny2DPoint;
    begin
      Result:=LocalData.Points.Center;
    end;function TAnyNurbs.GetSingleSelectorClass: TAnySingleSelectorClass;
    begin
      Result:=TAnyNurbsSelector;
    end;procedure TAnyNurbs.InternalDraw;
    begin
      with MapCanvas do
      begin
        Pen.Mode:=pmCopy;
        Pen.Style:=psSolid;
        Pen.Color:=LineStyle.LineColor;
        Pen.Width:=LineStyle.LineWidth;
        DrawShape(LocalData);
      end;
    end;procedure TAnyNurbs.LoadFromStream(Stream: TStream);
    var
      i:Integer;
      PointCount:Integer;
    begin
      try
        with Points do
        begin
          BeginUpdate;
          try
            Clear;
            inherited LoadFromStream(Stream);
            PointCount:=ReadInteger(Stream);
            for i:=0 to PointCount-1 do
              AddXY(ReadDouble(Stream), ReadDouble(Stream));
          finally
            EndUpdate;
          end;
        end;
      except
        raise;
      end;
    end;procedure TAnyNurbs.SaveToStream(Stream: TStream);
    var
      i:Integer;
      APoint:PAny2DPoint;
    begin
      inherited SaveToStream(Stream);
      WriteInteger(Stream, Points.Count);
      for i:=0 to Points.Count-1 do
      begin
        APoint:=Points.Items[i];
        WriteDouble(Stream, APoint^.x);
        WriteDouble(Stream, APoint^.y);
      end;
    end;function TAnyNurbs.SelectedAt(X, Y, W: Double): Boolean;
    var
      i:Integer;
      n:Integer;
      pt_s, pt_e, pt, pt0:TAny2DPoint;
      dist:Double;
    begin
      Result:=False;
      n:=LocalData.Points.Count-1;
      if n<0 then Exit;
      pt:=Geo2DPoint(X, Y);
      with MapCanvas do
      begin
        pt_s := Parent.ClientToMap(LocalData.NURBS(n, LocalData.Degree, 0));
        for i:=1 to (n - LocalData.Degree + 2) * 10 do
        begin
          pt_e := Parent.ClientToMap(LocalData.NURBS(n, LocalData.Degree, i / 10));
          if PtOnLine(pt_s, pt_e, pt, W, pt0, dist) then
          begin
            Result:=True;
            Exit;
          end;
          pt_s := pt_e;
        end;
      end;
    end;procedure TAnyNurbs.TrackDraw(const IsClear: Boolean);
    begin
      with MapCanvas do
      begin
        Pen.Mode := pmXor;
        Pen.Style:=psSolid;
        Pen.Color:=InverseRGB(LineStyle.LineColor);
        Pen.Width:=LineStyle.LineWidth;
        DrawShape(TAnyNurbsFrameData(TrackData));
      end;
    end;initialization
      NurbsClassIndex:=ShapeClasses.Add(TAnyNurbs, TAnyNurbsFrameData, TAnyNurbsSelector,
        @ConfigCustomWithDialog);
        
    end.
      

  3.   

    unit AnyBSpline;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      AnyFramework, AnyTypeDefs, AnyXYs, Any32, AnyGlobalConsts, AnyDevice, AnyStdCtrls;type
      TAnyBSplineFrameData=class(TAnyShapeFrameData)
      private
        FPoints: TMapPointList;
        FDegree: Integer;
        procedure DoPartBoundsChanged(Sender:TObject);
      public
        constructor Create; override;
        destructor Destroy; override;
        function GetAdvanceBoundsRect:TAnyRect;
        procedure CopyFrom(Source: TAnyShapeFrameData); override;
        procedure ForwardSynchronize(OldBounds, NewBounds:TAnyBounds); override;
        procedure DefaultBackwardSynchronize; override;
        procedure GetVertexs(APoints:TMapPointList);
        procedure ToPolyline(APolyline:TAnyPolyLine);
        property Points:TMapPointList read FPoints;
        property Degree:Integer read FDegree write FDegree;
      end;  TAnyBSplineSelector=class(TAnySingleSelector)
      private
        HotPoint:TAnyHotPoint;
        PartIndex, PointIndex:Integer;
      protected
        function GetHotPoint(X, Y: Integer):TAnyHotPoint; override;
        function GetHotPoint2(const PartIndex, PointIndex:Integer):TAnyHotPoint;
        procedure DoPointDragMove(Sender:TObject; X, Y, W:Integer;
          mX, mY, mW: Double); virtual;
        procedure SetControl(const Value: TAnyControl); override;
        procedure SetShareData(const Value: TAnyShareData); override;
      public
        constructor Create; override;
        destructor Destroy; override;
        procedure Draw; override;
        procedure FitToControl; override;
      end;
      
      TAnyBSpline=class(TAnySingleControl)
      private
        FControlLineColor: TColor;
        function GetLocalData: TAnyBSplineFrameData;
        function GetPoints: TMapPointList;
        procedure DoOnBackwardSynchronize(Sender:TObject);
        procedure DrawBSpline(Data:TAnyBSplineFrameData);
        procedure DrawControlLine(Data:TAnyBSplineFrameData);
      protected
        function GetFrameDataClass:TAnyShapeFrameDataClass; override;
        function GetSingleSelectorClass:TAnySingleSelectorClass; override;
        function GetRMCenter: TAny2DPoint; override;
        procedure InternalDraw; override;
        procedure TrackDraw(const IsClear:Boolean); override;
        property LocalData:TAnyBSplineFrameData read GetLocalData;
      public
        //------------------------------------------------------------------------//
        constructor Create; override;
        procedure Assign(Source:TAnyShape); override;
        //------------------------------------------------------------------------//
        class function ClassID:Byte; override;
        //------------------------------------------------------------------------//
        procedure LoadFromStream(Stream:TStream); override;
        procedure SaveToStream(Stream:TStream); override;
        //------------------------------------------------------------------------//
        function SelectedAt(ptX, ptY, W: Double):Boolean; override;
        procedure GetVertexs(APoints:TMapPointList);
        procedure ToPolyline(APolyline:TAnyPolyLine);
        //------------------------------------------------------------------------//
        {点集列表,相对于父图元}
        property Points:TMapPointList read GetPoints;
        property ControlLineColor:TColor read FControlLineColor write FControlLineColor;
        //------------------------------------------------------------------------//
      end;var
      BSplineClassIndex:Integer;
      
    implementationuses
      GraphicsTools, StreamIOAPIs, U_Form_CustomConfig;
      
    { TAnyBSplineFrameData }procedure TAnyBSplineFrameData.CopyFrom(Source: TAnyShapeFrameData);
    var
      ANurbsFrameData:TAnyBSplineFrameData;
    begin
      inherited CopyFrom(Source);
      if Source is TAnyBSplineFrameData then
      begin
        ANurbsFrameData:=TAnyBSplineFrameData(Source);
        Points.CopyFrom(ANurbsFrameData.Points);
      end;
    end;constructor TAnyBSplineFrameData.Create;
    begin
      inherited;
      FPoints:=TMapPointList.Create;
      FPoints.OnBoundsChanged:=DoPartBoundsChanged;
      FDegree:=5;
    end;procedure TAnyBSplineFrameData.DefaultBackwardSynchronize;
    var
      BRect:TAnyRect;
    begin
      BRect:=GetAdvanceBoundsRect;
      Self.SetMapBounds(BRect, False);
    end;destructor TAnyBSplineFrameData.Destroy;
    begin
      FPoints.Free;
      inherited Destroy;
    end;procedure TAnyBSplineFrameData.DoPartBoundsChanged(Sender: TObject);
    begin
      BackwardSynchronize;
    end;procedure TAnyBSplineFrameData.ForwardSynchronize(OldBounds,
      NewBounds: TAnyBounds);
    var
      i:Integer;
      XScale, YScale:Double;
    begin
      if OldBounds.Width=0 then
        XScale:=1
      else
        XScale:=NewBounds.Width/OldBounds.Width;
      if OldBounds.Height=0 then
        YScale:=1
      else
        YScale:=NewBounds.Height/OldBounds.Height;
      for i:=0 to Points.Count-1 do
        with Points.Items[i]^ do
        begin
          X:=NewBounds.XMin+XScale*(X-OldBounds.XMin);
          Y:=NewBounds.YMin+YScale*(Y-OldBounds.YMin);
        end;
    end;function TAnyBSplineFrameData.GetAdvanceBoundsRect: TAnyRect;
    var
      i,j:Integer;
      n:Integer;
      m:Integer;
      xA, yA, xB, yB, xC, yC, xD, yD, a0, a1, a2, a3, b0, b1, b2, b3, x, y:Double;
      t:Double;
      first:Boolean;
    begin
      first:=True;
      m:=Degree;
      n:=Points.Count;
      if n=0 then
      begin
        Result:=GeoRect(0, 0, 0, 0);
        Exit;
      end;
      with MapCanvas do
      begin
        for i:=1 to n - 3 do
        begin
          xA := Points.Items[i - 1].x;
    xB := Points.Items[i].x;
    xC := Points.Items[i + 1].x;
    xD := Points.Items[i + 2].x;
    yA := Points.Items[i - 1].y;
    yB := Points.Items[i].y;
    yC := Points.Items[i + 1].y;
    yD := Points.Items[i + 2].y;
    a3 := (-xA + 3 * (xB - xC) + xD) / 6;
    b3 := (-yA + 3 * (yB - yC) + yD) / 6;
    a2 := (xA - 2 * xB + xC) / 2;
    b2 := (yA - 2 * yB + yC) / 2;
    a1 := (xC - xA) / 2;
    b1 := (yC - yA) / 2;
    a0 := (xA + 4 * xB + xC) / 6;
    b0 := (yA + 4 * yB + yC) / 6;
          for j:=0 to m do
          begin
    t := j / m;
    x := ((a3 * t + a2) * t + a1) * t + a0;
    y := ((b3 * t + b2) * t + b1) * t + b0;
    if first then
            begin
    first := false;
              Result:=GeoRect(x, y, x, y);
            end
    else
            begin
              if Result.XMin>x then
                Result.XMin:=x;
              if Result.YMin>y then
                Result.YMin:=y;
              if Result.XMax<x then
                Result.XMax:=x;
              if Result.YMax<y then
                Result.YMax:=y;
            end;
    end;
        end;
      end;
    end;procedure TAnyBSplineFrameData.GetVertexs(APoints: TMapPointList);
    var
      i,j:Integer;
      n:Integer;
      m:Integer;
      xA, yA, xB, yB, xC, yC, xD, yD, a0, a1, a2, a3, b0, b1, b2, b3, x, y:Double;
      t:Double;
    begin
      m:=Degree;
      n:=Points.Count;
      with MapCanvas do
      begin
        for i:=1 to n - 3 do
        begin
          xA := Points.Items[i - 1].x;
    xB := Points.Items[i].x;
    xC := Points.Items[i + 1].x;
    xD := Points.Items[i + 2].x;
    yA := Points.Items[i - 1].y;
    yB := Points.Items[i].y;
    yC := Points.Items[i + 1].y;
    yD := Points.Items[i + 2].y;
    a3 := (-xA + 3 * (xB - xC) + xD) / 6;
    b3 := (-yA + 3 * (yB - yC) + yD) / 6;
    a2 := (xA - 2 * xB + xC) / 2;
    b2 := (yA - 2 * yB + yC) / 2;
    a1 := (xC - xA) / 2;
    b1 := (yC - yA) / 2;
    a0 := (xA + 4 * xB + xC) / 6;
    b0 := (yA + 4 * yB + yC) / 6;
          for j:=0 to m do
          begin
    t := j / m;
    x := ((a3 * t + a2) * t + a1) * t + a0;
    y := ((b3 * t + b2) * t + b1) * t + b0;
            APoints.CUAddXY(x, y);
    end;
        end;
      end;
    end;procedure TAnyBSplineFrameData.ToPolyline(APolyline: TAnyPolyLine);
    var
      Vertexs:TMapPointList;
    begin
      APolyline.Parts.Clear;
      Vertexs:=APolyline.Parts.Add;
      Vert