unit unitExportCenterlinesSilhouettesToGIS;
// 2021-09-28: Bug fixé dans l'export OSM

{$INCLUDE CompilationParameters.inc}
interface
uses
  {$INCLUDE SelectionLangues.inc} // insère les unités en fonction de la langue
  StructuresDonnees, GHTopoGeneralFunctions, unitDatesUtils, unitGHTopoViseesUtils, unitGHTopoStringUtils,  unitColorsUtils, unitSolveEquationsPolynomes,  Classes, SysUtils, Math, // anciennement Include
  ToporobotClasses2012,
  UnitEntitesExtended,
  UnitListesSimplesWithGeneriques,
  UnitKMLExport,
  UnitLeafletExport,
  UnitExportGeoJSON,
  //UnitDXFDrawing,
  UnitObjetSerie,
  ConvertisseurJPC,
  Graphics

  ;
type TExportCenterLinesSilhouettes = set of (expgisCENTERLINES, expgisSILHOUETTES, expgisENTRANCES, expgisPOIs, expgisNODES);
type TColoredBy = (expgisCOLOR_BY_DEFAULT, expgisCOLOR_BY_ENTRANCES, expgisCOLOR_BY_RESEAUX, expgisCOLOR_BY_SEANCES);

type

{ TExportGIS }

 TExportGIS = class
  private
    FConvertisseur                : TConversionSysteme;
    FDocTopo                      : TToporobotStructure2012;
    FDocumentTitle                : string;
    FBDDEntites                   : TBDDEntites;
    FProcProgression              : TProcDisplayProgression;
    FExportCenterLinesSilhouettes : TExportCenterLinesSilhouettes;
    FColoredBy                    : TColoredBy;
    FCenterlineColor              : TColor;
    FCenterlineOpacity            : byte;
    FSilhouetteColor              : TColor;
    FSilhouetteOpacity            : byte;
    FMyEPSG                       : TLabelSystemesCoordsEPSG;
    FCenterlineWidth              : double;

    function ExtractAndConvertBasePointBySerSt(const Ser: TNumeroSerie; const St: integer; out QLat, QLon, QAlt: double): boolean;
    function MakeSilhouetteOfSerie(const S: TObjSerie; out QPolygoneSilhouette: TArrayOfTProjUV): boolean;


  public
    function Initialiser(const QConvertisseur                : TConversionSysteme;
                          const QDocTopo                     : TToporobotStructure2012;
                          const QDocumentTitle               : string;
                          const QBDDEntites                  : TBDDEntites;
                          const QProcDisplayProgression      : TProcDisplayProgression;
                          const QExportCenterLinesSilhouettes: TExportCenterLinesSilhouettes;
                          const QColoredBy                   : TColoredBy;
                          const QCenterlineColor             : TColor;
                          const QCenterlineOpacity           : byte;
                          const QCenterlineWidth             : double;
                          const QSilhouetteColor             : TColor;
                          const QSilhouetteOpacity           : byte): boolean;
    procedure Finaliser();
    function  ExporterToKML(const QFilename: TStringDirectoryFilename): boolean;
    function  ExporterToOSM(const QFilename: TStringDirectoryFilename;
                            const MapWidthInPercent, MapHeightInPixels: integer;
                            const UseLocalJSLibraries: boolean): boolean;
    function  ExporterToGeoJSON(const QFilename: TStringDirectoryFilename): boolean;
    function  ExporterToDXF(const QFilename: TStringDirectoryFilename): boolean;

end;

implementation
uses
  DGCDummyUnit;



{ TExportGIS }

function TExportGIS.Initialiser(const QConvertisseur               : TConversionSysteme;
                                const QDocTopo                     : TToporobotStructure2012;
                                const QDocumentTitle: string;
                                const QBDDEntites                  : TBDDEntites;
                                const QProcDisplayProgression      : TProcDisplayProgression;
                                const QExportCenterLinesSilhouettes: TExportCenterLinesSilhouettes;
                                const QColoredBy                   : TColoredBy;
                                const QCenterlineColor             : TColor;
                                const QCenterlineOpacity           : byte;
                                const QCenterlineWidth             : double;
                                const QSilhouetteColor             : TColor;
                                const QSilhouetteOpacity           : byte): boolean;
begin
  Result := false;
  try
    AfficherMsgClass(self, 'Initialiser()');
    FConvertisseur   := QConvertisseur;
    FDocTopo         := QDocTopo;
    FDocumentTitle   := QDocumentTitle;
    FBDDEntites      := QBDDEntites;
    FProcProgression := QProcDisplayProgression;
    FExportCenterLinesSilhouettes := QExportCenterLinesSilhouettes;
    FColoredBy                    := QColoredBy;

    FCenterlineColor              := QCenterlineColor;
    FCenterlineWidth              := QCenterlineWidth;
    FCenterlineOpacity            := QCenterlineOpacity;

    FSilhouetteColor              := QSilhouetteColor;
    FSilhouetteOpacity            := QSilhouetteOpacity;

    FMyEPSG                       := FConvertisseur.GetEPSGSystemeFromCodeEPSG(FDocTopo.CodeEPSGSystemeCoordonnees.CodeEPSG);
    result := true;
  except
    pass;
  end;
end;

procedure TExportGIS.Finaliser();
begin
  pass;
end;
function TExportGIS.ExtractAndConvertBasePointBySerSt(const Ser: TNumeroSerie; const St: integer; out QLat, QLon, QAlt: double): boolean;
var
  EE: TBaseStation;
  PP: TProjUV;
begin
  Result := FBDDEntites.GetEntiteViseeFromSerSt(Ser, St, EE);
  if (Result) then
  begin
    PP := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, EE.PosStation.X, EE.PosStation.Y);
    QLat := PP.U;
    QLon := PP.V;
    QAlt := EE.PosStation.Z;
  end;
end;

function TExportGIS.MakeSilhouetteOfSerie(const S: TObjSerie; out QPolygoneSilhouette: TArrayOfTProjUV): boolean;
var
  NbVisees, QIR, i, QIL: Integer;
  NumSerie  : TNumeroSerie;
  MyStation : TBaseStation;
  MyPoint   : TProjUV;
  QListeVx  : TListeSimple<TProjUV>;
  QNbVx: LongInt;
begin
  result := false;
  NbVisees := S.NbVisees;
  NumSerie := S.NumeroDeSerie;
  //AfficherMessageErreur('MakeSilhouetteOfSerie(%s - %d visees', [S.NomSerie, NbVisees]));
  if (NbVisees < 2) then Exit(false);
  QListeVx := TListeSimple<TProjUV>.Create;
  try
    try
      QListeVx.ClearListe();
      for i := 1 to NbVisees - 1 do
      begin
        if (not FBDDEntites.GetEntiteViseeFromSerSt(NumSerie, i, MyStation)) then continue;
        if (1 = i) then
        begin
          MyPoint := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyStation.PosOPD.X, MyStation.PosOPD.Y);
          //QListeVx.AddElement(MyPoint);
        end;
        MyPoint := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyStation.PosPD.X, MyStation.PosPD.Y);
        QListeVx.AddElement(MyPoint);
      end;
      for i := NbVisees - 1 downto 1 do
      begin
        if (not FBDDEntites.GetEntiteViseeFromSerSt(NumSerie, i, MyStation)) then continue;
        if (1 = i) then
        begin
          MyPoint := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyStation.PosOPG.X, MyStation.PosOPG.Y);
        end;
        MyPoint := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyStation.PosPG.X, MyStation.PosPG.Y);
        QListeVx.AddElement(MyPoint);
      end;
      // et on ferme le polygone
      QListeVx.AddElement(QListeVx.GetElement(0));
      QNbVx := QListeVx.GetNbElements();
      QPolygoneSilhouette.SetCapacity(QNbVx);
      for i := 0 to QNbVx - 1 do QPolygoneSilhouette.SetElement(i, QListeVx.GetElement(i));
      result := true;
    except
      AfficherMessageErreur('*** Failed: MakeSilhouetteOfSerie(%d: "%s" (%d visees))', [S.NumeroDeSerie, S.NomSerie, NbVisees]);
    end;
  finally
    FreeAndNil(QListeVx);
  end;
end;

function TExportGIS.ExporterToKML(const QFilename: TStringDirectoryFilename): boolean;
const
  KML_PREFIX_STYLE_RESEAU = 'StyleReseau';
  KML_FOLDER_CENTERLINES          = 'centerlines';
  KML_FOLDER_ENTRANCES            = 'entrances';
  KML_STYLE_CENTERLINE_BY_DEFAULT = 'DefaultStyleCenterline';
  function QMakeStylenameReseau(const QIdx: integer): string;
  begin
    result := format('%s%d', [KML_PREFIX_STYLE_RESEAU, QIdx]);
  end;

var
  DC: TKMLExport;
  procedure QExporterCenterLines();
  var
    i, Nb, s, NbSts: Integer;
    MySerie: TObjSerie;
    QLat, QLon, QAlt: double;
    EWE: String;
    RS: TReseau;
  begin

    AfficherMessage(Format ('--> Styles: %d styles', [FDocTopo.NbReseaux + 1]));
    // styles par défault
    DC.DefineStylePoly(KML_STYLE_CENTERLINE_BY_DEFAULT, FCenterlineWidth, FCenterlineColor, FSilhouetteColor, FCenterlineOpacity, FSilhouetteOpacity);
    // styles par réseaux
    Nb := FDocTopo.NbReseaux;
    for i := 0 to Nb-1 do
    begin
      RS := FDocTopo.GetReseau(i);
      DC.DefineStylePoly(QMakeStylenameReseau(i), FCenterlineWidth, RS.ColorReseau, RS.ColorReseau, FCenterlineOpacity, FSilhouetteOpacity);
    end;
    AfficherMessage(Format ('--> Centerlines: %d series', [Nb]));




    Nb := FDocTopo.NbSeries;
    DC.BeginFolder(4, KML_FOLDER_CENTERLINES);
    DC.WriteCommentaire(Format('Centerlines: %d series', [Nb]));
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      //AfficherMessage('Serie: %d - %s', [MySerie.NumeroDeSerie, MySerie.NomSerie]));
      EWE := Format('Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      DC.WriteCommentaire(EWE);
      //DC.BeginPolyline(Format('Serie%d', [MySerie.NumeroDeSerie]), KML_STYLE_CENTERLINE_BY_DEFAULT, format('%d', [MySerie.NumeroDeSerie]));
      DC.BeginPolyline(Format('Serie%d', [MySerie.NumeroDeSerie]), QMakeStylenameReseau(MySerie.NumeroReseau), format('%d', [MySerie.NumeroDeSerie]));
      if (ExtractAndConvertBasePointBySerSt(MySerie.NoSerieDep,
                                            MySerie.NoPointDep,
                                            QLat, QLon, QAlt))
      then DC.AddVertex(QLat, QLon, QAlt, False);
      NbSts := MySerie.NbVisees;
      for s := 1 to NbSts - 1 do
      begin
        if (ExtractAndConvertBasePointBySerSt(MySerie.NumeroDeSerie, s, QLat, QLon, QAlt))
        then DC.AddVertex(QLat, QLon, QAlt, true);
      end;
      DC.EndPolyline();
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 10);
    end;
    DC.EndFolder(4, KML_FOLDER_CENTERLINES);
  end;
  (* TODO: A implémenter
  procedure QExporterSilhouettes();
  var
    i, Nb: Integer;
    QPolygoneSilhouette: TArrayOfTProjUV;
    MySerie: TObjSerie;
    EWE: String;
  begin
    Nb := FDocTopo.GetNbSeries();
    AfficherMessage(Format ('--> Silhouettes: %d series', [Nb]));
    QPolygoneSilhouette.Empty();
    if (Nb < 2) then exit;
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      EWE := Format('Silhouettes: Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      if (MakeSilhouetteOfSerie(MySerie, QPolygoneSilhouette)) then
      begin
        // TODO: A faire
      end;
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 10);
    end;
  end;
  //*)
  procedure QExporterEntrances();
  var
    i, Nb: Integer;
    MyEntrance: TEntrance;
    PP: TProjUV;
    EWE: String;
  begin
    Nb := FDocTopo.NbEntrances;
    AfficherMessage(Format ('--> Entrances: %d entrances', [Nb]));
    DC.BeginFolder(4, KML_FOLDER_ENTRANCES);
    for i := 0 to Nb - 1 do
    begin
      try
        MyEntrance := FDocTopo.GetEntrance(i);
        EWE := Format('%d: %s', [i, MyEntrance.eNomEntree]);
        PP := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyEntrance.ePosition.X, MyEntrance.ePosition.Y);

        DC.AddPlacemarkPoint(MyEntrance.ePosition.X,
                             MyEntrance.ePosition.Y,
                             MyEntrance.ePosition.Z,
                             PP.U, PP.V,
                             XML_real_escape_string(MyEntrance.eNomEntree),
                             format(FMTSERST, [MyEntrance.eRefSer, MyEntrance.eRefSt]),
                             '', '', '');

        if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 10);
      except
        on E: Exception do AfficherMessageErreur('*** Entrance %d: %s - %s', [i, MyEntrance.eNomEntree, E.Message]);
      end;
    end;
    DC.EndFolder(4, KML_FOLDER_ENTRANCES);
  end;
  procedure QExporterPOIs();
   begin
     //AfficherMessage(Format ('--> Points of interest: %d POIs', [Nb]));
   end;
   procedure QExporterNodes();
   begin
     AfficherMessage('--> Nodes: %d nodes', [FBDDEntites.NbJonctions]);
   end;
begin
  result := false;
  AfficherMsgClass(self, 'ExporterToKML(): %s', [QFilename]);
  FBDDEntites.SortBySerSts();  // Trier par séries et stations
  DC := TKMLExport.Create;
  try
    if (DC.Initialiser(QFilename, FDocumentTitle)) then
    begin
      if (expgisCENTERLINES in FExportCenterLinesSilhouettes) then QExporterCenterLines();
      //if (expgisSILHOUETTES in FExportCenterLinesSilhouettes) then QExporterSilhouettes();
      if (expgisENTRANCES   in FExportCenterLinesSilhouettes) then QExporterEntrances();
      if (expgisPOIs        in FExportCenterLinesSilhouettes) then QExporterPOIs();
      if (expgisNODES       in FExportCenterLinesSilhouettes) then QExporterNodes();
      DC.Finaliser();
    end;
    result := True;
  finally
    FreeAndNil(DC);
  end;
  FBDDEntites.SortByDepth();   // et retrier la table

end;

function TExportGIS.ExporterToOSM(const QFilename: TStringDirectoryFilename;
                                  const MapWidthInPercent, MapHeightInPixels: integer;
                                  const UseLocalJSLibraries: boolean):boolean;
const
  OSM_STYLE_CENTERLINE_BY_DEFAULT = 'DefaultStyleCenterline';
  OSM_STYLE_SILHOUETTE_BY_DEFAULT = 'DefaultStyleSilhouettes';

var
  DC: TLeafletExport;
  ID_LAYER_CENTERLINES: integer;
  ID_LAYER_ENTRANCES  : integer;
  ID_LAYER_SILHOUETTES: integer;
  ID_LAYER_POIs       : integer;
  ID_LAYER_NODES      : integer;
  C1, C2: TPoint3Df;
  MyCentroide: TProjUV;
  procedure QExporterEntrances();
  var
    i, Nb      : Integer;
    PP         : TProjUV;
    EWE        : String;
    MyEntrance : TEntrance;
    QLayer: TOSMLayer;
  begin
    Nb := FDocTopo.NbEntrances;
    QLayer := DC.GetLayer(ID_LAYER_ENTRANCES);
    DC.BeginConditionalSection(True);
      for i := 0 to Nb - 1 do
      begin
        MyEntrance := FDocTopo.GetEntrance(i);
        EWE := Format('%d: %s', [i, MyEntrance.eNomEntree]);
        PP := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyEntrance.ePosition.X, MyEntrance.ePosition.Y);
        DC.AddMarker(QLayer.LayerVarName,
                     MyEntrance.ePosition.X,
                     MyEntrance.ePosition.Y,
                     MyEntrance.ePosition.Z,
                     PP.U, PP.V,
                     format(FMTSERST, [MyEntrance.eRefSer, MyEntrance.eRefSt]),
                     XML_real_escape_string(MyEntrance.eNomEntree),
                     '',
                     XML_real_escape_string(MyEntrance.eObserv),
                     ''  // pas de photo
                     );
        if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 10);
      end;
    DC.FlushAllMarkers();
    DC.EndConditionalSection();
  end;
  procedure QExporterCenterLines();
  var
    i, Nb, NbSts, s : Integer;
    MySerie         : TObjSerie;
    QLat, QLon, QAlt: double;
    EWE             : String;
    QLayer: TOSMLayer;
  begin
    Nb := FDocTopo.NbSeries;
    QLayer := DC.GetLayer(ID_LAYER_CENTERLINES);
    DC.BeginConditionalSection(True);
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      NbSts := MySerie.NbVisees;
      if (Nb < 2) then Continue;
      EWE := Format('Centerlines: Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      DC.BeginPolyline(QLayer.LayerVarName, Format('Serie%d', [MySerie.NumeroDeSerie]), OSM_STYLE_CENTERLINE_BY_DEFAULT);
        if (ExtractAndConvertBasePointBySerSt(MySerie.NoSerieDep, MySerie.NoPointDep, QLat, QLon, QAlt))
        then DC.AddVertex(QLat, QLon, QAlt, False);
        NbSts := MySerie.NbVisees;
        for s := 1 to NbSts - 1 do
        begin
          if (ExtractAndConvertBasePointBySerSt(MySerie.NumeroDeSerie, s, QLat, QLon, QAlt))
          then DC.AddVertex(QLat, QLon, QAlt, s = (NbSts-1));
        end;
      DC.EndPolyline();
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 10);
    end;
    DC.EndConditionalSection();
  end;
  procedure QExporterSilhouettes();
  var
    i, Nb, v, QNbVx, NbV: Integer;
    QPolygoneSilhouette: TArrayOfTProjUV;
    QLayer: TOSMLayer;
    MySerie: TObjSerie;
    EWE: String;
    PV: TProjUV;
  begin
    Nb := FDocTopo.NbSeries;
    QLayer := DC.GetLayer(ID_LAYER_SILHOUETTES);
    DC.BeginConditionalSection(True);

    AfficherMessage('--> Silhouettes: %d series', [Nb]);
    AfficherMessageErreur('--> Silhouettes: %d series', [Nb]);

    QPolygoneSilhouette.Empty();
    if (Nb < 2) then exit;
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      EWE := Format('Silhouettes: Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      if (MakeSilhouetteOfSerie(MySerie, QPolygoneSilhouette)) then
      begin
        NbV := QPolygoneSilhouette.GetNbElements();
        if (NbV > 3) then
        begin
          DC.BeginPolygon(QLayer.LayerVarName, Format('Serie: %d: %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]), '');
          for v := 0 to nbV - 1 do
          begin
            PV := QPolygoneSilhouette.GetElement(v);
            DC.AddVertex(PV.U, PV.V, 0.00, v = (NbV -1)); //QPolygoneSilhouette.GetNbElements() - 1));
          end;
          DC.EndPolygon();
        end;
      end;
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 10);
    end;
    AfficherMessageErreur('-- Silhouettes séries OK');
    DC.EndConditionalSection();
  end;
  procedure QExporterPOIs();
  var
    i, Nb: Integer;
    QLayer: TOSMLayer;
    MyPOI: TGHTopoPointOfInterest;
    EWE: String;
    QLat, QLon, QAlt: double;
  begin
    Nb := FDocTopo.NbPointsOfInterests;
    AfficherMessage(Format ('--> Points of interest: %d POIs', [Nb]));
    if (0 = Nb) then exit;
    QLayer := DC.GetLayer(ID_LAYER_POIs);
    DC.BeginConditionalSection(True);
      for i := 0 to Nb - 1 do
      begin
        MyPOI := FDocTopo.GetPointOfInterest(i);
        EWE := Format('POIs: %d: %d.%d: %s', [i, MyPOI.Serie, MyPOI.Station, MyPOI.Description]);
        if (ExtractAndConvertBasePointBySerSt(MyPOI.Serie, MyPOI.Station, QLat, QLon, QAlt)) then
        begin
          DC.AddMarker(QLayer.LayerVarName,
                       MyPOI.Position.X, MyPOI.Position.Y, MyPOI.Position.Z,
                       QLat, QLon,
                       XML_real_escape_string(MyPOI.toString()),
                       XML_real_escape_string(MyPOI.Description),
                       Format('X = %s, Y = %s, Z = %s', [
                         FormatterNombreAvecSepMilliers(MyPOI.Position.X),
                         FormatterNombreAvecSepMilliers(MyPOI.Position.Y),
                         FormatterNombreAvecSepMilliers(MyPOI.Position.Z)]),
                        '',
                        '' // pas de photo
                     );
        end;
        if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 1);
      end;
    DC.FlushAllMarkers();
    DC.EndConditionalSection();
  end;
  procedure QExporterNodes();
  var
    Nb, i : Integer;
    MyNode: TJonctionXYZ;
    QLayer: TOSMLayer;
    EWE: String;
    PP: TProjUV;
  begin
    Nb := FBDDEntites.NbJonctions;
    AfficherMessage(Format ('--> Nodes: %d nodes', [Nb]));
    QLayer := DC.GetLayer(ID_LAYER_NODES);
    DC.BeginConditionalSection(True);
      for i := 0 to Nb - 1 do
      begin
        MyNode := FBDDEntites.GetJonction(i);
        EWE := Format('Jonctions: %d: %d%d', [i, MyNode.NoSer, MyNode.NoSt]);
        PP := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyNode.Position.X, MyNode.Position.Y);
        DC.AddMarker(QLayer.LayerVarName,
                     MyNode.Position.X, MyNode.Position.Y, MyNode.Position.Z,
                     PP.U, PP.V,
                     MyNode.ToString(),
                     MyNode.IDJonction,
                     Format('X = %s, Y = %s, Z = %s', [
                        FormatterNombreAvecSepMilliers(MyNode.Position.X),
                        FormatterNombreAvecSepMilliers(MyNode.Position.Y),
                        FormatterNombreAvecSepMilliers(MyNode.Position.Z)
                     ]),
                     '',
                     '' // pas de photo
                     );
        if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 100);
      end;
    DC.FlushAllMarkers();
    DC.EndConditionalSection();
  end;
begin
  result := false;
  AfficherMsgClass(self, 'ExporterToOSM(): %s)', [QFilename]);
  FBDDEntites.SortBySerSts();  // Trier par séries et stations
  DC := TLeafletExport.Create;
  try
    C1 := FBDDEntites.CoinBasGauche;
    C2 := FBDDEntites.CoinHautDroit;
    // calcul du centroide
    MyCentroide := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, 0.50 * (C1.X + C2.X), 0.50 * (C1.Y + C2.Y));
    if (DC.Initialiser(QFilename, FDocumentTitle, MapWidthInPercent, MapHeightInPixels,  MyCentroide.U, MyCentroide.V, UseLocalJSLibraries)) then
    begin
      DC.DefineStylePoly(OSM_STYLE_CENTERLINE_BY_DEFAULT, FCenterlineWidth, FCenterlineColor, FSilhouetteColor, FCenterlineOpacity, FSilhouetteOpacity);
      DC.AddLayer(false, true, 'entrances'  , 'Entrees'           , 'GHTopo', ''    , ssCIRCLE ,  5.00, clRed    , 0.50);
      ID_LAYER_ENTRANCES   := DC.GetNbLayers() - 1;
      DC.AddLayer(false, true, 'centerlines', 'Polygonales'       , 'GHTopo', ''    , ssCIRCLE ,  5.00, clBlue   , 0.50);
      ID_LAYER_CENTERLINES := DC.GetNbLayers() - 1;
      DC.AddLayer(false, true, 'silhouettes', 'Silhouettes'       , 'GHTopo', ''    , ssCIRCLE ,  5.00, clGreen  , 0.50);
      ID_LAYER_SILHOUETTES := DC.GetNbLayers() - 1;
      DC.AddLayer(false, true, 'POIs'       , 'Points d''intérêt' , 'GHTopo', ''    , ssDELTA  ,  5.00, clRed    , 0.50);
      ID_LAYER_POIs        := DC.GetNbLayers() - 1;
      DC.AddLayer(false, true, 'noeuds'     , 'Noeuds'            , 'GHTopo', ''    , ssDIAMOND,  2.50, clYellow , 0.50);
      ID_LAYER_NODES       := DC.GetNbLayers() - 1;
      DC.WriteHeader();
      AfficherMessageErreur('-- Header OK');
      if (expgisCENTERLINES in FExportCenterLinesSilhouettes) then QExporterCenterLines();
      AfficherMessageErreur('-- Centerlines OK');
      if (expgisSILHOUETTES in FExportCenterLinesSilhouettes) then QExporterSilhouettes();
      AfficherMessageErreur('-- Silhouettes OK');
      if (expgisENTRANCES   in FExportCenterLinesSilhouettes) then QExporterEntrances();
      AfficherMessageErreur('-- Entrances OK');
      if (expgisPOIs        in FExportCenterLinesSilhouettes) then QExporterPOIs();
      AfficherMessageErreur('-- POIs OK');
      if (expgisNODES       in FExportCenterLinesSilhouettes) then QExporterNodes();
      AfficherMessageErreur('-- Nodes OK');
      DC.WriteFooter();
      AfficherMessageErreur('-- Footer OK');
      DC.Finaliser();
      AfficherMessageErreur('-- Finaliser OK');
    end;
    result := True;
  finally
    FreeAndNil(DC);
  end;
  FBDDEntites.SortByDepth();   // et retrier la table
end;


function TExportGIS.ExporterToGeoJSON(const QFilename: TStringDirectoryFilename): boolean;
var
  DC: TGeoJSONExport;
  ID_LAYER_CENTERLINES: integer;
  ID_LAYER_ENTRANCES  : integer;
  ID_LAYER_SILHOUETTES: integer;
  ID_LAYER_POIs       : integer;
  ID_LAYER_NODES      : integer;
  MyPointCG: TProjUV;
  // calcul des centroides
  procedure QCalcCentroid();
  var
    C1, C2: TPoint3Df;
  begin
    C1 := FBDDEntites.CoinBasGauche;
    C2 := FBDDEntites.CoinHautDroit;
    MyPointCG.setFrom(0.50 * (C1.X + C2.X), 0.50 * (C1.Y + C2.Y));
    MyPointCG := FConvertisseur.ConversionSyst1ToSyst2ByCodeEPSG(FMyEPSG.CodeEPSG, CODE_EPSG_WGS84, MyPointCG);
  end;
  procedure QExporterCenterLines();
  var
    Nb, i, s, NbSts: Integer;
    MySerie: TObjSerie;
    EWE: String;
    QLat, QLon, QAlt: double;
  begin
    Nb := FDocTopo.NbSeries;
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      NbSts := MySerie.NbVisees;
      if (Nb < 2) then Continue;
      EWE := Format('Centerlines: Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      DC.BeginPolyline(Format('Serie%d', [MySerie.NumeroDeSerie]), '');
        if (ExtractAndConvertBasePointBySerSt(MySerie.NoSerieDep, MySerie.NoPointDep, QLat, QLon, QAlt))
        then DC.AddVertex(QLat, QLon, QAlt, False);
        for s := 1 to NbSts - 1 do
        begin
          if (ExtractAndConvertBasePointBySerSt(MySerie.NumeroDeSerie, s, QLat, QLon, QAlt))
          then DC.AddVertex(QLat, QLon, QAlt, s = (NbSts-1));
        end;
      DC.EndPolyline(i = (Nb - 1));
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 10);
    end;
  end;
  procedure QExporterSilhouettes();
  var
    i, v, Nb: Integer;
    QPolygoneSilhouette: TArrayOfTProjUV;
    MySerie: TObjSerie;
    EWE: String;
    PV: TProjUV;
  begin
    Nb := FDocTopo.NbSeries;
    AfficherMessage(Format ('--> Silhouettes: %d series', [Nb]));
    QPolygoneSilhouette.Empty();
    if (Nb < 2) then exit;
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      EWE := Format('Silhouettes: Serie: %d - %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]);
      if (MakeSilhouetteOfSerie(MySerie, QPolygoneSilhouette)) then
      begin
        DC.BeginPolygon(Format('Serie: %d: %s', [MySerie.NumeroDeSerie, XML_real_escape_string(MySerie.NomSerie)]), '');
          for v := 0 to QPolygoneSilhouette.GetNbElements() - 1 do
          begin
            PV := QPolygoneSilhouette.GetElement(v);
            DC.AddVertex(PV.U, PV.V, 0.00, v = (QPolygoneSilhouette.GetNbElements() - 1));
          end;
        DC.EndPolygon(i = (Nb - 1));
      end;
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 10);
    end;
  end;
begin
  result := false;
  AfficherMsgClass(self, 'ExporterToGeoJSON(): %s', [QFilename]);
  FBDDEntites.SortBySerSts();  // Trier par séries et stations
  DC := TGeoJSONExport.Create;
  try
    QCalcCentroid();
    AfficherMessageErreur('--> Centroid: Lon: %.8f, Lat: %.8f', [MyPointCG.V, MyPointCG.U]);
    if (DC.Initialiser(QFilename,'Cavite001', MyPointCG.V, MyPointCG.U, clRed, 255)) then
    begin
      DC.AddLayer('entrances');
      DC.AddLayer('centerlines');
      DC.AddLayer('silhouettes');
      DC.AddLayer('POIs');
      DC.AddLayer('noeuds');
      DC.WriteHeader();
      // le dessin ici
      if (expgisCENTERLINES in FExportCenterLinesSilhouettes) then QExporterCenterLines();
      if (expgisSILHOUETTES in FExportCenterLinesSilhouettes) then
      begin
        DC.WriteLine(',');    // virgule indispensable pour séparer les chapitres
        QExporterSilhouettes();
      end;
      DC.WriteFooter();
      DC.Finaliser();
    end;
    result := True;
  finally
    FreeAndNil(DC);
  end;
  FBDDEntites.SortByDepth();   // et retrier la table
end;


function TExportGIS.ExporterToDXF(const QFilename: TStringDirectoryFilename): boolean;
const
  //LAYER_0               = 'Layer0';                ID_LAYER_0              = 0;
  LAYER_ENTRANCES       = 'ENTRANCES';             ID_LAYER_ENTRANCES      = 1;
  LAYER_CENTERLINES     = 'CENTERLINES';           ID_LAYER_CENTERLINES    = 2;
  LAYER_RADIANT_SHOTS   = 'RADIANTSHOTS';          ID_LAYER_RADIANT_SHOTS  = 3;
  LAYER_CROSS_SECTIONS  = 'CROSSSECTIONS';         ID_LAYER_CROSS_SECTIONS = 4;
  LAYER_STATIONS        = 'STATIONS';              ID_LAYER_STATIONS       = 5;
  LAYER_SILHOUETTES     = 'SILHOUETTES';           ID_LAYER_SILHOUETTES    = 6;
  LAYER_NOEUDS          = 'NOEUDS';                ID_LAYER_NOEUDS         = 7;
var
  ewe : integer;
  (*
  MyExport: TDXFExport;
  C1, C2: TPoint3Df;
  procedure QExporterCenterLines();
  var
    i, Nb, NbSts, s : Integer;
    MySerie         : TObjSerie;
    QLayer: TDXFLayer;
    EE, VR: TBaseStation;
    EWE: String;
  begin
    Nb := FDocTopo.GetNbSeries();
    QLayer := MyExport.GetLayer(ID_LAYER_CENTERLINES);
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      EWE := Format('Centerlines: Serie: %d - %s', [MySerie.NumeroDeSerie, MySerie.NomSerie]);
      MyExport.BeginPolyline(QLayer.LayerName);
        if (FBDDEntites.GetEntiteViseeFromSerSt(MySerie.NoSerieDep, MySerie.NoPointDep, EE))
        then MyExport.AddVertex(QLayer.LayerName, EE.PosStation.X, EE.PosStation.Y, EE.PosStation.Z);
        NbSts := MySerie.NbVisees;
        for s := 1 to NbSts - 1 do
        begin
          if (FBDDEntites.GetEntiteViseeFromSerSt(MySerie.NumeroDeSerie, s, EE)) then
            MyExport.AddVertex(QLayer.LayerName, EE.PosStation.X, EE.PosStation.Y, EE.PosStation.Z);
        end;
      MyExport.EndPolyline(QLayer.LayerName);
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 100);
    end;
    // sections
    QLayer := MyExport.GetLayer(ID_LAYER_CROSS_SECTIONS);
    for i := 1 to Nb - 1 do
    begin
      MySerie := FDocTopo.GetSerie(i);
      EWE := Format('Sections: Serie: %d - %s', [MySerie.NumeroDeSerie, MySerie.NomSerie]);
      NbSts := MySerie.NbVisees;
      for s := 1 to NbSts - 1 do
      begin
        if (FBDDEntites.GetEntiteViseeFromSerSt(MySerie.NumeroDeSerie, s, EE)) then
        MyExport.DrawLine(QLayer.LayerName, EE.PosPD.X, EE.PosPD.Y, EE.PosPD.Z, EE.PosPG.X, EE.PosPG.Y, EE.PosPG.Z);
      end;
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 1, Nb, 100);
    end;
    // visées radiantes
    QLayer := MyExport.GetLayer(ID_LAYER_RADIANT_SHOTS);
    Nb := FBDDEntites.GetNbEntitesAntennes();
    if (Nb > 0) then
    begin
      for i := 1 to Nb - 1 do
      begin
        VR := FBDDEntites.GetEntiteAntenne(i);
        MyExport.DrawLine(QLayer.LayerName, VR.PosExtr0.X, VR.PosExtr0.Y, VR.PosExtr0.Z, VR.PosStation.X, VR.PosStation.Y, VR.PosStation.Z);
        if (assigned(FProcProgression) and (0 = i mod 2000)) then
        begin
          EWE := Format('Radiantes: %d / %d', [i, Nb]);
          FProcProgression(EWE, i, 1, Nb, 1000);
        end;
      end;
    end;
  end;
  procedure QExporterNodes();
  const
    QR = 1.00;
  var
    Nb, i: Integer;
    MyNode: TJonctionXYZ;
    QLayer: TDXFLayer;
    EWE: String;
  begin
    Nb := FBDDEntites.GetNbJonctions();
    AfficherMessage(Format ('--> Nodes: %d nodes', [Nb]));
    QLayer := MyExport.GetLayer(ID_LAYER_NOEUDS);
    for i := 0 to Nb - 1 do
    begin
      MyNode := FBDDEntites.GetJonction(i);
      EWE := Format('Jonctions: %d: %d%d', [i, MyNode.NoSer, MyNode.NoSt]);
      MyExport.DrawCircle(QLayer.LayerName, MyNode.Position.X, MyNode.Position.Y, MyNode.Position.Z, QR);
      //MyExport.DrawTexte(QLayer.LayerName, MyNode.X + QR, MyNode.Y + QR, MyNode.Z, 3.00, Format(FMTSERST, [MyNode.NoSer, MyNode.NoSt]));
      if (assigned(FProcProgression)) then FProcProgression(EWE, i, 0, Nb, 100);
    end;
  end;
  //*)
begin
  result := false;
  AfficherMsgClass(self, 'ExporterToDXF(): %s', [QFilename]);
  (*
  MyExport := TDXFExport.Create;
  FBDDEntites.SortBySerSts();  // Trier par séries et stations
  try
    if (MyExport.Initialiser(QFilename)) then
    begin
      C1 := FBDDEntites.GetCoinBasGauche();
      C2 := FBDDEntites.GetCoinHautDroit();
      MyExport.SetLimitesDessin(C1, C2);
      MyExport.AddLayer(LAYER_0             , 32, 0);
      MyExport.AddLayer(LAYER_ENTRANCES     , 64, 1);
      MyExport.AddLayer(LAYER_CENTERLINES   , 80, 5);
      MyExport.AddLayer(LAYER_RADIANT_SHOTS , 64, 1);
      MyExport.AddLayer(LAYER_CROSS_SECTIONS, 64, 1);
      MyExport.AddLayer(LAYER_STATIONS      , 64, 1);
      MyExport.AddLayer(LAYER_SILHOUETTES   , 84, 1);
      MyExport.AddLayer(LAYER_NOEUDS        , 83, 1);
      MyExport.writeHeader();
      if (expgisCENTERLINES in FExportCenterLinesSilhouettes) then QExporterCenterLines();
      //if (expgisSILHOUETTES in FExportCenterLinesSilhouettes) then QExporterSilhouettes();
      //if (expgisENTRANCES   in FExportCenterLinesSilhouettes) then QExporterEntrances();
      //if (expgisPOIs        in FExportCenterLinesSilhouettes) then QExporterPOIs();
      if (expgisNODES       in FExportCenterLinesSilhouettes) then QExporterNodes();
      MyExport.writeFooter();
      MyExport.Finaliser();
    end;
  finally
    FreeAndNil(MyExport);
  end;
  //*)
  FBDDEntites.SortByDepth();   // et retrier la table
end;

end.

