{************************************************************}
{                   Delphi VCL Extensions                    }
{                                                            }
{                   Parsing lines by rects                   }
{                                                            }
{      Copyright (c) 2002-2003 SoftGold software company     }
{                                                            }
{************************************************************}

unit Parser;

interface

uses
  Windows, Classes, Math;

type
  PLine = ^TLine;
  TLine = record
    x1, y1, x2, y2: Integer;
  end;

  PRectangle = ^TRectangle;
  TRectangle = record
    X1, Y1, X2, Y2: Integer;
  end;

  procedure ClipLine(ALine: TLine; ARect: TRectangle; AParsedLines: TList);
  procedure SwapInts(var A,B);

implementation

procedure SwapInts(var A,B);
asm
	MOV	ECX,[EAX]
	XCHG	ECX,[EDX]
	MOV	[EAX],ECX
end;

procedure ClipLine(ALine: TLine; ARect: TRectangle; AParsedLines: TList);

  function GetYByX(X: Integer): Integer;
  begin
    Result := MaxInt;
    if ((ALine.x1 > X) and (ALine.x2 < X)) or
      ((ALine.x1 < X) and (ALine.x2 > X)) then
      Result := ALine.y1 + (ALine.y2 - ALine.y1) * (X - ALine.x1) div
          (ALine.x2 - ALine.x1);
    if (Result < ARect.Y1) or (Result > ARect.Y2) then
      Result := MaxInt;
  end;

  function GetXByY(Y: Integer): Integer;
  begin
    Result := MaxInt;
    if ((ALine.y1 > Y) and (ALine.y2 < Y)) or
      ((ALine.y1 < Y) and (ALine.y2 > Y)) then
      Result := ALine.x1 + (ALine.x2 - ALine.x1) * (Y - ALine.y1)
        div (ALine.y2 - ALine.y1);
    if (Result < ARect.X1) or (Result > ARect.X2) then
      Result := MaxInt;
  end;

var
  vInt: Integer;
  P: PLine;
begin
  vInt := GetYByX(ARect.X1); // left
  if vInt <> MaxInt then
  begin
    New(P);
    P^ := ALine;
    if P.x1 < ARect.X1 then
    begin
      P.x2 := ARect.X1;
      P.y2 := vInt;
    end
    else
    begin
      P.x1 := ARect.X1;
      P.y1 := vInt;
    end;
    AParsedLines.Add(P);
  end;

  vInt := GetYByX(ARect.X2); // right
  if vInt <> MaxInt then
  begin
    New(P);
    P^ := ALine;
    if P.x1 > ARect.X2 then
    begin
      P.x2 := ARect.X2;
      P.y2 := vInt;
    end
    else
    begin
      P.x1 := ARect.X2;
      P.y1 := vInt;
    end;
    AParsedLines.Add(P);
  end;

  vInt := GetXByY(ARect.Y1); // top
  if vInt <> MaxInt then
  begin
    New(P);
    P^ := ALine;
    if P.y1 < ARect.Y1 then
    begin
      P.y2 := ARect.Y1;
      P.x2 := vInt;
    end
    else
    begin
      P.y1 := ARect.Y1;
      P.x1 := vInt;
    end;
    AParsedLines.Add(P);
  end;

  vInt := GetXByY(ARect.Y2); // bottom
  if vInt <> MaxInt then
  begin
    New(P);
    P^ := ALine;
    if P.y1 > ARect.Y2 then
    begin
      P.y2 := ARect.Y2;
      P.x2 := vInt;
    end
    else
    begin
      P.y1 := ARect.Y2;
      P.x1 := vInt;
    end;
    AParsedLines.Add(P);
  end;
  if AParsedLines.Count = 0 then
    if not PtInRect(Rect(ARect.X1 + 1, ARect.Y1 + 1, ARect.X2, ARect.Y2),
      Point(ALine.x1, ALine.y1)) then
    begin
      New(P);
      P^ := ALine;
      AParsedLines.Add(P);
    end;
end;

end.
