unit kCutter;
{
   Unit for simulating Cutter

   Author:  Vesa Lappalainen
   Date:    20.2.1998
   Changes:

   Creates two TBlade component.

}

interface
uses Dialogs,Graphics,Classes,Controls,ExtCtrls,kavesimu;

const  blOnline =0;
       blUpperLeft =1;
       blUpperRight =2;
type
    TCutter = class;
    TBlade = class;

    TBladeMessage = ( blmsgDone, blmsgHome, blmsgOver );
//    TBladeLine   = ( blOnline, blUpperLeft, blUpperRight );
    TBladeLine   = integer;
    TBladeEvent = procedure (blade:TBlade; msg:TBladeMessage) of object;

    TBlade = class(TPersistent) // Blade can be only inside TCutter
    private
      FAutoCut : boolean;
      FMin : double;          // Relative to parent dp.y and p.y
      FMax : double;
      FOrg  : double;
      FHole     : double;
      FTimeWork : double;     // In sec.
      FTimeRet   : double;
      FDirection : integer;   // -1 = down, 1 = up, 0 = no move
      FBlade : TaSimuObject;
      FOwner : TCutter;

      FTimer : TTimer;
      FSpeed : double;
      FOrgY : double;
      FMaxY : double;
      FMinY : double;
      FHomeY : double;
      FDs    : double;
      FOnBlade : TBladeEvent;
      FPosY : double;
    protected

    public
      constructor Create(AOwner:TCutter);     virtual;
      destructor Destroy; override;
      procedure SetHole(value:double); virtual;
      function  GetBrush : TBrush; virtual;
      procedure SetBrush(value:TBrush); virtual;
      function  GetPen : TPen; virtual;
      procedure SetPen(value:TPen); virtual;
      function  GetVisible : Boolean; virtual;
      procedure SetVisible(value:Boolean); virtual;
//      procedure Assign(value:TPersistent); override;
      property Blade : TaSimuObject read FBlade;
      procedure OnTimerWork(Sender: TObject);
      procedure OnTimerHome(Sender: TObject);
      procedure StartCut; virtual;
      procedure GoHome; virtual;
      procedure Stop; virtual;
      property Owner : TCutter read FOwner;
      function  GetInterval : Integer; virtual;
      procedure SetInterval(value:Integer); virtual;
    published

      property Max : double read FMax write FMax nodefault;
      property Min : double read FMin write FMin nodefault;
      property Org : double read FOrg write FOrg nodefault;
      property TimeWork : double read FTimeWork write FTimeWork;
      property TimeRet : double read FTimeRet write FTimeRet;
      property Direction : integer read FDirection write FDirection default -1;
      property Hole : double read FHole write SetHole nodefault;
      property Brush : TBrush read GetBrush write SetBrush;
      property Pen : TPen read GetPen write SetPen;
      property OnBlade : TBladeEvent read FOnBlade write FOnBlade;
      property PosY : double read FPosY;
      property AutoCut : boolean read FAutoCut write FAutoCut default false;
      property Interval : Integer read GetInterval write SetInterval default 100;
      property Visible : boolean read GetVisible write SetVisible default True;
    end;


  TCutter = class(TaSimuObject)
  private
    FBladeUpper : TBlade;
    FBladeLower : TBlade;
    FBladeLine : TBladeLine;
  protected

    procedure SetParent(AParent:TWinControl);  override;
  public
    constructor Create(AOwner:TComponent);     override;
    destructor Destroy; override;
    procedure DoScale(force:boolean); override;
    procedure CheckBlades; virtual;
    procedure Paint;                           override;
    function  GetOnBladeUpper : TBladeEvent; virtual;
    procedure SetOnBladeUpper(value:TBladeEvent); virtual;
    function  GetOnBladeLower : TBladeEvent; virtual;
    procedure SetOnBladeLower(value:TBladeEvent); virtual;
    function  GetVisible : boolean; override;
    procedure SetVisible(value:boolean); override;
    procedure SetBladeLine(value:TBladeLine); virtual;
  published

    property BladeUpper : TBlade read FBladeUpper write FBladeUpper;
    property BladeLower : TBlade read FBladeLower write FBladeLower;
    property OnBladeUpper : TBladeEvent read GetOnBladeUpper write SetOnBladeUpper;
    property OnBladeLower : TBladeEvent read GetOnBladeLower write SetOnBladeLower;
    property Visible : boolean read GetVisible write SetVisible default True;
    property BladeLine : TBladeLine read FBladeLine write SetBladeLine default blOnline;
  end;


procedure Register;

{------------------------------------------------------------------------------}
implementation

{------------------------------------------------------------------------------}
procedure Register;
begin
  RegisterComponents('Kave2000', [TCutter]);
end;


//-----------------------------------------------------------------------------
procedure TCutter.DoScale(force:boolean); //  override;
begin
  inherited;
  CheckBlades;
end;


//-----------------------------------------------------------------------------
procedure TCutter.CheckBlades; //  virtual;
begin
  if ( not assigned(BladeUpper) ) or ( not Assigned(BladeLower) ) then exit;
    ShowMessage('Moi');
  with BladeUpper.Blade.Box do begin
    DoInform := false;
    case BladeLine of
      blOnline: begin
        dp.x := Self.Box.dp.x;
        Origo.x := Self.Box.Origo.x;
      end;
      blUpperLeft : begin
        dp.x := Self.Box.Origo.x;
        Origo.x := dp.x;
      end;
      blUpperRight : begin
        dp.x := Self.Box.dp.x - Self.Box.Origo.x;
        Origo.x := 0;
      end;
    end;
    Origo.y := 0;
    dp.y := Self.Box.dp.y - Self.Box.Origo.y - Self.Box.dp.y*BladeUpper.Hole;
    p.x := Self.Box.p.x;
    p.y := Self.Box.p.y + Self.Box.dp.y*BladeUpper.Hole + BladeUpper.PosY;
    DoInform := true;
  end;

  with BladeLower.Blade.Box do begin
    DoInform := false;
    case BladeLine of
      blOnline: begin
        dp.x := Self.Box.dp.x;
        Origo.x := Self.Box.Origo.x;
       end;
      blUpperLeft : begin
        dp.x := Self.Box.dp.x - Self.Box.Origo.x;
        Origo.x := 0;
       end;
      blUpperRight : begin
        dp.x := Self.Box.Origo.x;
        Origo.x := dp.x;
       end;
    end;
    dp.y := Self.Box.Origo.y - Self.Box.dp.y*BladeLower.Hole;
    Origo.y := dp.y;
    p.x := Self.Box.p.x;
    p.y := Self.Box.p.y - Self.Box.dp.y*BladeLower.Hole + BladeLower.PosY;
    DoInform := true;
  end;
end;


//-----------------------------------------------------------------------------
constructor TCutter.Create(AOwner:TComponent); //      override;
begin
  inherited;
  Brush.Style := bsClear;
  Pen.Style := psDot;
  FBladeUpper := TBlade.Create(self);
  FBladeLower := TBlade.Create(self);
  ControlVisible(false);
  FBladeLower.Direction := 0;
  FBladeLower.Hole := 0;
  FBladeLower.Min := -0.2;
  FBladeUpper.Max :=  0.2;
  FBladeUpper.Hole :=  0.1;
  FBladeLine := blOnline;
  CheckBlades;
end;


//-----------------------------------------------------------------------------
destructor TCutter.Destroy; //  override;
begin
//  if ( Assigned(LowerBlade ) ) then LowerBlade.Free;
  FBladeLower := nil;
//  if ( Assigned(BladeUpper ) ) then  BladeUpper.Free;
  FBladeUpper := nil;
  inherited;
end;


//-----------------------------------------------------------------------------
procedure TCutter.SetBladeLine(value:TBladeLine); //  virtual;
begin
  FBladeLine := value;
  CheckBlades;
end;


//-----------------------------------------------------------------------------
procedure TCutter.SetParent(AParent:TWinControl); //   override;
begin
  inherited;
  if ( Assigned(BladeLower ) ) then BladeUpper.Blade.Parent := AParent;
  if ( Assigned(BladeUpper ) ) then BladeLower.Blade.Parent := AParent;
  BringToFront;
end;


//-----------------------------------------------------------------------------
procedure TCutter.SetOnBladeUpper(value:TBladeEvent); //  virtual;
begin
  BladeUpper.OnBlade := value;
end;


//-----------------------------------------------------------------------------
function  TCutter.GetOnBladeUpper : TBladeEvent; //  virtual;
begin
  Result := BladeUpper.OnBlade;
end;


//-----------------------------------------------------------------------------
procedure TCutter.SetOnBladeLower(value:TBladeEvent); //  virtual;
begin
  BladeLower.OnBlade := value;
end;


//-----------------------------------------------------------------------------
function  TCutter.GetOnBladeLower : TBladeEvent; //  virtual;
begin
  Result := BladeLower.OnBlade;
end;

//-----------------------------------------------------------------------------
procedure TCutter.Paint; //                            override;
begin
  inherited;
end;

//-----------------------------------------------------------------------------
procedure TCutter.SetVisible(value:boolean); //  virtual;
begin
  if ( value = Visible ) then exit;
  Link.Visible := value;
  BladeUpper.Visible := value;
  BladeLower.Visible := value;
  ControlVisible(false);
end;


//-----------------------------------------------------------------------------
function  TCutter.GetVisible : boolean; //  virtual;
begin
  Result := BladeUpper.Visible;
end;


//-----------------------------------------------------------------------------
constructor TBlade.Create(AOwner:TCutter); //      virtual;
begin
  inherited Create;
  FOwner := AOwner;
  FBlade := taSimuObject.Create(FOwner);
  FMin := 0;
  FMax := 0;
  FOrg := 0;
  FTimeRet := 1;
  FTimeWork := 1;
  FHole := 0;
  FDirection := -1;
  FTimer := TTimer.Create(FOwner);
  FTimer.Enabled := false;
  FTimer.Interval := 100;
end;


//-----------------------------------------------------------------------------
procedure TBlade.SetHole(value:double); //  virtual;
begin
  FHole := value;
  FOwner.CheckBlades;
end;


//-----------------------------------------------------------------------------
destructor TBlade.Destroy; //  override;
begin
  // FBlade ei tarvitse tuhota, koska se tuhoutuu omistajansa mukana
  inherited;
end;


//-----------------------------------------------------------------------------
procedure TBlade.SetBrush(value:TBrush); //  virtual;
begin
  Blade.Brush.Assign(value);
end;


//-----------------------------------------------------------------------------
function  TBlade.GetBrush : TBrush; //  virtual;
begin
  Result := Blade.Brush;
end;


//-----------------------------------------------------------------------------
procedure TBlade.SetPen(value:TPen); //  virtual;
begin
  Blade.Pen.Assign(value);
end;


//-----------------------------------------------------------------------------
function  TBlade.GetPen : TPen; //  virtual;
begin
  Result := Blade.Pen;
end;


//-----------------------------------------------------------------------------
procedure TBlade.SetVisible(value:Boolean); //  virtual;
begin
  Blade.Visible := value;
end;


//-----------------------------------------------------------------------------
function  TBlade.GetVisible : Boolean; //  virtual;
begin
  Result := Blade.Visible;
end;

{
//-----------------------------------------------------------------------------
procedure TBlade.Assign(value:TPersistent); //  override;
var b : TBlade;
begin
  if  not ( value is TBlade ) then exit;
  b := value as TBlade;
  Min := b.min;
end;
}

//-----------------------------------------------------------------------------
procedure TBlade.OnTimerWork(Sender: TObject);
begin
  Blade.box.p.y := Blade.box.p.y + FSpeed;
  FPosY := FPosY + FSpeed;
  if direction <= 0 then begin // direction down
    if ( Blade.box.p.y < FOrgY ) then begin
      Blade.box.p.y := FOrgY;
      FPosY := -Fds;
      FOrgY := -100000;
      if Assigned(OnBlade) then OnBlade(self,blmsgDone);
      if ( AutoCut ) then GoHome;
    end;
    if ( Blade.box.p.y < FMinY ) then begin
      Stop;
      if Assigned(OnBlade) then OnBlade(self,blmsgOver);
    end;
    exit;
  end;

  // direction up
  if ( Blade.box.p.y > FOrgY ) then begin
    Blade.box.p.y := FOrgY;
    FPosY := Fds;
    FOrgY := 100000;
    if Assigned(OnBlade) then OnBlade(self,blmsgDone);
    if ( AutoCut ) then GoHome;
  end;
  if ( Blade.box.p.y > FMaxY ) then begin
    Stop;
    if Assigned(OnBlade) then OnBlade(self,blmsgOver);
  end;
end;

//-----------------------------------------------------------------------------
procedure TBlade.OnTimerHome(Sender: TObject);
begin
  Blade.box.p.y := Blade.box.p.y + FSpeed;
  FPosY := FPosY + FSpeed;
  if direction <= 0 then begin  // direction down
    if ( Blade.box.p.y >= FHomeY ) then begin
      Blade.box.p.y := FHomeY;
      FPosY := 0;
      FHomeY := 1000000;
      if ( AutoCut ) then Stop;
      if Assigned(OnBlade) then OnBlade(self,blmsgHome);
    end;
    if ( Blade.box.p.y >= FMaxY ) then begin
      Stop;
      if Assigned(OnBlade) then OnBlade(self,blmsgOver);
    end;
    exit;
  end;

  if ( Blade.box.p.y <= FHomeY ) then begin
    Blade.box.p.y := FHomeY;
    FPosY := 0;
    FHomeY := 1000000;
    if ( AutoCut ) then Stop;
    if Assigned(OnBlade) then OnBlade(self,blmsgHome);
  end;
  if ( Blade.box.p.y <= FMinY ) then begin
    Stop;
    if Assigned(OnBlade) then OnBlade(self,blmsgOver);
  end;
end;


//-----------------------------------------------------------------------------
procedure TBlade.StartCut; //  virtual;
var dt : double;
begin
  if  ( Direction = 0 ) then exit;
  FPosY := 0;
  FOwner.CheckBlades;
  FOrgY := FOwner.Box.p.y + Org * FOwner.Box.dp.y;
  FMaxY := FOwner.Box.p.y + Max * FOwner.Box.dp.y;
  FMinY := FOwner.Box.p.y + Min * FOwner.Box.dp.y;
  FHomeY := Blade.box.p.y;
  dt := TimeWork; if ( dt = 0 ) then dt := 1;
  FDs := abs(FHomeY - FOrgY);
  FSpeed := direction*FDs/dt*Interval/1000;
  if ( FSpeed = 0 ) then FSpeed := direction;
  FTimer.OnTimer := OnTimerWork;
  Ftimer.Enabled := true;
end;


//-----------------------------------------------------------------------------
procedure TBlade.GoHome; //  virtual;
var dt : double;
begin
  if  ( Direction = 0 ) then exit;
  dt := TimeRet; if ( dt = 0 ) then dt := 1;
  FSpeed := -direction*FDs/dt*Interval/1000;
  if ( FSpeed = 0 ) then FSpeed := -direction;
  FTimer.OnTimer := OnTimerHome;
  Ftimer.Enabled := true;
end;


//-----------------------------------------------------------------------------
procedure TBlade.Stop; //  virtual;
begin
  Ftimer.Enabled := false;
end;


//-----------------------------------------------------------------------------
procedure TBlade.SetInterval(value:Integer); //  virtual;
begin
  FTimer.Interval := value;
end;


//-----------------------------------------------------------------------------
function  TBlade.GetInterval : Integer; //  virtual;
begin
  Result := FTimer.Interval;
end;








































end.






























