⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hgenurbs.pas

📁 完整的Delphi游戏开发控件
💻 PAS
📖 第 1 页 / 共 2 页
字号:
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 + -