Autor Beitrag
Myribo
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mi 19.11.08 09:41 
wubderschönen guten morgen... ;)

entschuldigt, wenn dieses thread nicht in der richtigen sparte ist, ich dachte allerdings, dass algorithmen und optimierung schon mal zutrifft.. =)

sooo, nun zu meinem anliegen:
vor kurzem bin ich auf die datenbank OpenStreetMap aufmerksam geworden.
ich hatte mir vorher schon einen kleinen A* pathfinder zusammengebastelt, der dann auch ganz gut funktionierte.
jtzt habe ich mir als ziel gesetzt, ein "echtes" navigationssystem zu basteln, bzw. eigentlich zu programmieren...!
ich bekomme die rohdaten als *osm files, diese beinhalten aber nur xml... so weit, so gut, ich benutze als parser den JvSimpleXML von den Jedis. das einlesen der daten geht auch ganz gut, allerdings höchstens nur für eine stadt...
die datei meiner stadt (bielefeld) ist ca. 4,8 MB groß. das bekommt er in ca. 4-5 sekunden hin. allerdings ist ganz deutschland 2,7 GB groß und selbst NRW allein 450 MB....!!!

...Out Of Memory ...! :(
und selbst wenns gehen würde, müsste man wahrscheinlich echt lange warten... ;)

ich poste auch einfach mal den code von einem selbstgeschriebenem programm, das die datei nochmal splitten und vereinfachen soll... allerdings muss dieses ja auch mit den riesigen osm dateien was anfangen lönnen...:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
procedure TfrmCreator.btnCreateClick(Sender: TObject);
var MapFS:TFileStream;
    i,y:Integer;
    ThisItem,NewElem,NewWPElem:TJvSimpleXMLElem;
begin
  btnCreate.Enabled:=False;

  MapFS:=TFileStream.Create('input/'+edtInput.Text,fmOpenRead);
  XML.LoadFromStream(MapFS);
  MapFS.Destroy;

  for i:=0 to pred(XML.Root.Items.Count) do
  begin
    ThisItem:=XML.Root.Items.Item[i];

    // Ist ein (Knoten-)Punkt
    if ThisItem.Name='node' then
    begin
      NewElem:=XMLWaypoints.Root.Items.Add(ThisItem.Properties.ItemNamed['id'].Value);
      NewElem.Items.Add('X',ThisItem.Properties.ItemNamed['lon'].Value);
      NewElem.Items.Add('Y',ThisItem.Properties.ItemNamed['lat'].Value);
      XMLWaypoints.Root.Items.Add(NewElem);
    end
    else if ThisItem.Name='way' then
    begin
      NewElem:=XMLStreets.Root.Items.Add(ThisItem.Properties.ItemNamed['id'].Value);

      NewWPElem:=NewElem.Items.Add('waypoints');
      for y:=0 to pred(ThisItem.Items.Count) do
      begin
        // Ist ein Wegpunkt...
        if ThisItem.Items.Item[y].Name='nd' then
          NewWPElem.Items.Add('wp',ThisItem.Items.Item[y].Properties.ItemNamed['ref'].Value)
        // Ist eine Eigenschaft...
        else if (ThisItem.Items.Item[y].Name='tag'AND (ThisItem.Items.Item[y].Properties.ItemNamed['k'].Value='name'then
          NewElem.Items.Add('name',UTF8ToAnsi(ThisItem.Items.Item[y].Properties.ItemNamed['v'].Value))
        else if (ThisItem.Items.Item[y].Name='tag'AND (ThisItem.Items.Item[y].Properties.ItemNamed['k'].Value='highway'then
          NewElem.Items.Add('type',ThisItem.Items.Item[y].Properties.ItemNamed['v'].Value);
      end;
      TRY
        if (NewElem.Items.ItemNamed['name'].Value<>''OR (NewElem.Items.ItemNamed['type'].Value<>''then
          XMLStreets.Root.Items.Add(NewElem);
      EXCEPT
        // Die Straße hat keinen Namen oder keinen Typ... Mit dem Auto wahrscheinlich nicht befahrbar!
      END;
    end;
  end;

  XMLWaypoints.SaveToFile('output/Waypoints.xml');
  XMLStreets.SaveToFile('output/Streets.xml');

  btnCreate.Enabled:=True;
end;



nun natürlich meine frage:
wie bewältige, bzw. lese ich diese verdammt großen dateien (aus), ohne gleich die ganze datei einzulesen. gibts vielleicht irgendwelche xml komponenten, die mit so etwas fertig werden?


ich bedanke mich schon einmel (auch fürs lesen :P) und hoffe, es kann mir vielleicht jemand weiterhelfen...
lieben gruß
myribo
freedy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 403
Erhaltene Danke: 1

Winows 7
Delphi XE
BeitragVerfasst: Mi 19.11.08 10:43 
Hi!

Warum willst du eigentlich die ganze Datei einlesen? Die kleinen Navigationsgeräte, die dann sogar ganz Europa speichern, können das auch nicht. Vielleicht kannst du dir eine Methode überlegen, wie du sequentiell durch die XML-Datei gehst und nur die Daten rausholst, die du wirklich brauchst.

Grüße
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mi 19.11.08 11:23 
Ich schätze, dafür gibt es Datenbanken. Nicht, das die die XML-Daten direkt speichern (obwohl das auch ginge), aber da es eine XML-Struktur gibt, kann man die ganz einfach in eine DB konvertieren und dann ein Import-Tool schreiben, das die XML-Datei häppchenweise einließt und in die DB bläst.

_________________
Na denn, dann. Bis dann, denn.
Myribo Threadstarter
Hält's aus hier
Beiträge: 6



BeitragVerfasst: So 23.11.08 22:02 
puuuuh, hab mir euren rat zu herzen genommen und hab jetzt ein kleines tool gebastelt, welches die dateien durchgeht und das ganze in eine mysql datenbank schaufelt (mit "mysql direct")... das ist schon einmal wesentlich übersichtlicher und die abfrage geht in sekundenbruchteilen ;) schönen dank für die anregung mit der db...!

sooo, ich stehe jetzt nur leider vor einem anderen problem... ich lese im hauptprogramm die ganze db aus und speicher diese in arrays. das klappt auch ganz gut. atm schreibe ich die methode, welche die map zeichnet. ich poste mal eben den code...

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
procedure TfrmMain.DrawMap(Mitte:String);
var MitteX,MitteY:Double;
    i,y:Integer;
    firststreetwp:Boolean;
    streetid:String;
begin
  for i:=0 to High(Streets) do
  begin
    // Wegpunkte durchgehen
    firststreetwp:=true;
    streetid:=Streets[i].ID;
    // [-> PUNKT 2 <-]
    for y:=0 to High(Waypoints) do
    begin
      // [-> PUNKT 2 <-]
      if Waypoints[i].Street=streetid then
      begin
        if firststreetwp then
          imgMap.Canvas.MoveTo(Round(ZOOM*GeoPoints[GetPointByID(Waypoints[i].Point)].lat),Round(ZOOM*GeoPoints[GetPointByID(Waypoints[i].Point)].lon))
        else
          imgMap.Canvas.LineTo(Round(ZOOM*GeoPoints[GetPointByID(Waypoints[i].Point)].lat),Round(ZOOM*GeoPoints[GetPointByID(Waypoints[i].Point)].lon));
        showmessage('ka-boom');

        firststreetwp:=false;
      end;
    end;
  end;
end;


und hiermit werden vorher die arrays gefüllt:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
procedure TfrmMain.FormCreate(Sender: TObject);
var i:Integer;
begin
  SQL:=TMySQLClient.Create;
  SQL.Host:='localhost';
  SQL.User:='Myribo';
  SQL.Password:='meinpw';
  SQL.Db:='navi';
  SQL.Connect;

  AllPointsSQL:=mysql_query('SELECT * FROM points');
  AllPointsSQL.First;
  SetLength(GeoPoints,AllPointsSQL.RowsCount);
  for i:=0 to pred(AllPointsSQL.RowsCount) do
  begin
    GeoPoints[i].ID:=AllPointsSQL.FieldValue(0);
    GeoPoints[i].lat:=StringToFloat(AllPointsSQL.FieldValue(1));
    GeoPoints[i].lon:=StringToFloat(AllPointsSQL.FieldValue(2));
    AllPointsSQL.Next;
  end;

  AllWayPointsSQL:=mysql_query('SELECT * FROM waypoints');
  AllWayPointsSQL.First;
  SetLength(Waypoints,AllWayPointsSQL.RowsCount);
  for i:=0 to pred(AllWayPointsSQL.RowsCount) do
  begin
    Waypoints[i].Street:=AllWayPointsSQL.FieldValue(0);
    Waypoints[i].Point:=AllWayPointsSQL.FieldValue(1);
    AllWayPointsSQL.Next;
  end;

  AllStreetsSQL:=mysql_query('SELECT * FROM streets');
  AllStreetsSQL.First;
  SetLength(Streets,AllStreetsSQL.RowsCount);
  for i:=0 to pred(AllStreetsSQL.RowsCount) do
  begin
    Streets[i].ID:=AllStreetsSQL.FieldValue(0);
    Streets[i].StreetType:=AllStreetsSQL.FieldValue(1);
    Streets[i].StreeName:=AllStreetsSQL.FieldValue(2);
    AllStreetsSQL.Next;
  end;

  ZOOM:=1000;
  SQL.Close;
end;


sooo nun das problem:
füge ich "showmessage(streetid)" bei punkt 1 ein ,bekomme ich etwas anderes, als wenn ich das ganze bei punkt 2 reinschreiben würde. bei punkt 2 bekomme ich immer das gleiche. bei jedem durchgang. in der db steht aber eindeutig etwas anderes. als wenn die arrayfelder mit irgendetwas "verknüpft" wären. vielleicht liegt das problem ja schon an der zuweisung...?!

es wäre total super, wenn mir noch einmal jemand helfen könnte...
schönen dank schon einmal ;)
lg myribo
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 24.11.08 09:11 
Bei Datenbanken muss man manchmal etwas warten, bis diese ihre Daten wirklich im Record-Set liefern. ggf. mal kurz Application.ProcessMessages; aufrufen, bevor DU die Daten ausliest.

Wieso übergibst Du Mitte als String. Sollte dass nicht ein TPoint sein?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Myribo Threadstarter
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mo 24.11.08 15:45 
heyho! =)
erstmal schönen dank für deine antwort!

leider leider bringt das ganze aber gar nichts... )=
Streets[i].I hängt immer noch auf einem wert, wenn ich es in der for-schleife für High(Waypoints) ausgeben lassen will...
vor dem schleifenstart passt alles! komisch...! :(

zu deiner frage: die mitte ist in meinem fall ein punkt, für den ich die id (Mitte) reinschmeiße. außerdem wäre ein TPoint für längen- und breitengrade viel zu ungenau... hab mir aber schon ne klasse dafür gebastelt ;)

lg
myribo!