📄 hgenurbs.pas
字号:
begin
KnotsCount := CPCount + OrderOfCurve;
SetLength(KnotsVector, KnotsCount);
for i := 0 to CPCount - 1 do
KnotsVector[i + OrderOfCurve - 1] := i;
for i := (KnotsCount - OrderOfCurve) to KnotsCount - 1 do
KnotsVector[i] := KnotsVector[KnotsCount - OrderOfCurve];
ParameterStart := KnotsVector[0];
ParameterEnd := KnotsVector[KnotsCount - 1];
end;
// ==========================================================================
function TNURBSCurve.GetCurveLength: Single;
begin
if not FittingCurveReady then SetFittingCurve;
Result := GetSegmentLength(1,Segments - 1);
end;
// ==========================================================================
function TNURBSCurve.GetSegmentLength(Index1, Index2: Integer): Single;
var
i: Integer;
begin
if not FittingCurveReady then SetFittingCurve;
Result := 0;
for i := Index1 to Index2 - 1 do
Result := Result + Length2(Point2(FittingCurve[i].x, FittingCurve[i].y) -
Point2(FittingCurve[i+1].x, FittingCurve[i+1].y));
end;
// ==========================================================================
function TNURBSCurve.GetTangent(Parameter: Single): Single;
var
Index: Integer;
ParameterDetla: Single;
p1, p2: TPoint2;
begin
case FittingCurveType of
fcConstantParameter:
begin
ParameterDetla := 0.001;
if (Parameter >= 1) {or (Parameter + ParameterDetla >= 1)} then
Parameter := Parameter - ParameterDetla;
p1 := CalcXY(Parameter*ParameterEnd);
p2 := CalcXY(Parameter*ParameterEnd + ParameterDetla);
Result := Angle2(p2 - p1);
end;
fcConstantSpeed:
begin
Index := Trunc(Parameter*Segments);
if Index >= Segments - 1 then Index := Segments - 2;
Result := Angle2(FittingCurve[Index+1] - FittingCurve[Index]);
end;
end;
end;
// ==========================================================================
function TNURBSCurve.GetXY(Parameter: Single): TPoint2;
var
Index: Integer;
k, Residue, Span : Single;
begin
case FittingCurveType of
fcConstantParameter: Result := CalcXY(Parameter*ParameterEnd);
fcConstantSpeed:
begin
Index := Trunc(Parameter*Segments);
if Index > Segments - 2 then
begin
Result.X := FittingCurve[Segments - 1].X;
Result.Y := FittingCurve[Segments - 1].Y;
Exit;
end;
Residue := Parameter*Segments - Index;
k := FittingCurve[Index+1].Y - FittingCurve[Index].Y;
k := k / (FittingCurve[Index+1].X - FittingCurve[Index].X);
Span := GetSegmentLength(Index, Index+1);
Span := Span * Residue;
Result.X := Span * Cos(ArcTan2(k,1));
Result.Y := Span * Sin(ArcTan2(k,1));
if FittingCurve[Index+1].X > FittingCurve[Index].X then
begin
Result.X := FittingCurve[Index].X + Result.X;
Result.Y := FittingCurve[Index].Y + Result.Y;
end
else
begin
Result.X := FittingCurve[Index].X - Result.X;
Result.Y := FittingCurve[Index].Y - Result.Y;
end;
end;
end;
end;
{ TNURBSCurveEX }
// ==========================================================================
constructor TNURBSCurveEX.Create(var AControlPoints: array of TPoint2);
begin
inherited;
Color := $FFFFFFFF;
CPColor := $FFFFFFFF;
CPRadius := 10;
HullColor := $FFFFFFFF;
DragMode := false;
DrawMode := dmCurveCPHull;
CPIndex := 0;
end;
// ==========================================================================
constructor TNURBSCurveEX.Create;
begin
inherited;
Color := $FFFFFFFF;
CPColor := $FFFFFFFF;
CPRadius := 10;
HullColor := $FFFFFFFF;
DragMode := false;
DrawMode := dmCurveCPHull;
CPIndex := 0;
end;
// ==========================================================================
function TNURBSCurveEX.CreateCP(X, Y: Integer): Integer;
begin
CPCount := CPCount + 1;
SetLength(ControlPoints, CPCount);
ControlPoints[CPCount - 1].X := X;
ControlPoints[CPCount - 1].Y := Y;
Result := CPCount - 1;
UpdateKnots;
end;
// ==========================================================================
procedure TNURBSCurveEX.DeleteCP;
begin
if CPCount = 1 then Exit;
CPCount := CPCount - 1;
SetLength(ControlPoints, CPCount);
UpdateKnots;
end;
// ==========================================================================
destructor TNURBSCurveEX.Destroy;
begin
inherited;
end;
// ==========================================================================
procedure TNURBSCurveEX.Draw;
var
i: Integer;
begin
case DrawMode of
dmNone: begin end;
dmCurve: begin
if CPCount > 4 {BaseCurve.FOrderOfCurve} then
for i := 1 to Segments - 1 do
FHGE.Gfx_RenderLine(FittingCurve[i-1].x, FittingCurve[i-1].y,
FittingCurve[i].x, FittingCurve[i].y,
Color);
end;
dmCurveCP: begin
for i := 0 to CPCount - 1 do
FHGE.Circle(ControlPoints[i].X, ControlPoints[i].Y, CPRadius, $FFFFFFFF, False);
if CPCount > 4 {BaseCurve.FOrderOfCurve} then
for i := 1 to Segments - 1 do
FHGE.Gfx_RenderLine(FittingCurve[i-1].x, FittingCurve[i-1].y,
FittingCurve[i].x, FittingCurve[i].y,
Color);
end;
dmCurveCPHull: begin
for i := 0 to CPCount - 1 do
FHGE.Circle(ControlPoints[i].X, ControlPoints[i].Y, CPRadius, $FFFFFFFF, False);
if CPCount > 4 {BaseCurve.FOrderOfCurve} then
for i := 1 to Segments - 1 do
FHGE.Gfx_RenderLine(FittingCurve[i-1].x, FittingCurve[i-1].y,
FittingCurve[i].x, FittingCurve[i].y,
Color);
for i := 1 to CPCount - 1 do
FHGE.Gfx_RenderLine(ControlPoints[i-1].X, ControlPoints[i-1].Y,
ControlPoints[i].X, ControlPoints[i].Y,
HullColor);
end;
end;
end;
// ==========================================================================
function TNURBSCurveEX.GetCP(X, Y: Integer): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to CPCount-1 do
if CPRadius >= sqrt((ControlPoints[i].X - X)*(ControlPoints[i].X - X) +
(ControlPoints[i].Y - Y)*(ControlPoints[i].Y - Y)) then
begin
Result := i;
Exit;
end;
end;
// ==========================================================================
procedure TNURBSCurveEX.LoadBakeCurve(Filename: String);
var
i: Integer;
SFile: file of TPoint2;
begin
AssignFile(SFile, Filename);
Reset(SFile);
Segments := FileSize(SFile);
SetLength(FittingCurve, Segments);
for i := 0 to Segments - 1 do
Read(SFile, FittingCurve[i]);
CloseFile(SFile);
FittingCurveReady := True;
end;
// ==========================================================================
procedure TNURBSCurveEX.LoadCurve(Filename: String);
var
i: Integer;
SFile: file of TPoint2;
Point: TPoint2;
begin
AssignFile(SFile, Filename);
Reset(SFile);
CPCount := FileSize(SFile);
SetLength(ControlPoints, CPCount);
for i := 0 to CPCount - 1 do
begin
Read(SFile, Point);
ControlPoints[i].X := Point.X;
ControlPoints[i].Y := Point.Y;
end;
CloseFile(SFile);
FittingCurveReady := False;
UpdateKnots;
if FileExists(Filename + BAKE_EXT) then LoadBakeCurve(Filename + BAKE_EXT);
end;
// ==========================================================================
procedure TNURBSCurveEX.SaveBakeCurve(Filename: String);
var
i: Integer;
SFile: file of TPoint2;
begin
AssignFile(SFile, Filename + BAKE_EXT);
Rewrite(SFile);
for i := 0 to Segments - 1 do
Write(SFile, FittingCurve[i]);
CloseFile(SFile);
end;
// ==========================================================================
procedure TNURBSCurveEX.SaveCurve(Filename: String);
var
i: Integer;
SFile: file of TPoint2;
begin
AssignFile(SFile, FILENAME);
Rewrite(SFile);
for i := 0 to CPCount - 1 do
Write(SFile, ControlPoints[i]);
CloseFile(SFile);
if FileExists(Filename + BAKE_EXT) then DeleteFile(Filename + BAKE_EXT);
if FittingCurveReady and (FittingCurveType = fcConstantSpeed) then
SaveBakeCurve(Filename);
end;
// ==========================================================================
procedure TNURBSCurveEx.SwitchDrawMode;
begin
case DrawMode of
dmNone: DrawMode := dmCurve;
dmCurve: DrawMode := dmCurveCP;
dmCurveCP: DrawMode := dmCurveCPHull;
dmCurveCPHull: DrawMode := dmNone;
end;
end;
// ==========================================================================
procedure TNURBSCurveEx.Update;
var
i: Integer;
points: array of TPoint2;
begin
if CPCount > 4 {BaseCurve.FOrderOfCurve} then
begin
SetLength(points, CPCount);
for i := 0 to CPCount - 1 do
begin
points[i].x := ControlPoints[i].X;
points[i].y := ControlPoints[i].Y;
end;
SetFittingCurve;
end;
points := nil;
end;
initialization
FHGE := nil;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -