const
  cFormWidth  = 350;
  cFormHeight = 150;

var
  FThreshold: Integer;
  FAreaIndex: TStringList;

  AForm: TvxSceneForm;
  AFormCaption: String;
  AThreshold: TvxNumberBox;

function BuildForm: TvxSceneForm;
var
  ALabel: TvxLabel;
  AEdit: TvxTextBox;
  ACombo: TvxPopupBox;
  AOk: TvxButton;
  ASave: TvxButton;
  ALoad: TvxButton;
  AMacroButton: TvxButton;
  ASampleButton: TvxButton;
begin
  result := TvxSceneForm.Create(nil);
  result.Caption  := AFormCaption;
  result.Position := poScreenCenter;
  result.Width := Round(cFormWidth * result.DPIFactor);
  result.Height := Round(cFormHeight * result.DPIFactor);

  ALabel := TvxLabel.Create(result.Root);
  result.Root.AddObject(ALabel);
  ALabel.Text := 'Overlap Threshold %';
  ALabel.TextAlign := vgTextAlignNear;
  ALabel.Position.Point := vgPoint(20, 20);

  AEdit := TvxNumberBox.Create(result.Root);
  result.Root.AddObject(AEdit);
  TvxNumberBox(AEdit).Min := 1;
  TvxNumberBox(AEdit).Max := 100;
  AEdit.Width := 200;
  TvxNumberBox(AEdit).Value := FThreshold;
  AEdit.Position.Point := vgPoint(ALabel.Position.X, ALabel.Position.Y + ALabel.Height + 0);
  AThreshold := AEdit;

  AOk := TvxButton.Create(result.Root);
  result.Root.AddObject(AOk);
  AOk.ModalResult := mrOk;
  AOk.Position.Point := vgPoint(AEdit.Position.X, (result.Height / result.DPIFactor) - 10 - AOk.Height);
  AOk.Text := 'OK';
  AOk.Default := True;
end;

function Initialize: Boolean;
begin
  result := True;

  FAreaIndex := TStringList.Create;

  FHit := 0;
  FThreshold    := 10;  // allow overlap of 10%
  FThreshold    := ReadFromRegistry ('Scripts', 'FilterOverlapAreas', FThreshold);

  AFormCaption := 'Filter Overlapping Areas';
  AForm := BuildForm;
  AForm.ShowModal;
  result := (AForm.ModalResult = mrOk);
  if result then
    FThreshold := Trim(AThreshold.Value);
  AForm.Free;
end;

procedure Finalize;
var
  i: Integer;
begin
  WriteToRegistry ('Scripts', 'FilterOverlapAreas', FThreshold);

  for i := 0 to FAreaIndex.Count - 1 do
  begin
    FAreaIndex.Objects[i].Free;
    FAreaIndex.Objects[i] := nil;
  end;

  FAreaIndex.Free;
end;

function FindAreasForImage(AImage: TImageItem): TCatalogAreas;
var
  AIdx: Integer;
begin
  AIdx := FAreaIndex.IndexOf(AImage.GUID);
  if AIdx = -1 then
  begin
    result := TCatalogAreas.Create(TCatalogArea, '');
    FAreaIndex.AddObject(AImage.GUID, result);
    PublicCatalog.EnumAreasForImage(AImage, result);
  end
  else
    result := TCatalogAreas(FAreaIndex.Objects[AIdx]);
end;

function HasAreaOverlap(AAreas: TCatalogAreas; AThreshold: Integer): Boolean;
var
  i, j: Integer;
  ARect1, ARect2, AOverlap: TvxRect;
  ARect1Surface, ARect2Surface, AOverlapSurface: Double;
  AThresholdFactor: Double;
begin
  result := False;

  AThresholdFactor := AThreshold / 100;

  for i := 0 to AAreas.Count - 1 do
  begin
    ARect1 := vgRect(
                      AAreas.Items[i].AreaLeft,
                      AAreas.Items[i].AreaTop,
                      AAreas.Items[i].AreaRight,
                      AAreas.Items[i].AreaBottom
                    );
    ARect1Surface := vgRectWidth(ARect1) * vgRectHeight(ARect1);
    if ARect1Surface > 0.0 then
    begin
      for j := 0 to AAreas.Count - 1 do
      begin
        if i = j then Continue;

        ARect2 := vgRect(
                          AAreas.Items[j].AreaLeft,
                          AAreas.Items[j].AreaTop,
                          AAreas.Items[j].AreaRight,
                          AAreas.Items[j].AreaBottom
                        );

        ARect2Surface := vgRectWidth(ARect2) * vgRectHeight(ARect2);
        if ARect2Surface > 0.0 then
        begin
          AOverlap := vgRect(0, 0, 0, 0);
          if vgIntersectRect(AOverlap, ARect1, ARect2) then
          begin
            // check the threshold
            AOverlapSurface := vgRectWidth(AOverlap) * vgRectHeight(AOverlap);

            if (AOverlapSurface / ARect1Surface) > AThresholdFactor then
              result := True;
          end;
        end;

        if result then break;
      end;
    end;

    if result then break;
  end;
end;

procedure BeforeFilter;
begin
  Screen.Cursor := crHourglass;
end;

procedure AfterFilter;
begin
  Screen.Cursor := crDefault;
end;

function Filter(AItem: TImageItem): Boolean;
var
  AAreas: TCatalogAreas;
begin
  result := False;
  if (FThreshold < 0) or (FThreshold > 100) then
    exit;

  AAreas := FindAreasForImage(AItem);
  if AAreas.Count = 0 then
    exit;

  result := HasAreaOverlap(AAreas, FThreshold);
end;
