Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi wie kann ich bestimmte Infos aus Textdokument einlesen? (https://www.delphipraxis.net/168443-wie-kann-ich-bestimmte-infos-aus-textdokument-einlesen.html)

Boyington 21. Mai 2012 19:54

wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Leute,
weiß Jemand vielleicht, wie ich alle Koordinaten aus einem Textdokument (*.stl Datei im ASCII Format) einlesen und dann in einer Liste speichern kann? Da ich mich mit Text- oder StringVerarbeitung in Delphi nicht gut auskenne.

*.stl Datei (ASCII Format) sieht wie folgendes aus:

Code:
solid ascii
  facet normal 2.445222e-016 0.000000e+000 1.000000e+000
    outer loop
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal 2.445222e-016 -5.090141e-032 1.000000e+000
    outer loop
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
    endloop
  endfacet
.
.
.
.
 facet normal 7.071068e-001 -1.471962e-016 7.071068e-001
    outer loop
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
    endloop
  endfacet
endsolid
Jedes 3D-Objekt besteht aus vielen kleinen Dreiecken und jedes Dreieck besteht aus 1x normal (Nomalvektor) und 3x vertex (Koordinaten der 3 Eckpunkten von jedem Dreieck).

Meine Frage ist: wie kann ich vom Anfang bis zum Ende der *.stl Datei alle Normalvektoren (als type: TVektor) und alle Koordinaten der 3 Eckpunkten von jedem Dreieck in einer Liste speichern (die Liste soll dynamisch sein, weil die Länge der Liste vorher nicht bekannt ist)?

Typen sehen ungefähr wie folgendes aus:
Code:
type
  TVektor = record
    x, y, z: real;
  end;
  TDreieck = record
    n: TVektor; // n ist Normalvektor
    p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
  end;
.
.
.
.
Var
  hDreieck : ^TDreieck;
Ich bitte euch um die Hilfe und bin sehr dankbar für die Antwort wie immer ;-)

Gruss
Lee

Amateurprofi 21. Mai 2012 22:44

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Versuch es mal hiermit.
Ich habe die von dir gezeigten daten ins Clipboard kopiert
und von dort in die StringList geschrieben.
Alle Daten wurden korrekt gelesen.
Du solltest das mit list.LoadFromFile machen.
Delphi-Quellcode:
type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
Var
   hDreieck : ^TDreieck;
   Dreiecke:Array of TDreieck;

PROCEDURE TMain.Test;
const
   recstart='facet normal';
   recline='vertex';
var list:TStrings; line:integer; data:TDreieck;
FUNCTION FindLine(const s:string; raiseerr:boolean):boolean;
begin
   while (line<list.count) and (Copy(Trim(list[line]),1,Length(s))<>s) do inc(line);
   if line<list.count then result:=true
      else if not raiseerr then result:=false
         else raise Exception.Create(s+' nicht gefunden.');
end;
FUNCTION ReadNumber(const s:string; var i:integer):real;
var j:integer;
begin
   j:=i;
   while s[j]<>' ' do dec(j);
   result:=StrToFloat(Copy(s,j+1,i-j));
   while s[j]=' ' do dec(j);
   i:=j;
end;
PROCEDURE ReadLine(var v:TVektor);
var s:string; i:integer;
begin
   s:=Trim(list[line]);
   i:=Length(s);
   v.z:=ReadNumber(s,i);
   v.y:=ReadNumber(s,i);
   v.x:=ReadNumber(s,i);
   inc(line);
end;
PROCEDURE ReadRecord;
var i:integer;
begin
   ReadLine(data.n);
   for i:=1 to 3 do begin
      FindLine(recline,true);
      ReadLine(data.p[i]);
   end;
   SetLength(Dreiecke,Length(Dreiecke)+1);
   Dreiecke[High(dreiecke)]:=data;
end;
// var f:TextFile; i,j:integer; // nur zur Kontrolle benutzt
begin
   Dreiecke:=nil;
   list:=TStringList.Create;
   try
      try
         list.text:=Clipboard.AsText;
         // oder List.LoadFromFile('Filename');
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            Dreiecke:=nil;
         end;
      end;
   finally
      list.free;
   end;
end;

Boyington 22. Mai 2012 06:34

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Morgen alle,
vielen Dank für die nette Antwort, Klaus!
Ich werde später selbst auch mal probieren, ob die bei mir geht.

l.g
Lee

Boyington 23. Mai 2012 22:27

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Amateurprofi (Beitrag 1167521)
Versuch es mal hiermit.
Ich habe die von dir gezeigten daten ins Clipboard kopiert
und von dort in die StringList geschrieben.
Alle Daten wurden korrekt gelesen.
Du solltest das mit list.LoadFromFile machen.
Delphi-Quellcode:
type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
Var
   hDreieck : ^TDreieck;
   Dreiecke:Array of TDreieck;

PROCEDURE TMain.Test;
const
   recstart='facet normal';
   recline='vertex';
var list:TStrings; line:integer; data:TDreieck;
FUNCTION FindLine(const s:string; raiseerr:boolean):boolean;
begin
   while (line<list.count) and (Copy(Trim(list[line]),1,Length(s))<>s) do inc(line);
   if line<list.count then result:=true
      else if not raiseerr then result:=false
         else raise Exception.Create(s+' nicht gefunden.');
end;
FUNCTION ReadNumber(const s:string; var i:integer):real;
var j:integer;
begin
   j:=i;
   while s[j]<>' ' do dec(j);
   result:=StrToFloat(Copy(s,j+1,i-j));
   while s[j]=' ' do dec(j);
   i:=j;
end;
PROCEDURE ReadLine(var v:TVektor);
var s:string; i:integer;
begin
   s:=Trim(list[line]);
   i:=Length(s);
   v.z:=ReadNumber(s,i);
   v.y:=ReadNumber(s,i);
   v.x:=ReadNumber(s,i);
   inc(line);
end;
PROCEDURE ReadRecord;
var i:integer;
begin
   ReadLine(data.n);
   for i:=1 to 3 do begin
      FindLine(recline,true);
      ReadLine(data.p[i]);
   end;
   SetLength(Dreiecke,Length(Dreiecke)+1);
   Dreiecke[High(dreiecke)]:=data;
end;
// var f:TextFile; i,j:integer; // nur zur Kontrolle benutzt
begin
   Dreiecke:=nil;
   list:=TStringList.Create;
   try
      try
         list.text:=Clipboard.AsText;
         // oder List.LoadFromFile('Filename');
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            Dreiecke:=nil;
         end;
      end;
   finally
      list.free;
   end;
end;

Guten Abend, Leute
Zwei Fragen an dich, Klaus:

1)für SetLength(Dreiecke,Length(Dreiecke)+1), Length(Dreiecke)+1 darf nur zwischen 0...255 sein, oder? Wenn ein 3D-Objekt z.B nur aus weniger als 255 Dreiecken besteht, ist es in Ordnung, aber wenn es aus 10000 Dreiecken besteht, wie mache ich mit dieser Funktion Dreiecke[256], Dreiecke[257]....bis Dreiecke[10000]?

2)wie kann man nach dem Einlesen der *.stl Datei und nach dem Schreiben aller Koordinaten in Variable "Dreiecke"(array of TDreieck) alle dort gespeicherte Koordinaten wieder in Clipboard kopieren? Damit kann ich alle in Variable "Dreiecke" gespeicherten Koordinaten mit den original Koordinaten mal vergleichen und überprüfen, ob es richtig ist.

Danke für die Antwort im Voraus!

l.g
Lee

Amateurprofi 24. Mai 2012 00:43

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Boyington (Beitrag 1167809)
Guten Abend, Leute
Zwei Fragen an dich, Klaus:

1)für SetLength(Dreiecke,Length(Dreiecke)+1), Length(Dreiecke)+1 darf nur zwischen 0...255 sein, wenn ein 3D-Objekt nur aus weniger als 255 Dreiecken besteht, ist es in Ordnung, aber wenn das 3D-Objekt aus 10000 Dreiecken besteht, wie mache ich mit dieser Funktion Dreiecke[256], Dreiecke[257]....bis Dreiecke[10000]?

2)wie kann man nach dem Einlesen der *.stl Datei und nach dem Schreiben aller Koordinaten in Variable "Dreiecke"(array of TDreieck) alle dort gespeicherte Koordinaten wieder in Clipboard kopieren? Damit kann ich die original Koordinaten mit allen in Variable "Dreiecke" gespeicherten Koordinaten mal vergleichen und überprüfen, ob es richtig ist.

Danke für die Antwort im Voraus!

l.g
Lee

@Lee:

Zu (1) :
Wie kommst du auf die Beschränkung bei SetLength?
Ein dynamisches Array kannst du High(integer) lang machen.
Somit dürfte die einzige Beschränkung der verfügbare Speicherplatz sein.

Zu (2) :
So :
Delphi-Quellcode:
PROCEDURE CopyDreiecke(tofile:boolean);
var list:TStrings;
FUNCTION ToStr(v:real):String;
begin
   result:=FloatToStrF(v,ffExponent,7,3)+' ';
   if result[1]<>'-' then result:=' '+result;
end;
PROCEDURE AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;
var s,s1:string; i:integer;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;
var i,j:integer;
begin
   list:=TStringList.Create;
   try
      try
         if Length(Dreiecke)=0 then
            raise Exception.Create('Dreiecke ist leer.');
         for i:=0 to High(Dreiecke) do
            with Dreiecke[i] do begin
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt')
            else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
   end;
end;
Mit CopyDreiecke(false) stellst du die Daten ins Clipboard, mit CopyDreiecke(true) in die Datei "Log.txt" im Programmverzeichnis.

Boyington 24. Mai 2012 06:31

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Amateurprofi (Beitrag 1167827)
Zitat:

Zitat von Boyington (Beitrag 1167809)
Guten Abend, Leute
Zwei Fragen an dich, Klaus:

1)für SetLength(Dreiecke,Length(Dreiecke)+1), Length(Dreiecke)+1 darf nur zwischen 0...255 sein, wenn ein 3D-Objekt nur aus weniger als 255 Dreiecken besteht, ist es in Ordnung, aber wenn das 3D-Objekt aus 10000 Dreiecken besteht, wie mache ich mit dieser Funktion Dreiecke[256], Dreiecke[257]....bis Dreiecke[10000]?

2)wie kann man nach dem Einlesen der *.stl Datei und nach dem Schreiben aller Koordinaten in Variable "Dreiecke"(array of TDreieck) alle dort gespeicherte Koordinaten wieder in Clipboard kopieren? Damit kann ich die original Koordinaten mit allen in Variable "Dreiecke" gespeicherten Koordinaten mal vergleichen und überprüfen, ob es richtig ist.

Danke für die Antwort im Voraus!

l.g
Lee

@Lee:

Zu (1) :
Wie kommst du auf die Beschränkung bei SetLength?
Ein dynamisches Array kannst du High(integer) lang machen.
Somit dürfte die einzige Beschränkung der verfügbare Speicherplatz sein.

Zu (2) :
So :
Delphi-Quellcode:
PROCEDURE CopyDreiecke(tofile:boolean);
var list:TStrings;
FUNCTION ToStr(v:real):String;
begin
   result:=FloatToStrF(v,ffExponent,7,3)+' ';
   if result[1]<>'-' then result:=' '+result;
end;
PROCEDURE AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;
var s,s1:string; i:integer;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;
var i,j:integer;
begin
   list:=TStringList.Create;
   try
      try
         if Length(Dreiecke)=0 then
            raise Exception.Create('Dreiecke ist leer.');
         for i:=0 to High(Dreiecke) do
            with Dreiecke[i] do begin
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt')
            else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
   end;
end;
Mit CopyDreiecke(false) stellst du die Daten ins Clipboard, mit CopyDreiecke(true) in die Datei "Log.txt" im Programmverzeichnis.


Morgen Alle,
alles klar, danke für die hilfreiche Antwort:)

l.g
Lee

Boyington 28. Mai 2012 13:08

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Klaus,
ich hab dein Programm vereinfacht, aber es funktioniert einfach nicht (die *.exe Datei kann nicht mehr geschlossen werden nach der Durchführung), es scheint, dass Fehler irgendwo aufgetreten sind (wegen unendlicher Schleife???).

Code:
type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
Var
   Dreiecke:Array of TDreieck;


function ReadNumber(const s:string; var i:integer):real;
var
j:integer;
begin
j:=i;
while s[j]<>' ' do dec(j);
 result:=StrToFloat(Copy(s,j+1,i-j));
while s[j]=' ' do dec(j);
 i:=j;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  s1='facet normal';
  s2='vertex';
  s3='endsolid';

var
  s:string;
  //i:integer;
  j:integer;
  L:integer;
  List:TStrings;
  Line:integer;
  data:TDreieck;

begin
   Dreiecke:=nil;
   List:=TStringList.Create;
   List.LoadFromFile(OpenDialog1.FileName);
   Line:=1;

   while (Copy(Trim(List[Line]),1,Length(s3))<>s3) do
   begin
    s:=Trim(List[Line]);
    L:=Length(s);

    if (Copy(s,1,Length(s1))=s1) then
      begin
       data.n.z:=ReadNumber(s,L);
       data.n.y:=ReadNumber(s,L);
       data.n.x:=ReadNumber(s,L);
       inc(Line);

       while (Copy(s,1,Length(s2))<>s2) do inc(Line);
         for j:=1 to 3 do begin
          data.p[j].z:=ReadNumber(s,L);
          data.p[j].y:=ReadNumber(s,L);
          data.p[j].x:=ReadNumber(s,L);
          inc(line);
         end;

       SetLength(Dreiecke,Length(Dreiecke)+1);
       Dreiecke[High(dreiecke)]:=data;
      end

       else inc(Line);
    end;
end;
könntest du vielleicht für mich die Fehler mal suchen und dann korrigieren?
Vielen Dank!

lg
Lee

Amateurprofi 28. Mai 2012 21:51

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Boyington (Beitrag 1168374)
Hallo Klaus,
ich hab dein Programm vereinfacht, aber es funktioniert einfach nicht (die *.exe Datei kann nicht mehr geschlossen werden nach der Durchführung), es scheint, dass Fehler irgendwo aufgetreten sind (wegen unendlicher Schleife???).

Code:
type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
Var
   Dreiecke:Array of TDreieck;


function ReadNumber(const s:string; var i:integer):real;
var
j:integer;
begin
j:=i;
while s[j]<>' ' do dec(j);
 result:=StrToFloat(Copy(s,j+1,i-j));
while s[j]=' ' do dec(j);
 i:=j;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  s1='facet normal';
  s2='vertex';
  s3='endsolid';

var
  s:string;
  //i:integer;
  j:integer;
  L:integer;
  List:TStrings;
  Line:integer;
  data:TDreieck;

begin
   Dreiecke:=nil;
   List:=TStringList.Create;
   List.LoadFromFile(OpenDialog1.FileName);
   Line:=1;

   while (Copy(Trim(List[Line]),1,Length(s3))<>s3) do
   begin
    s:=Trim(List[Line]);
    L:=Length(s);

    if (Copy(s,1,Length(s1))=s1) then
      begin
       data.n.z:=ReadNumber(s,L);
       data.n.y:=ReadNumber(s,L);
       data.n.x:=ReadNumber(s,L);
       inc(Line);

       while (Copy(s,1,Length(s2))<>s2) do inc(Line);
         for j:=1 to 3 do begin
          data.p[j].z:=ReadNumber(s,L);
          data.p[j].y:=ReadNumber(s,L);
          data.p[j].x:=ReadNumber(s,L);
          inc(line);
         end;

       SetLength(Dreiecke,Length(Dreiecke)+1);
       Dreiecke[High(dreiecke)]:=data;
      end

       else inc(Line);
    end;
end;
könntest du vielleicht für mich die Fehler mal suchen und dann korrigieren?
Vielen Dank!

lg
Lee

Hallo Lee,
eigentlich verspüre ich keine große Lust den Korrektor zu spielen, wenn jemand, dem ich einen perfekt funktionierenden
Code lieferte, diesen vermeintlich "vereinfacht" und in nicht funktionierenden Code umwandelt.
Hab's mir trotzdem mal angeschaut, und ohne viel zu suchen tippe ich darauf dass das Programm in der Zeile while (Copy(s,1,Length(s2))<>s2) do inc(Line); festhängt.
Warum ?!
Weil du zwar korrekt den Zeilenzähler erhöhst, aber die neue Zeile nicht in s stellst.
In der Zeile while (Copy(s,1,Length(s2))<>s2) do inc(Line); prüfst du gegen s und das enthält "facet normal ...."
Also wird "vertex" nicht gefunden, und wenn du dann noch die Überlaufprüfung abgeschaltet hast ....

Was mir noch auffiel:
Du gibst List nicht frei.
Du sprachst in einem der Beiträge von 10000 Dreiecken.
Für 1 Dreieck werden ca. 270 Chars gebraucht für 10000 Dreiecke also 2.7 MB (oder 5.4 MB bei WideChars).
Irgendwann kriegst du dann eine Out of Memory Exception.

Das von mir gewählte Konstrukt sorgt dafür, dass
1) list immer freigegeben wird
2) Dreiecke auf nil gesetzt wird, wenn ein Fehler auftritt.
Deine "Vereinfachung" sorgt für
1) unsicheren Code
2) Memory Leaks

Denk mal darüber nach, ob solch eine Vereinfachung wirklich sinnvoll ist.

Boyington 29. Mai 2012 00:11

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Liste der Anhänge anzeigen (Anzahl: 2)
[QUOTE=Amateurprofi;1168431]
Zitat:

Zitat von Boyington (Beitrag 1168374)
Hallo Lee,
eigentlich verspüre ich keine große Lust den Korrektor zu spielen, wenn jemand, dem ich einen perfekt funktionierenden
Code lieferte, diesen vermeintlich "vereinfacht" und in nicht funktionierenden Code umwandelt.
Hab's mir trotzdem mal angeschaut, und ohne viel zu suchen tippe ich darauf dass das Programm in der Zeile while (Copy(s,1,Length(s2))<>s2) do inc(Line); festhängt.
Warum ?!
Weil du zwar korrekt den Zeilenzähler erhöhst, aber die neue Zeile nicht in s stellst.
In der Zeile while (Copy(s,1,Length(s2))<>s2) do inc(Line); prüfst du gegen s und das enthält "facet normal ...."
Also wird "vertex" nicht gefunden, und wenn du dann noch die Überlaufprüfung abgeschaltet hast ....

Was mir noch auffiel:
Du gibst List nicht frei.
Du sprachst in einem der Beiträge von 10000 Dreiecken.
Für 1 Dreieck werden ca. 270 Chars gebraucht für 10000 Dreiecke also 2.7 MB (oder 5.4 MB bei WideChars).
Irgendwann kriegst du dann eine Out of Memory Exception.

Das von mir gewählte Konstrukt sorgt dafür, dass
1) list immer freigegeben wird
2) Dreiecke auf nil gesetzt wird, wenn ein Fehler auftritt.
Deine "Vereinfachung" sorgt für
1) unsicheren Code
2) Memory Leaks

Denk mal darüber nach, ob solch eine Vereinfachung wirklich sinnvoll ist.

vielen Dank für die sehr ausführlichen Antwort und Hinweise, Klaus.
Ich hab dein erstes Programm (stl-Datei einlesen) gerade probiert, aber leider hab ich folgende Fehlermeldungen bekommen.


http://www.delphipraxis.net/attachme...1&d=1338246528

http://www.delphipraxis.net/attachme...1&d=1338246528

Wegen Fehlermeldung von "PROCEDURE TMain.Test;" (in erstem Bild) hab ich folgende code, die eigentlich zu Procedure TMain.Test gehört, in "procedure TForm1.Button2Click(Sender: TObject);" geschrieben.

const
recstart='facet normal';
recline='vertex';
var list:TStrings; line:integer; data:TDreieck;

Dann hab ich das Programm wieder durchgeführt durch Drücken von Button2 "Koordinaten der STL einlesen", bekomme ich zweite Fehlermeldung (in 2. Bild)

Boyington 29. Mai 2012 00:28

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Folgende ist mein Programm (code von dir gemacht), durch Drücken von Button2 werden STL-Datei eingelesen, und durch Drücken von Button3 wird die Liste in Log.txt gespeichert.
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GLScene, GLMisc, GLVectorFileObjects, GLWin32Viewer, GLFileSTL,
  Menus, ComCtrls, StdCtrls, ExtCtrls, GLTexture, GLObjects, GLHUDObjects;

type
    TVektor = record
    x, y, z: real;
    end;

    TDreieck = record
    n: TVektor;
    p: array[1..3] of TVektor;
    end;
.
.
.
Var
  Form1: TForm1;
  Dreiecke:array of TDreieck;
.
.
.
//PROCEDURE TMain.Test; <--bekomme ich Fehlermeldun

FUNCTION FindLine(const s:string; raiseerr:boolean):boolean;
var
  line:integer;
  list:TStrings;
begin
   while (line<list.count) and (Copy(Trim(list[line]),1,Length(s))<>s) do inc(line);
   if line<list.count then result:=true
      else if not raiseerr then result:=false
         else raise Exception.Create(s+' nicht gefunden.');
end;


FUNCTION ReadNumber(const s:string; var i:integer):real;
var j:integer;
begin
   j:=i;
   while s[j]<>' ' do dec(j);
   result:=StrToFloat(Copy(s,j+1,i-j));
   while s[j]=' ' do dec(j);
   i:=j;
end;


PROCEDURE ReadLine(var v:TVektor);
var s:string; i:integer; list:TStrings; line:integer;
begin
   s:=Trim(list[line]);
   i:=Length(s);
   v.z:=ReadNumber(s,i);
   v.y:=ReadNumber(s,i);
   v.x:=ReadNumber(s,i);
   inc(line);
end;


PROCEDURE ReadRecord;
const recline='vertex';
var i:integer; data:TDreieck;
begin
   ReadLine(data.n);
   for i:=1 to 3 do begin
      FindLine(recline,true);
      ReadLine(data.p[i]);
   end;
   SetLength(Dreiecke,Length(Dreiecke)+1);
   Dreiecke[High(dreiecke)]:=data;
end;


// var f:TextFile; i,j:integer; // nur zur Kontrolle benutzt

PROCEDURE CopyDreiecke(tofile:boolean);
var list:TStrings;

FUNCTION ToStr(v:real):String;
begin
   result:=FloatToStrF(v,ffExponent,7,3)+' ';
   if result[1]<>'-' then result:=' '+result;
end;

PROCEDURE AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;

var s:string; i:integer; list:TStrings;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;

var i,j:integer;
begin
   list:=TStringList.Create;
   try
      try
         if Length(Dreiecke)=0 then
            raise Exception.Create('Dreiecke ist leer.');
         for i:=0 to High(Dreiecke) do
            with Dreiecke[i] do begin
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt');
           //else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
   end;
end;



procedure TForm1.Button3Click(Sender: TObject);
begin
CopyDreiecke(true);
end;

procedure TForm1.Button2Click(Sender: TObject);
const
   recstart='facet normal';
   recline='vertex';
var list:TStrings; line:integer; data:TDreieck;
begin
   Dreiecke:=nil;
   list:=TStringList.Create;
   try
      try
         //list.text:=Clipboard.AsText;
         List.LoadFromFile(OpenDialog1.FileName);        
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            Dreiecke:=nil;
         end;
      end;
   finally
      list.free;
   end;
end;

end.

Amateurprofi 29. Mai 2012 16:54

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,

natürlich kriegst du eine Fehlermeldung, wenn du in einer Form namens "Form1" eine Prozedur hast, die "TMain.Test" heißt.

Benenne sie um in TForm1.Test oder nenne sie TForm1.Button2Click und alles wird gut.

Zur Access Violation.
Na klar kommt die.

Du hast das ja alles so schön vereinfacht und die Funktionen, die ursprünglich innerhalb von "Test" lagen, ausgelagert.

Dann hast du warscheinlich eine Fehlermeldung "list unbekannt" oder so erhalten und zur Abhilfe in den ausgelagerten Funktionen list noch einmal deklariert.
So funktioniert das halt nicht.

Mein Tipp:
Höre auf mit deinen Verschlimmbesserungen.
Nimm die Prozedur "TMain.Test", benenne sie um in "TForm1.Button2Click", und dann wird das funktionieren.

Boyington 31. Mai 2012 20:19

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Amateurprofi (Beitrag 1168602)
Hallo Lee,

natürlich kriegst du eine Fehlermeldung, wenn du in einer Form namens "Form1" eine Prozedur hast, die "TMain.Test" heißt.

Benenne sie um in TForm1.Test oder nenne sie TForm1.Button2Click und alles wird gut.

Zur Access Violation.
Na klar kommt die.

Du hast das ja alles so schön vereinfacht und die Funktionen, die ursprünglich innerhalb von "Test" lagen, ausgelagert.

Dann hast du warscheinlich eine Fehlermeldung "list unbekannt" oder so erhalten und zur Abhilfe in den ausgelagerten Funktionen list noch einmal deklariert.
So funktioniert das halt nicht.

Mein Tipp:
Höre auf mit deinen Verschlimmbesserungen.
Nimm die Prozedur "TMain.Test", benenne sie um in "TForm1.Button2Click", und dann wird das funktionieren.

Guten Abend Klaus,
heute funktioniert nicht nur dein original Programm bei mir perfekt, sondern auch meine eigne "Verschlimmbessserung" 8-)

Nochmals vielen Dank für deine nette Hilfe!

Gruss
Lee

Boyington 2. Jun 2012 08:15

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Guten Morgen alle,
ich hab wieder ne Frage:
wie kann ich eine dynamische Array (hier z.B Dreiecke: array of TDreieck) in TList umwandeln?
Also alle gerade eingelesenen Koordinaten sollen in TList gespeichert werden, damit kann ich später eine vorhandene Funktion (z.B function Abstand(var MinAbstand: real; Messpos, Blick: TVektor; hList: TList): integer; ) verwenden.

Danke dafür!

Gruss
Lee

Bummi 2. Jun 2012 10:46

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Die Optionen hängen etwas von Deiner Delphiversion ab, ab 2009 kannst Du Records in Listen verwenden, vorher Klassen in TList oder TObjectList...
Delphi-Quellcode:

uses
  ......,Generics.Collections,Contnrs;

type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;

   TDreieckOld = Class
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;

  TDreieckListNew=TList<TDreieck>;
  TDreieckListOld=TObjectList;

Boyington 2. Jun 2012 15:39

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Bummi (Beitrag 1169178)
Die Optionen hängen etwas von Deiner Delphiversion ab, ab 2009 kannst Du Records in Listen verwenden, vorher Klassen in TList oder TObjectList...
Delphi-Quellcode:

uses
  ......,Generics.Collections,Contnrs;

type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;

   TDreieckOld = Class
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;

  TDreieckListNew=TList<TDreieck>;
  TDreieckListOld=TObjectList;

danke für die Antwort, Bummi:)
Aber ich verwende und besitze im Moment nur Delphi7, wie kann ich dynamischen Array mit so alter Delphiversion in TList einfach umwandeln?

Gruss
Lee

Bummi 2. Jun 2012 16:03

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Delphi-Quellcode:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

  TVektor = record
    x, y, z: real;
  end;
  TDreieck = Class
    n: TVektor; // n ist Normalvektor
    p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
  end;

  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FList:TList;
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
 i:Integer;
 d:TDreieck;
begin
    FList:=TList.Create;
    for I := 0 to 10 do
       begin
          d :=TDreieck.Create;
          d.n.x := Random(100);
          d.n.y := i;
          FList.Add(d);
       end;
    Showmessage(FloatToStr(TDreieck(Flist[5]).n.y));
    for I := Flist.Count-1 to 0 do TDreieck(Flist[i]).Free;
    FList.Free;

end;

end.

Boyington 4. Jun 2012 23:08

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Guten Abend Leute und danke für die Codes, Bummi.
Um Parameter "Dreiecke" (array of TDreieck) von dynamischem Array in Typ von "TList" umzuwandeln, habe ich original code von Klaus wie folgendes umgeschrieben:

Delphi-Quellcode:
type
   TVektor = record
     x, y, z: real;
   end;
   TDreieck = record
     n: TVektor; // n ist Normalvektor
     p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
Var
   hDreieck:^TDreieck; //von mir zugefügt!!!
   //Dreiecke:Array of TDreieck;
   Dreiecke: TList; //von mir zugefügt!!!

PROCEDURE TMain.Test;
const
   recstart='facet normal';
   recline='vertex';
var list:TStrings; line:integer; data:TDreieck;

FUNCTION FindLine(const s:string; raiseerr:boolean):boolean;
begin
   while (line<list.count) and (Copy(Trim(list[line]),1,Length(s))<>s) do inc(line);
   if line<list.count then result:=true
      else if not raiseerr then result:=false
         else raise Exception.Create(s+' nicht gefunden.');
end;

FUNCTION ReadNumber(const s:string; var i:integer):real;
var j:integer;
begin
   j:=i;
   while s[j]<>' ' do dec(j);
   result:=StrToFloat(Copy(s,j+1,i-j));
   while s[j]=' ' do dec(j);
   i:=j;
end;

PROCEDURE ReadLine(var v:TVektor);
var s:string; i:integer;
begin
   s:=Trim(list[line]);
   i:=Length(s);
   v.z:=ReadNumber(s,i);
   v.y:=ReadNumber(s,i);
   v.x:=ReadNumber(s,i);
   inc(line);
end;

PROCEDURE ReadRecord;
var i:integer;
begin
   //ReadLine(data.n);
   ReadLine(hDreieck^.n); //von mir zugefügt!!!
   for i:=1 to 3 do begin
      FindLine(recline,true);
      //ReadLine(data.p[i]);
      ReadLine(hDreieck^.p[i]); //von mir zugefügt!!!
   end;
   //SetLength(Dreiecke,Length(Dreiecke)+1);
   //Dreiecke[High(dreiecke)]:=data;
   Dreiecke.Add(hDreieck); //von mir zugefügt!!!
end;

// var f:TextFile; i,j:integer; // nur zur Kontrolle benutzt
begin
   //Dreiecke:=nil; //von mir gelöscht
   list:=TStringList.Create;
   try
      try
         list.text:=Clipboard.AsText;
         // oder List.LoadFromFile('Filename');
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            //Dreiecke:=nil; //von mir gelöscht
         end;
      end;
   finally
      list.free;
   end;
end;
Ich bin nicht sicher, ob das Programm richtig ist, und evtl. s.g "Memory Leaks" vorhanden ist, weil the Codes der Ausgabe in Log.txt ich noch nicht umgeschrieben habe und auch nicht probieren kann.

Ich bin sehr dankbar für weitere Hilfe und nützliche Hinweise:)

Gruss
Lee

Amateurprofi 5. Jun 2012 00:36

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,
hast du schon mal probiert, das laufen zu lassen ?

Ich würde mal vermuten, dass in der Zeile
Delphi-Quellcode:
v.z:=ReadNumber(s,i);
in der Prozedur ReadLine eine Exception (Access Violation) kommt.

Warum?:
hDreieck ist ein Zeiger auf TDreieck und er ist = Nil, zeigt also ins Nichts.
Ins "Nichts" kannst du aber keine Daten schreiben.
Abhilfe:
Delphi-Quellcode:
New(hDreieck)
als erste Zeile in die Prozedur ReadRecord einfügen.

Dann wirst du in der Zeile
Delphi-Quellcode:
Dreiecke.Add(hDreieck);
in der Prozedur ReadRecord eine Exception Exception (Access Violation) kriegen.
Warum?!
Die TList Dreiecke existiert noch nicht.
Abhilfe:
Delphi-Quellcode:
Dreiecke:=TList.Create
als erste Zeile in der Prozedur Test einfügen.

Und wenn du dann irgendwann Dreiecke nicht mehr brauchst musst du erstens für alle Einträge in Dreiecke ein Dispose machen und anschließend ein Dreiecke.Free.

Letzteres solltest auch im except Block in Test machen.

Alternativ kannst du es so machen, wie Bummi es vorschlug.

Boyington 5. Jun 2012 10:40

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Danke dafür, Klaus!
Ich hab gerade das Programm wieder korrigiert, und die Compile scheint in Ordnung zu sein, aber ohne Ausgabe in Log.txt kann ich nun leider nicht überprüfen, ob das Ergebnis richtig ist.

Memory freemachen (am Anfang des Programms unter Type "procedure FormDestroy(Sender: TObject);" zugefügt):
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
var hDreieck:^TDreieck;
    i:integer;
begin
  for i:= 0 to Dreiecke.Count-1 do
  begin
    hDreieck:=Dreiecke[i];
    Dispose(hDreieck);
  end;
  Dreiecke.Free;
end;

Die original Ausgabe-Code von dir hab ich auch umgeschrieben:
Delphi-Quellcode:
procedure AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;
var s:string; i:integer;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;

var i,j:integer;
begin
   list:=TStringList.Create;
   try
      try
         //if Length(Dreiecke)=0 then
         if Dreiecke.count=0 then //von mir umgeschrieben
            raise Exception.Create('Dreiecke ist leer.');
         //for i:=0 to High(Dreiecke) do //wie ist entsprechende Code für TList???
            //with Dreiecke[i] do begin //record,objetc or class type required
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt');
            //else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
   end;
end;

Amateurprofi 5. Jun 2012 17:57

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,

zu
Delphi-Quellcode:
for i:=0 to High(Dreiecke) do //wie ist entsprechende Code für TList???

Ich bin sicher, dass du das auch ohne Hilfe herausbekommst.
Schau doch mal, wie du das in deinem "FormDestroy" machst.


Zu
Delphi-Quellcode:
with Dreiecke[i] do begin //record,objetc or class type required

Die Fehlermeldung sagt doch was fehlt.
Erwartet wird ein Rekord-, Objekt- oder Klassentyp, Dreiecke[i] ist keines davon sondern ein Zeiger auf ein TDreieck. Wenn ich das richtig sehe, ist das dem Compiler aber nicht bekannt, für den ist Dreiecke[i] nur ein Zeiger auf einen Speicherbereich.
Wenn du schreibst with
Delphi-Quellcode:
hDreieck(Dreiecke[i]) do begin
dann weiß er zumindest, dass es sich um einen Zeiger auf ein TDreieck handelt, was aber das Problem nicht heilt, denn es wird ja ein Rekord-, Objekt- oder Klassentyp erwartet.
Mit
Delphi-Quellcode:
with hDreieck(Dreiecke[i])^ do begin
sollte es funktionieren (Beachte das ' ^ ').

Boyington 5. Jun 2012 21:13

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Amateurprofi (Beitrag 1169609)
Hallo Lee,

zu
Delphi-Quellcode:
for i:=0 to High(Dreiecke) do //wie ist entsprechende Code für TList???

Ich bin sicher, dass du das auch ohne Hilfe herausbekommst.
Schau doch mal, wie du das in deinem "FormDestroy" machst.


Zu
Delphi-Quellcode:
with Dreiecke[i] do begin //record,objetc or class type required

Die Fehlermeldung sagt doch was fehlt.
Erwartet wird ein Rekord-, Objekt- oder Klassentyp, Dreiecke[i] ist keines davon sondern ein Zeiger auf ein TDreieck. Wenn ich das richtig sehe, ist das dem Compiler aber nicht bekannt, für den ist Dreiecke[i] nur ein Zeiger auf einen Speicherbereich.
Wenn du schreibst with
Delphi-Quellcode:
hDreieck(Dreiecke[i]) do begin
dann weiß er zumindest, dass es sich um einen Zeiger auf ein TDreieck handelt, was aber das Problem nicht heilt, denn es wird ja ein Rekord-, Objekt- oder Klassentyp erwartet.
Mit
Delphi-Quellcode:
with hDreieck(Dreiecke[i])^ do begin
sollte es funktionieren (Beachte das ' ^ ').

Abend Klaus, danke für deine nette und ausführliche Erklärung!
zu 1). Da hast du recht:-D "for i:=0 to High(Dreiecke) do" soll durch "for i:=0 to Dreiecke.Count-1 do" ersetzt werden, ich hab es in "FormDestroy" schon gemacht, bin doch blöd :(

zu 2). "with hDreieck(Dreiecke[i])^ do begin" schon in Programm geschrieben, aber leider hab ich wieder Fehlermeldung bekommen: Missing Operator or semicolon

Meine Frage: es ist ganz klar, dass Dreiecke[i] ein Zeiger auf ein TDreieck ist. Aber was ist denn hDreieck(Dreiecke[i])? Also hDreieck(ein Zeiger auf ein TDreieck ) ist auch ein Zeiger auf ein TDreieck? Ich bin verwirrt.

Gruss
Lee

Amateurprofi 6. Jun 2012 02:19

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,

tja, dann fehlt da vielleicht irgendwo ein Semikolon.

Ich habe das mal getestet mit nachstehender Prozedur.
Wundere dich nicht, dass die auch Test heißt. (Bei mir gibt es in jedem Projekt eine Prozedur "Test" (zum Testen, wie der Name sagt.)).

Zu
Meine Frage: es ist ganz klar, dass Dreiecke[i] ein Zeiger auf ein TDreieck ist. Aber was ist denn hDreieck(Dreiecke[i])? Also hDreieck(ein Zeiger auf ein TDreieck ) ist auch ein Zeiger auf ein TDreieck? Ich bin verwirrt.

Nein, es ist eben nicht ganz klar, dass Dreiecke[i] ein Zeiger auf ein TDreieck ist.
Das weißt du, nicht aber der Compiler, denn TList ist einfach nur eine Liste mit Pointern.
Dadurch dass du die TList "Dreiecke" nennst, wird Dreiecke[i] für den Compiler nicht zu einem Zeiger auf ein TDreieck.
Erst durch hDreieck(Dreiecke[i]) wird der Pointer zu einem Pointer auf ein TDreieck.
Und mit dem ' ^ ' dahinter 'weiß' der Compiler, dass er auf einen Record TDreieck zugreifen soll.

OT : Wenn du die Variable "Dreiecke" umbenennst in "Kirchturmuhr" wird daraus ja auch kein Zeiger einer Uhr.

Delphi-Quellcode:
type
   TVektor = record
      x, y, z: real;
   end;
   TDreieck = record
      n: TVektor; // n ist Normalvektor
      p: array[1..3] of TVektor; //p hat Koordinaten von 3 Eckpunkten
   end;
   hDreieck=^TDreieck;

var
   Dreiecke:TList;

PROCEDURE TMain.Test;
var i,j:integer; pDreieck:hDreieck; list:TStrings; s:string;
begin
   Dreiecke:=TList.Create;
   for i:=1 to 3 do begin
      New(pDreieck);
      pDreieck.n.x:=i*100+1;
      pDreieck.n.y:=i*100+2;
      pDreieck.n.z:=i*100+3;
      for j:=1 to 3 do begin
         pDreieck.p[j].x:=i*100+j*10+1;
         pDreieck.p[j].y:=i*100+j*10+2;
         pDreieck.p[j].z:=i*100+j*10+3;
      end;
      Dreiecke.Add(pDreieck);
   end;
   list:=TStringList.Create;
   for i:=0 to Dreiecke.Count-1 do
      with hDreieck(Dreiecke[i])^ do begin
         list.Add('n     '+
                  FloatToStr(n.x)+' '+FloatToStr(n.y)+' '+FloatToStr(n.z));
         for j:=1 to 3 do
            list.Add('p['+IntToStr(j)+'] : '+
                     FloatToStr(p[j].x)+' '+FloatToStr(p[j].y)+' '+FloatToStr(p[j].z));
         list.Add('');
      end;
   list.SaveToFile('Log.txt');
   list.Free;
   for i:=0 to Dreiecke.Count-1 do Dispose(Dreiecke[i]);
   Dreiecke.Free;
end;
Das Ergebis in Log.txt :
Code:
n     101 102 103
p[1] : 111 112 113
p[2] : 121 122 123
p[3] : 131 132 133

n     201 202 203
p[1] : 211 212 213
p[2] : 221 222 223
p[3] : 231 232 233

n     301 302 303
p[1] : 311 312 313
p[2] : 321 322 323
p[3] : 331 332 333

DeddyH 6. Jun 2012 07:14

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Der Vorteil von TList ist die Flexibilität, da sie untypisierte Pointer enthält. Der Nachteil ist ihre Flexibilität, da sie nur untypisierte Pointer enthält :mrgreen:. Um ein Mindestmaß an Typsicherheit zu erreichen, könnte man eine eigene Liste von TList ableiten, die dann nur typsierte Pointer eines bestimmten Typs verarbeitet, in aktuellen Delphi-Versionen auf eine generische Liste umsteigen, oder aus den Records Klassen machen und in einer TObjecList verwalten, dann hat man zumindest die Möglichkeit, die Einträge mittels is und as auf ihren Typ zu untersuchen (oder man leitet auch hier wieder eine spezialisierte Liste ab).

Boyington 6. Jun 2012 10:32

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Guten Tag Zusammen,
die original Ausgabe-Code (in Log.txt) von Klaus funktioniert jetzt schon (besonders "with hDreieck(Dreiecke[i])^ do begin""), hab ich gerade schon probiert, jedoch muss man hDreieck = ^TDreieck; am Anfang des Programms unter Type erklären, aber nicht innerhalb von Ausgabe-Code, also nicht innerhalb von procedure CopyDreiecke(tofile:boolean)
Delphi-Quellcode:
procedure CopyDreiecke(tofile:boolean);
var list:TStrings;

function ToStr(v:real):String;
begin
   result:=FloatToStrF(v,ffExponent,7,3)+' ';
   if result[1]<>'-' then result:=' '+result;
end;

procedure AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;
var s:string; i:integer;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;

var i,j:integer;
begin
   list:=TStringList.Create;
   try
      try
         //if Length(Dreiecke)=0 then
         if Dreiecke.Count=0 then
            raise Exception.Create('Dreiecke ist leer.');
         //for i:=0 to High(Dreiecke) do
           for i:=0 to Dreiecke.Count-1 do
            //with Dreiecke[i] do begin
             with hDreieck(Dreiecke[i])^ do begin
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt');
            //else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
   end;
end;
Nun neue Probleme: die in Log.txt ausgegebenen/gespeicherten Koordinaten stimmen mit original Koordinaten in *.stl nicht überein, wo können die Fehler liegen?
Delphi-Quellcode:
.
.
.
PROCEDURE ReadRecord;
var i:integer;
begin
   //ReadLine(data.n);
   ReadLine(hDreieck^.n); //von mir umgeschrieben!!!
   for i:=1 to 3 do begin
      FindLine(recline,true);
      //ReadLine(data.p[i]);
      ReadLine(hDreieck^.p[i]); //von mir umgeschrieben!!!
   end;
   //SetLength(Dreiecke,Length(Dreiecke)+1);
   //Dreiecke[High(dreiecke)]:=data;
   Dreiecke.Add(hDreieck); //von mir umgeschrieben!!! Vielleicht HIER fehlt noch etwas
end;

begin
   //Dreiecke:=nil; //von mir gelöscht, sonst kriege ich "Access Violation..."
   list:=TStringList.Create;
   try
      try
         list.text:=Clipboard.AsText;
         // oder List.LoadFromFile('Filename');
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            Dreiecke:=nil;
         end;
      end;
   finally
      list.free;
   end;
end;
Gruss
Lee

Amateurprofi 6. Jun 2012 10:46

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Was bedeutet "stimmen nicht überein" ?
Zeige doch mal die Original-Daten und was dann in Log.txt ankam.
(Nicht alle 10000. Nur 2 bis 3 bitte)

DeddyH 6. Jun 2012 10:50

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Welche Werte sind denn im Debugger zu sehen? Da ich weder ReadLine noch FindLine kenne, kann ich Dir auch nicht sagen, ob die korrekt arbeiten.

p80286 6. Jun 2012 10:52

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Boyington (Beitrag 1169666)
Nun neue Probleme: die in Log.txt ausgegebenen/gespeicherten Koordinaten stimmen mit original Koordinaten in *.stl nicht überein, wo können die Fehler liegen?

Aller Wahrscheinlichkeit nach in Deinem Programm!

Wie unterscheiden sich die Werte denn?
werden sie verschoben, wird einer ausgelassen oder wo klemmt es?

Gruß
K-H

Boyington 6. Jun 2012 10:53

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Zitat:

Zitat von Amateurprofi (Beitrag 1169667)
Was bedeutet "stimmen nicht überein" ?
Zeige doch mal die Original-Daten und was dann in Log.txt ankam.
(Nicht alle 10000. Nur 2 bis 3 bitte)

original Koordinaten von *.stl Datei:
Code:
solid ascii
  facet normal 2.445222e-016 0.000000e+000 1.000000e+000
    outer loop
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal 2.445222e-016 -5.090141e-032 1.000000e+000
    outer loop
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal -3.209883e-031 -1.000000e+000 2.312965e-015
    outer loop
      vertex  -2.007874e+000 -1.968504e+000 -5.905512e-002
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal 1.476360e-016 -1.000000e+000 -3.414769e-031
    outer loop
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 -5.905512e-002
    endloop
  endfacet
  facet normal 0.000000e+000 1.000000e+000 0.000000e+000
    outer loop
      vertex  -2.007874e+000 1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal 0.000000e+000 1.000000e+000 0.000000e+000
    outer loop
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
      vertex  -3.937008e-002 1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 -5.905512e-002
    endloop
  endfacet
  facet normal -1.000000e+000 0.000000e+000 2.312965e-015
    outer loop
      vertex  -2.007874e+000 -1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal -1.000000e+000 0.000000e+000 2.312965e-015
    outer loop
      vertex  -2.007874e+000 1.968504e+000 5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 -5.905512e-002
    endloop
  endfacet
  facet normal 1.387779e-016 0.000000e+000 -1.000000e+000
    outer loop
      vertex  -2.007874e+000 1.968504e+000 -5.905512e-002
      vertex  -3.937008e-002 1.968504e+000 -5.905512e-002
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
    endloop
  endfacet
  facet normal 1.387779e-016 0.000000e+000 -1.000000e+000
    outer loop
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 -1.968504e+000 -5.905512e-002
      vertex  -2.007874e+000 1.968504e+000 -5.905512e-002
    endloop
  endfacet
  facet normal 7.071068e-001 0.000000e+000 7.071068e-001
    outer loop
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
      vertex  -3.937008e-002 1.968504e+000 -5.905512e-002
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
    endloop
  endfacet
  facet normal 7.071068e-001 -1.471962e-016 7.071068e-001
    outer loop
      vertex  -1.574803e-001 1.968504e+000 5.905512e-002
      vertex  -1.574803e-001 -1.968504e+000 5.905512e-002
      vertex  -3.937008e-002 -1.968504e+000 -5.905512e-002
    endloop
  endfacet

Koordinaten von Log.txt
Code:
 1.476983E-311  0.000000E+000  0.000000E+000 
 0.000000E+000  0.000000E+000  0.000000E+000 
 0.000000E+000  0.000000E+000  0.000000E+000 
-1.473896E+000 -6.222585E-001 -1.159190E+000 

 6.281842E-312  0.000000E+000  0.000000E+000 
 0.000000E+000  0.000000E+000  0.000000E+000 
 0.000000E+000  0.000000E+000  0.000000E+000 
 3.305282E-001  2.457197E+000  1.327775E+000 

 6.773484E-311  5.330479E+228  1.591497E-312 
 1.251978E-312  5.738129E+180  2.473799E-091 
 3.699094E-057  8.242291E-072  3.272333E+179 
-1.473896E+000 -6.222585E-001 -1.159190E+000 

 5.771902E-311  1.397371E-076  1.396426E-076 
 6.530859E-038  1.398037E-076  1.200317E-071 
 1.723460E-311  3.705492E-322  6.013469E-154 
-2.337179E+000  1.018424E+000 -1.187628E+000 

 4.999496E-311  1.748032E+000 -2.062994E+000 
-1.016916E-012 -1.748032E+000 -2.062994E+000 
 1.016916E-012  1.748032E+000 -2.062993E+000 
 1.255161E+000  8.556853E-001  1.263198E+000 

 4.362897E-311  2.527831E-052  1.207374E-153 
 1.200317E-071  3.098513E-311  3.705492E-322 
 6.013469E-154  9.067593E+271  1.397371E-076 
 3.918780E-001  2.496368E+000  1.234760E+000 

 3.369803E-311  3.705492E-322  6.013469E-154 
 9.067593E+271  1.397371E-076  1.396426E-076 
 2.527831E-052  1.207374E-153  1.200317E-071 
 3.305282E-001  2.457197E+000  1.327775E+000 

 2.521004E-311  0.000000E+000  5.263544E-315 
 7.812500E-003  0.000000E+000  5.263544E-315 
 1.587352E-314 -7.812501E-003  4.388941E-120 
-2.337179E+000  1.018424E+000 -1.187628E+000 

 1.672206E-311  1.397371E-076  1.396426E-076 
 6.530859E-038  1.398037E-076  1.200317E-071 
 5.823156E-311  3.705492E-322  6.013469E-154 
-1.353527E+000 -6.853117E-001 -1.256328E+000 

 8.234078E-312  1.269314E-076  1.591497E-312 
 1.251978E-312  5.738129E+180  2.473799E-091 
 3.699094E-057  8.242291E-072  3.272333E+179 
 3.918780E-001  2.496368E+000  1.234760E+000 

 6.994172E-311  7.259042E-043  1.398037E-076 
 1.832558E-076  8.450653E-053  2.948785E+179 
 5.981315E-154  8.429613E+252  3.654820E-086 
 1.255161E+000  8.556853E-001  1.263198E+000 

 6.145373E-311  1.085864E-042  4.581108E-072 
 3.272333E+179  2.908879E-033  1.269314E-076 
 6.013470E-154  6.017568E-244  1.574079E+161 
-1.353527E+000 -6.853117E-001 -1.256328E+000

p80286 6. Jun 2012 11:25

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Sieht nicht so schön aus,
wie wäre es direkt in Readline ein Protokoll der gelesenen Daten anzufertigen?

ansonsten der Debugger ist wirklich ein tolles Fehersuchundbehebewerkzeug.

Gruß
K-H

Amateurprofi 6. Jun 2012 11:56

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,

Ich hab die Daten eingelesen (mit der Original-Routine aus #2) und dann in die Datei Log.txt geschrieben (mit der Original-Routine aus #5).
Die Daten stimmen 100 %ig überein.

Das läßt mich vermuten, dass durch eine deiner Vereinfachungen etwas durcheinander gebracht wurde.

Poste doch noch einmal die Typ-Deklarationen und die Routinen, mit denen du eingelesen und ausgegeben hast.

Ohne die, kann das hier niemand prüfen.

Boyington 6. Jun 2012 12:25

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Das ist mein Programm mit Code von Klaus

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GLScene, GLMisc, GLVectorFileObjects, GLWin32Viewer, GLFileSTL,
  Menus, ComCtrls, StdCtrls, ExtCtrls, GLTexture, GLObjects, GLHUDObjects;

type
   //TVektor = array[1..3] of real;
    TVektor = record
    x, y, z: real;
    end;

    TDreieck = record
    n: TVektor;
    p: array[1..3] of TVektor;
    end;

    hDreieck = ^TDreieck;

    TMatrix_3x3 = array[1..3, 1..3] of real;
    TMatrix_4x4 = array[1..4, 1..4] of real;
.
.
.
Var
  Form1: TForm1;
  Rotationsmatrix: TMatrix_3x3;
  //Dreiecke:array of TDreieck;
  Dreiecke: TList;
.
.
.
procedure TForm1.Button2Click(Sender: TObject);
const
   recstart='facet normal';
   recline='vertex';
var list:TStrings; line:integer; //data:TDreieck;

FUNCTION FindLine(const s:string; raiseerr:boolean):boolean;
begin
   while (line<list.count) and (Copy(Trim(list[line]),1,Length(s))<>s) do inc(line);
   if line<list.count then result:=true
      else if not raiseerr then result:=false
         else raise Exception.Create(s+' nicht gefunden.');
end;

FUNCTION ReadNumber(const s:string; var i:integer):real;
var j:integer;
begin
   j:=i;
   while s[j]<>' ' do dec(j);
   result:=StrToFloat(Copy(s,j+1,i-j));
   while s[j]=' ' do dec(j);
   i:=j;
end;

PROCEDURE ReadLine(var v:TVektor);
var s:string; i:integer;
begin
   s:=Trim(list[line]);
   i:=Length(s);
   v.z:=ReadNumber(s,i);
   v.y:=ReadNumber(s,i);
   v.x:=ReadNumber(s,i);
   inc(line);
end;

PROCEDURE ReadRecord;
var i:integer; hDreieck:^TDreieck;
begin
   //ReadLine(data.n);
   New(hDreieck) //neu zugefuegt;
   ReadLine(hDreieck^.n); //Fehlermeldung:missing Operator or Semicolon;
   for i:=1 to 3 do begin
      FindLine(recline,true);
      //ReadLine(data.p[i]);
      ReadLine(hDreieck^.p[i]);
   end;
   //SetLength(Dreiecke,Length(Dreiecke)+1);
   //Dreiecke[High(dreiecke)]:=data;
   Dreiecke.Add(hDreieck);
   
end;


// var f:TextFile; i,j:integer; // nur zur Kontrolle benutzt
begin
   Dreiecke:=nil;
   Dreiecke:=TList.Create;
   list:=TStringList.Create;
   try
      try
         //list.text:=Clipboard.AsText;
         List.LoadFromFile(OpenDialog1.FileName);
         line:=0;
         while FindLine(recstart,false) do ReadRecord;
      except
         On E:Exception do begin
            ShowMessage(E.Message);
            Dreiecke:=nil;
         end;
      end;
   finally
      list.free;
   end;
end;



//die Liste zur Kontrolle als Log.txt speichern;
procedure CopyDreiecke(tofile:boolean);
var list:TStrings;

function ToStr(v:real):String;
begin
   result:=FloatToStrF(v,ffExponent,7,3)+' ';
   if result[1]<>'-' then result:=' '+result;
end;

procedure AddVector(const v:TVektor);
type TxVector=Array[0..2] of real;
var s:string; i:integer;
begin
   for i:=0 to High(TxVector) do s:=s+ToStr(TxVector(v)[i]);
   list.Add(s);
end;

var i,j:integer; //hDreieck:^TDreieck;
begin
   list:=TStringList.Create;
   try
      try
         //if Length(Dreiecke)=0 then
         if Dreiecke.Count=0 then
            raise Exception.Create('Dreiecke ist leer.');
         //for i:=0 to High(Dreiecke) do
           for i:=0 to Dreiecke.Count-1 do
            //with Dreiecke[i] do begin
             with hDreieck(Dreiecke[i])^ do begin
               AddVector(n);
               for j:=Low(p) to High(p) do AddVector(p[j]);
               list.Add('');
            end;
         if tofile then list.SaveToFile(ExtractFilePath(ParamStr(0))+'Log.txt');
            //else Clipboard.AsText:=List.Text;
         ShowMessage('fertig.');
      except
         On E:Exception do ShowMessage(E.Message);
      end;
   finally
      list.free;
      for i:=0 to Dreiecke.Count-1 do Dispose(Dreiecke[i]); //neu zugefuegt Code;
      Dreiecke.Free; //neu zugefuegt Code;
   end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
CopyDreiecke(true);
end;

end.

Amateurprofi 6. Jun 2012 13:41

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Hallo Lee,
ich hab das mal 1:1 kopiert.

Bei mir wurde das nicht kompiliert, weil in der Prozedur ReadRecord hinter
Delphi-Quellcode:
New(hDreieck)
das Semikolon fehlt.

Nach Hinzufügen des Semikolons lief das einwandfrei.

Ich habe die Daten aus #28 ins Clipboard kopiert und in Button2Click in list gestellt.
Nach Ausführen von Button2Click habe ich die Daten mit CopyDreiecke in Log.txt geschrieben.
Ergebnis : Alle Werte sind identisch mit den Originalwerten.

Dann habe ich die Daten aus #28 in eine Datei gestellt und in Button2Click aus dieser Datei in list geladen.
Nach Ausführen von Button2Click habe ich die Daten mit CopyDreiecke in Log.txt geschrieben.
Ergebnis : Alle Werte sind identisch mit den Originalwerten.

Da das, was du gepostet hast, so wie es war (fehlendes Semikolon), nicht kompiliert wurde, kann ich nicht so recht glauben, dass das die Version war, die bei dir fehlerhafte Ergebnisse brachte, denn die hätte ja gar nicht laufen können.
Aber vielleicht hast du ja so einen Zauberkompiler, der fehlende Semikola toleriert – kann ich aber auch nicht glauben.

Was mir noch auffiel:

Erstens:
Oberhalb der Prozeduren deklarierst du einen Typ
Delphi-Quellcode:
hDreieck=^TDreieck
.
In der Prozedur ReadRecord deklarierst du eine Variable
Delphi-Quellcode:
hDreieck=^TDreieck
.
Das ist zwar unkritisch aber unschön.
Sinnvoller wäre, die Variable als z.B.
Delphi-Quellcode:
Dreieck:hDreieck
zu deklarieren.

Zweitens:
Im Except Block in Button2Click schreibst du Dreiecke:=nil;
Wenn es tatsächlich zu einer Exception kommt erzeugst du damit schöne Memory Leaks.
Richtig wäre.
Delphi-Quellcode:
for i:=0 to Dreiecke.Count-1 do Dispose(Dreiecke[i]);
Dreiecke.Free;
Drittens:
Du lädtst eine Datei deren Namen du aus OpenDialog.Filename entnimmst.
Kann es sein, dass da ein anderer Dateiname steht, als du vermutest ?

Boyington 6. Jun 2012 16:07

AW: wie kann ich bestimmte Infos aus Textdokument einlesen?
 
Nachdem ich den "schönen kleinen" Semikolon zugefügt habe, funktioniert diesmal die original Code (Eingabe+Ausgabe) von Klaus bei mir ganz gut, und Gott sei dank, mein eigenes Programm (*.STL Datei Einlesen basiert auf Code von Klaus) läuft auch so gut (vorher hab ich New(hDreieck) irgendwo zweimal geschrieben, deshalb falsche Koordinaten bekommen).

Danke für alle Antworten, besonders für Antworten von Klaus und Bummi:-D

wünsche euch einen schönen Tag (vielleicht schönen Abend) noch!

Gruss
lee


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:39 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz