{$mode objfpc}{$H+}
unit uUncertainty;

// CC 20260322 uncertainty zone diamond create/update/remove helpers

interface

uses
  Graphics,
  TGClasses, Globe4, TGSysUtils, GlobeUtils, TGPresenters, TGObjects,
  uHCTypeDefs, uHCUtils;

procedure CreateUncertaintyZone(aGlobe: TGlobe4; aLayer: TGlobeLayer;
  aColor: TColor; var ioNextID: Integer;
  out presID, objID: Integer);

procedure UpdateUncertaintyZone(aLayer: TGlobeLayer;
  objID, presID: Integer;
  const pRegion: PURegion; aColor: TColor; visible: Boolean);

procedure RemoveUncertaintyZone(aLayer: TGlobeLayer; presID, objID: Integer);

function UncertaintyCenter(const pRegion: PURegion): TPointLL;

implementation

procedure CreateUncertaintyZone(aGlobe: TGlobe4; aLayer: TGlobeLayer;
  aColor: TColor; var ioNextID: Integer;
  out presID, objID: Integer);
var
  lPres:    TPolylinePresenter;
  lDataObj: TGeoDataObject;
begin
  lPres := TPolylinePresenter.Create(aGlobe, 0);
  lPres.PolyPen.PenColor := aColor;
  aLayer.Presenters.Add(lPres);
  presID := lPres.PresenterID;

  lDataObj := TGeoDataObject.Create(aLayer.Objects);
  lDataObj.PresenterID := lPres.PresenterID;
  lDataObj.ID          := ioNextID;
  lDataObj.Centroid    := PointLLH(0, 0, 0);
  lDataObj.Chains[0].Count := 0;
  objID := ioNextID;
  Inc(ioNextID);
end;

procedure UpdateUncertaintyZone(aLayer: TGlobeLayer;
  objID, presID: Integer;
  const pRegion: PURegion; aColor: TColor; visible: Boolean);
var
  lObj:    TGlobeObject;
  lPres:   TGlobePresenter;
  lChain:  TPointStore;
  pts:     array[0..3] of TPointLL;
  i:       Integer;
begin
  lObj := aLayer.ObjectByID(objID);
  if lObj = nil then Exit;

  lPres := aLayer.Presenters.ByID(presID, False);
  if lPres <> nil then
    TPolylinePresenter(lPres).PolyPen.PenColor := aColor;

  lChain := TGeoDataObject(lObj).Chains[0];

  if visible and (pRegion <> nil) then
  begin
    // CC 20260322 convert 4 sliver corner pairs to TPointLL
    for i := 0 to 3 do
      pts[i] := PointLLH(
        DecimalToGlobeUnits(HCLon2Deg(pRegion^.sLon[i])),
        DecimalToGlobeUnits(HCLat2Deg(pRegion^.sLat[i])),
        0);

    // Write 5 points: vertices 0..3 then 0 again to close the diamond
    lChain.Count := 0;
    for i := 0 to 3 do
      lChain.Add(pts[i]);
    lChain.Add(pts[0]);

    // Update centroid to average position
    TGeoDataObject(lObj).Centroid := UncertaintyCenter(pRegion);

    TGeoDataObject(lObj).RedrawObject;
  end
  else
    lChain.Count := 0;
end;

procedure RemoveUncertaintyZone(aLayer: TGlobeLayer; presID, objID: Integer);
var
  lObj:  TGlobeObject;
  lPres: TGlobePresenter;
begin
  if presID < 0 then Exit;

  lObj := aLayer.ObjectByID(objID);
  if lObj <> nil then
  begin
    aLayer.Objects.Delete(lObj);
    lObj.Free;
  end;

  lPres := aLayer.Presenters.ByID(presID, False);
  if lPres <> nil then
  begin
    aLayer.Presenters.Delete(lPres);
    lPres.Free;
  end;
end;

function UncertaintyCenter(const pRegion: PURegion): TPointLL;
var
  avgLon, avgLat: LongInt;
begin
  avgLon := (pRegion^.sLon[0] + pRegion^.sLon[1] +
             pRegion^.sLon[2] + pRegion^.sLon[3]) div 4;
  avgLat := (pRegion^.sLat[0] + pRegion^.sLat[1] +
             pRegion^.sLat[2] + pRegion^.sLat[3]) div 4;
  Result := PointLLH(
    DecimalToGlobeUnits(HCLon2Deg(avgLon)),
    DecimalToGlobeUnits(HCLat2Deg(avgLat)),
    GlobeUnitsFrom(0.1, Mile));
end;

end.
