Jump to content
Sign in to follow this  
Linuxuser1234

Shapefiles not projecting to TSphere

Recommended Posts

trying to get shapefiles to display on a TSphere Component  in BOLT.pas(UNIT 1/Form1) from GISEngine.pas 

i tried this  

function TGISEngine.RenderShp: boolean;
begin
GISobj.Viewport3D1.Parent := Earth;
end;

but that doesnt do anything here is the full unit 

unit GISEngine;
//thank you  programmerdelphi2k for helping 
//This unit Displays Shapefiles onto a 3D Globe
interface
uses
  System.SysUtils,
  System.Classes,
  FMX.Viewport3D,
  FMX.Objects3D,
  System.IOUtils,
  System.Generics.Collections,
  BOLT;

type
  TGISFilesnamesSHP = TArray<string>;
  TGISEngine = class
  private
    FFilenames : TList<string>;
    Viewport3D1: TViewport3D;
    Earth:       TSphere;

    function GetFilename(const i: integer): string;
  public
    constructor Create; overload;
    constructor Create(const AFilenames: TGISFilesnamesSHP); overload;
    destructor Destroy; override;
    procedure AddFilenames(const AFilenames: TGISFilesnamesSHP);
    procedure ClearFilenames;
    function CountFilenames: integer;
    function RenderShp: boolean;
    property Filename[const i: integer]: string read GetFilename;
    property Filenames: TList<string> read FFilenames;
    function VerifyIfAllFilesSHPExists(out AErrors: TGISFilesnamesSHP): boolean;
    function LoadFilenames: boolean;
    property GISViewport3D: TViewport3D read Viewport3D1 write Viewport3D1;
    property GISEarth: TSphere read Earth write Earth;
  end;
 var
 GISobj : TGISEngine;
 Form1: TForm1;
implementation
{ TGISEngine }

constructor TGISEngine.Create;
begin
  Viewport3D1 := TViewport3D.Create(nil);
  Earth      := TSphere.Create(nil);
  FFilenames  := TList<string>.Create;
end;

constructor TGISEngine.Create(const AFilenames: TGISFilesnamesSHP);
begin
  Create;
  AddFilenames(AFilenames);
end;

destructor TGISEngine.Destroy;
begin
  FFilenames.Free;
  Earth.Free;
  Viewport3D1.Free;
  inherited;
end;

function TGISEngine.GetFilename(const i: integer): string;
begin
  result := '';
  if (i > -1) and (i < FFilenames.Count) then
    result := FFilenames.Items[i];
end;


procedure TGISEngine.ClearFilenames;
begin
  FFilenames.Clear;
end;

function TGISEngine.CountFilenames: integer;
begin
  result := FFilenames.Count;
end;
procedure TGISEngine.AddFilenames(const AFilenames: TGISFilesnamesSHP);
var F: string;
begin
  if (Length(AFilenames) > 0 ) then
    for F in AFilenames do
      if not FFilenames.Contains(F) then
      FFilenames.Add(F);
end;

function TGISEngine.VerifyIfAllFilesSHPExists(out AErrors: TGISFilesnamesSHP): boolean;
var
F: string;
begin
  result := false;
  if (FFilenames.Count = 0) then
    begin
      AErrors := ['Filenames list is empty'];
      exit;
    end;
  for  F in FFilenames do
    if not FileExists(F) then
      AErrors := AErrors + [F + ', dont exists!'];
end;

function TGISEngine.LoadFilenames: boolean;
var F: string;
begin
  result := false;
  if (FFilenames.Count > 0) then
    begin
    for F in Filenames do
    GISobj.AddFilenames(['tl_2021_01001_roads.shp','world-administrative-boundaries.shp']);
end;
end;

function TGISEngine.RenderShp: boolean;
begin
GISobj.Viewport3D1.Parent := Earth;
end;

initialization
GISobj := TGISEngine.Create;
finalization
GISobj.Free;
end.

 

Edited by Linuxuser1234

Share this post


Link to post

hi @Linuxuser1234

 

Quote

function TGISEngine.LoadFilenames: boolean;  --> you already load (list of files) in "procedure TGISEngine.AddFilenames(const AFilenames: TGISFilesnamesSHP);"

then, to "load", in fact, should be another way on final usage of this class...

 

for example: 

xxxxx.READmyDATASHPFromFiles;

begin

for F in FFilenames do

   MyDataFromFileSHP.readdata( F );  //  MyDataFromFileSHP can be a list with each data from each file... if the value is very "big", then, try another way to store it on memory... and release it after usage!

 

note that GISobj is a instance of "TGISEngine", and it dont really do nothing, in fact!

try to assing your "Earth" on form where is the "3Dviewport" not in GISObj

Edited by programmerdelphi2k

Share this post


Link to post

try this way to store your "file names" and "data from each file:

uses
  System.Generics.Collections;

type
  TMyFileNames   = TArray<string>;
  TMyDataFromSHP = string; { just for show the idea } // this type is dependent of "how the data are stored into SHP file", you see?

// ...
var
  MyFileNames      : TMyFileNames;
  MyDataFromFileSHP: TDictionary<string, TMyDataFromSHP>; // this can replace your FFilenames=TList<string>
begin
  // create on "Create"-class
  MyDataFromFileSHP := TDictionary<string, TMyDataFromSHP>.Create;
  //
  for var F in MyFileNames do
    MyDataFromFileSHP.Add(F, 'my data into SHP file');

  // destroy it on "Destroy"-class
  MyDataFromFileSHP.Free; //
end;

Share this post


Link to post
Quote

function TGISEngine.VerifyIfAllFilesSHPExists(out AErrors: TGISFilesnamesSHP): boolean;

change to


procedure TGISEngine.VerifyIfAllFilesSHPExists(out AErrors: TGISFilesnamesSHP);  // not need result because you are using "Out AErrors", then, if Lenght(AErros)>0 then... exists a error msg!

 

Quote

function TGISEngine.LoadFilenames: boolean;

...

result := XXXList.Count > 0;  // false or true

 

Share this post


Link to post

you're mixing things up now! or you use your TList<string> or new way TDictionary, look my text above:

  • TMyDataFromSHP = string; { just for show the idea } // this type is dependent of "how the data are stored into SHP file", you see?
Quote

    MyListWithString.Add( 'Filename1.shp' );  // your way

 

   //  or new way using TDictionary

   // here you'll have that open your "filename1" and get the data (values into file... if is it possible) for example, if the data is very big, then as said above, you need another way

    MyDataFromFileSHP.Add('Filename1.shp', 'my data into filename1 is hello world');  // here the values will be "the file content", NOT Filenames list!!!
    MyDataFromFileSHP.Add('Filename2.shp', 'my data into filename2 is hello world ');

 

  • First, I dont know the file content is stored: binary, string, etc... 
    • open file, read content, store it on MyDataFromFileSHP dictionary!
  • the content is very big, or moderated? 

 

Let's use a example:

  • a file1.SHP have its content like a coordenates using in SVG files... then, the content is not big, can be read on memory easely!
  • now, if you read many files SHP in same time, and all together needs a big memory volume, then, this it's not desirable, too!
Edited by programmerdelphi2k

Share this post


Link to post
  • What size (average) SHP file do you want to read in your application?
  • What is the content of this file? Is it a binary? Is it some strings? What type of data?
  • How many files do you need to read at any given time? 1, 2, 100, etc.?

Share this post


Link to post

look this sample using a Dictionary:

unit uMyClass;

interface

uses
  System.SysUtils,
  System.Classes,
  System.Generics.Collections;

type
  TMySHPDataValues = string;
  TMyDic           = TDictionary<string, TMySHPDataValues>;

  //
  TMyClass = class // not inherited from other...
  private
    FMyFileSHPwithData: TMyDic;
    //
    function GetMyCountFiles: integer;
    function GetMyFileNames: TArray<string>;
  public
    constructor Create;
    destructor Destroy; override;
    //
    procedure AddFilesAndData(const AFilename: string);
    procedure RemoveFilesOnList(const AFilename: string);
    procedure RemoveAllFilesOnList;
    //
    property MyCountFiles: integer read GetMyCountFiles;
    property MyFileNames: TArray<string> read GetMyFileNames;
    property MyFilesAndData: TMyDic read FMyFileSHPwithData;
  end;

implementation

{ TMyClass }

constructor TMyClass.Create;
begin
  FMyFileSHPwithData := TMyDic.Create; // TDictionary<string, TMySHPDataValues>.Create;
end;

destructor TMyClass.Destroy;
begin
  FMyFileSHPwithData.Free;
  //
  inherited;
end;

function TMyClass.GetMyCountFiles: integer;
begin
  result := FMyFileSHPwithData.Count;
end;

function TMyClass.GetMyFileNames: TArray<string>;
begin
  result := [];
  //
  for var F in FMyFileSHPwithData do
    result := result + [F.Key];
end;

procedure TMyClass.RemoveFilesOnList(const AFilename: string);
begin
  if (AFilename <> '') and (FMyFileSHPwithData.Count > 0) then
    FMyFileSHPwithData.Remove(AFilename); // if not exits, nothing happens!
end;

procedure TMyClass.RemoveAllFilesOnList;
begin
  FMyFileSHPwithData.Clear;
end;

procedure TMyClass.AddFilesAndData(const AFilename: string);
var
  MyFileContent: string;
begin
  if (AFilename <> '') { and FileExists(AFilename) } then
    begin
      // now, you need open the file and read all content to store it on dictionary...
      // How are you going to do this? It depends on the content of the file...
      //
      // each file will have a content, of course!!!
      //
      // ... let's say that content is like a strings:  C1, L2, A54, V100, hello, world, etc...
      MyFileContent := 'C1, L2, A54, V100, hello, world, etc...';
      //
      // if already exists, just replace value
      FMyFileSHPwithData.AddOrSetValue(AFilename, MyFileContent);
    end;
end;

end.
implementation

{$R *.fmx}

uses
  uMyClass;

var
  MyFilesSHP: TArray<string>;

var
  MyClass: TMyClass = nil;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (MyClass = nil) then
    exit;
  //
  MyClass.RemoveAllFilesOnList;
  //
  MyFilesSHP := ['file1.shp', 'file2.shp'];
  //
  for var F in MyFilesSHP do
    MyClass.AddFilesAndData(F);
  //
  for var F in MyClass.MyFilesAndData do
    Memo1.Lines.Add('File: ' + F.Key + ', Content: ' + F.Value);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if (MyClass <> nil) then
    Memo1.Lines.AddStrings(MyClass.MyFileNames);
end;

initialization

ReportMemoryLeaksOnShutdown := true;
MyClass                     := TMyClass.Create;

finalization

MyClass.Free;

end.

image.thumb.png.0506076e424b45d1783f6e07e3b860b4.png

Edited by programmerdelphi2k

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×