unit Unit1;

interface

uses
  Winapi.OpenGL,
  System.Types,
  System.SysUtils,
  System.Classes,
  System.Math,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.ExtCtrls,
  Vcl.StdCtrls,


  GLVectorTypes,
  GLVectorLists,
  GLScene,
  GLObjects,
  GLCadencer,
  GLVectorFileObjects,
  GLMaterial,
  GLColor,
  GLState,
  GLSceneViewer,
  GLVectorGeometry,
  GLGraph,
  GLGeomObjects,
  GLCrossPlatform,
  GLCoordinates,
  GLBaseClasses;

type
  TForm1 = class(TForm)
    Viewer: TGLSceneViewer;
    GLScene: TGLScene;
    GLCadencer: TGLCadencer;
    GLCamera1: TGLCamera;
    GLLightSource1: TGLLightSource;
    GLLightSource2: TGLLightSource;
    DCCamTarget: TGLDummyCube;
    Panel2: TPanel;
    GLCube1: TGLCube;
    GLXYZGrid1: TGLXYZGrid;
    GLLines1: TGLLines;
    CheckBoxGrid: TCheckBox;
    ButtonFindIntersect: TButton;
    CheckBoxPosition: TCheckBox;
    CheckBoxScale: TCheckBox;
    CheckBoxTriangle: TCheckBox;
    ButtonNotFindIntersect: TButton;
    GLPolygon1: TGLPolygon;
    CheckBoxVisible: TCheckBox;
    GLPoints1: TGLPoints;
    CheckBoxAxis: TCheckBox;
    GLLines2: TGLLines;
    GLPolygon2: TGLPolygon;
    RadioGroupCoPolygon: TRadioGroup;
    procedure GLCadencerProgress(Sender: TObject; const deltaTime,
      newTime: Double);
    procedure FormCreate(Sender: TObject);
    procedure ViewerMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    procedure FormResize(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure ButtonNotFindIntersectClick(Sender: TObject);
    procedure ButtonFindIntersectClick(Sender: TObject);
    procedure CheckBoxVisibleClick(Sender: TObject);
    procedure RadioGroupCoPolygonClick(Sender: TObject);
  private
    mdx, mdy : Integer;
    BoxPos, BoxScale,
    MinExtend, MaxExtend : TAffineVector;
    TriangePos           : array [0..2] of TAffineVector;
    PolygonPos           : array [0..4] of TAffineVector;
    procedure MakeRandomData;
    procedure DrawResult;
    procedure DrawCoplanarPolygon;
  public
  end;

var
  Form1 : TForm1;

implementation

{$R *.DFM}

const
  SizePos   = 10;
  ScaleSize = 3;
  TrigRect  = 10;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  Randomize;
  BoxScale := XYZVector;
  DrawCoplanarPolygon;
end;

procedure TForm1.DrawCoplanarPolygon;
begin
  GLPolygon2.Nodes.Clear;
  GLPolygon2.Material.FrontProperties.Ambient.RandomColor;
  PolygonPos[0] := AffineVectorMake(-5,-5,0);
  PolygonPos[1] := AffineVectorMake(5,-5,0);
  PolygonPos[2] := AffineVectorMake(5,5,0);
  PolygonPos[3] := AffineVectorMake(-5,5,0);
  PolygonPos[4] := AffineVectorMake(0,0,0);
  GLPolygon2.AddNode(PolygonPos[0]);
  GLPolygon2.AddNode(PolygonPos[1]);
  GLPolygon2.AddNode(PolygonPos[2]);
  GLPolygon2.AddNode(PolygonPos[3]);
  GLPolygon2.AddNode(PolygonPos[4]);
end;

procedure TForm1.MakeRandomData;
var
  i : Integer;
begin
    // Change position.
  if CheckBoxPosition.Checked then
    BoxPos   := AffineVectorMake( Random*SizePos -SizePos/2,
                                  Random*SizePos -SizePos/2,
                                  Random*SizePos -SizePos/2  );
    // Change scale.
  if CheckBoxScale.Checked then
    BoxScale := AffineVectorMake( Random*ScaleSize +ScaleSize/2,
                                  Random*ScaleSize +ScaleSize/2,
                                  Random*ScaleSize +ScaleSize/2 );
    // Change triangle.
  if CheckBoxTriangle.Checked then
    for i := 0 to 2 do
      TriangePos[i] := AffineVectorMake( Random*TrigRect -TrigRect/2,
                                         Random*TrigRect -TrigRect/2,
                                         Random*TrigRect -TrigRect/2 );
   // Calc extends.
  MinExtend := VectorSubtract(BoxPos, VectorScale(BoxScale, 0.5));
  MaxExtend := VectorAdd(     BoxPos, VectorScale(BoxScale, 0.5));
end;

procedure TForm1.RadioGroupCoPolygonClick(Sender: TObject);
begin
  case RadioGroupCoPolygon.ItemIndex of
     0: GLPolygon2.Material.PolygonMode := pmFill;
     1: GLPolygon2.Material.PolygonMode := pmLines;
     2: GLPolygon2.Material.PolygonMode := pmPoints;
  end;
end;

procedure TForm1.DrawResult;
var
  i : Integer;
begin
  GLPolygon1.Nodes.Clear;
  GLPolygon1.Material.FrontProperties.Emission.Color := clrGreen;
  GLPolygon1.Material.BackProperties.Emission.Color := clrGreen;
  GLPolygon1.AddNode(TriangePos[0]);
  GLPolygon1.AddNode(TriangePos[1]);
  GLPolygon1.AddNode(TriangePos[2]);

  GLPoints1.Positions.Clear;
  GLPoints1.Colors.Add(1, 0, 1, 1); //magenta
  GLPoints1.Size := 5;
  for i := 0 to 2 do
    GLPoints1.Positions.Add(TriangePos[i]);

  GLLines2.Nodes.Clear;
  GLLines2.Nodes.AddNode(TriangePos[0]);
  GLLines2.Nodes.AddNode(TriangePos[1]);
  GLLines2.Nodes.AddNode(TriangePos[2]);
  GLLines2.Nodes.AddNode(TriangePos[0]);

  DCCamTarget.Position.SetPoint(BoxPos);
  DCCamTarget.Scale.SetVector(BoxScale);
  GLCube1.Position.SetPoint(BoxPos);
  GLCube1.Scale.SetVector(BoxScale);

  DrawCoplanarPolygon;
end;

// Find next with intersection
procedure TForm1.ButtonFindIntersectClick(Sender: TObject);
var
  IterCnt : Integer;
  Res1    : Boolean;
begin
  IterCnt := 0;
  repeat
    MakeRandomData;
    Res1 := IntersectTriangleBox(TriangePos[0], TriangePos[1], TriangePos[2],
      MinExtend, MaxExtend);
    IterCnt := IterCnt + 1;
    if IterCnt >= 10000 then
    begin
      DrawResult;
      ShowMessage('Intersection not found!');
      exit;
    end;
  until Res1;
  DrawResult;
end;

// Find next without intersection.
procedure TForm1.ButtonNotFindIntersectClick(Sender: TObject);
var
  IterCnt : Integer;
  Res1    : Boolean;
begin
  IterCnt := 0;
  repeat
    MakeRandomData;
    Res1 := IntersectTriangleBox(TriangePos[0], TriangePos[1], TriangePos[2],
      MinExtend, MaxExtend);
    IterCnt := IterCnt + 1;
    if IterCnt >= 10000 then
    begin
      DrawResult;
      ShowMessage('Intersection not found!');
      Exit;
    end;
  until not Res1;
  DrawResult;
end;

procedure TForm1.CheckBoxVisibleClick(Sender: TObject);
begin
  GLCube1.Visible    := CheckBoxVisible.Checked;
  GLXYZGrid1.Visible := CheckBoxGrid.Checked;
  GLLines1.Visible   := CheckBoxAxis.Checked;
end;

procedure TForm1.GLCadencerProgress(Sender: TObject; const deltaTime,
  newTime: Double);
begin
  if Form1.Active then Viewer.Invalidate
end;

procedure TForm1.ViewerMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Shift = [ssLeft] then GLCamera1.MoveAroundTarget(mdy -y, mdx -x);
  mdx := x;
  mdy := y;
end;

procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  GLCamera1.AdjustDistanceToTarget(Power(1.02, WheelDelta/120));
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  GLCamera1.FocalLength := MinInteger(Height, Width) / 10;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #27 then close;
end;

end.
