{ 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;
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);
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;
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.
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