"Verschachtelte" dynamische Arrays of records

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

"Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Hallo Forum,

eine Frage im Zusammenhang mit dem Datenhandling von großen ASCII-Dateien: kann man dynamische Arrays verschachteln? Zur Erläuterung folgender Code:

Code: Alles auswählen

 
{ Element Connectivity }
{ ==================== }
 
  TElementNodeNumbers = integer;
 
  TElemConnectionEntry = Record
    ielid : integer;          { element number }
    ityp  : integer;          { element type of element }
    nnod  : integer;          { number of nodes for element ijk }
    iel : Array of integer;   { array node numbers of element }        { <---- dynamic array of integer }
  End;
 
  TElementConnectivity = Record
    numel    : integer;       { number of elements }
    nnodmx   : integer;       { max. number of nodes per element }
    elemconn : Array of TElemConnectionEntry; { array of element connection entries }    { <---- dynamic array of TElemConnectionEntry }
  End;
 
{ im Programm dann }
...
  SetLength(iel,nnodmx);      { max. number of nodes per element }
...
  SetLength(elemconn,numel);  { max. number of elements }
...
  { Speicher für ElementConnectivity besorgen }
  { numel und nnodmx im record setzen }
  for i:=1 to numel do
  begin
    { weiteren Speicher-Block ElementConnectionEntry besorgen }
    { ... und mit den Daten für 1 Element füllen: }
    { ielid, ityp, nnod und Array iel füllen }
    { die ganze Strucktur in elemconn }
  end;
 

D.h. Die übergeordnete Struktur [i]TElementConnectivity
enthält ein dyn. Array der Struktur TElemConnectionEntry, welches selbst ein dyn. Array enthält. Beide Arrays können erst zu Laufzeit des Programms dimensioniert werden, da erst dann die Anzahl der Elemente, Konten, ElementConnectivity etc bekannt ist - nebenbei: davon wird es dann noch mehr geben (FEM eben :roll: ).

Ich bin nicht sicher, ob das so überhaupt möglich ist. Und wenn ja, ob es sinnvoll ist. Oder ob man lieber mit TList arbeiten sollte; die Listen kann man ja dynamisch erweitern. Da es sehr viele Einträge sind, ist Geschwindigkeit und Speicherverbrauch auch immer eine Aspekt.

Danke für Euren Input,
Photor

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von mse »

Es ist möglich und sinnvoll.

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von Mathias »

kann man dynamische Arrays verschachteln?

Ja, dies sollte gehen, man muss einfach mit SetLength gewisse Sachen beachten.

Da iel mehrmals in elemconn vor kommt, muss es auch mehrmals mit SetLength definiert werden.

Beispiel:

Code: Alles auswählen

var
  test: TElementConnectivity;
begin
  SetLength(test.elemconn, 4);
  SetLength(test.elemconn[3].iel, 123);
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von wp_xyz »

photor hat geschrieben:... ob es sinnvoll ist. Oder ob man lieber mit TList arbeiten sollte; die Listen kann man ja dynamisch erweitern. Da es sehr viele Einträge sind, ist Geschwindigkeit und Speicherverbrauch auch immer eine Aspekt.

Ich möchte noch anmerken, dass es wichtig ist, ob die Arraygröße konstant ist, oder sich z.B. während des Einlesens erst sukzessive ergibt. Im zweiteren Fall ist es wichtig, das Array nicht immer um 1 wachsen zu lassen, weil bei jeder Größenänderung das alte Array an einen neuen Platz kopiert wird, was ganz schön lange dauert, wenn du schon ein paar GByte eingeladen hast. Mache stattdessen das Array in größeren Häppchen (1000 Elemente meinetwegen) größer und lasse einen Zähler mitlaufen, der protokolliert wieviele Einträge tatsächlich benutzt worden sind. Dann kannst du am Ende, wenn alle Elemente feststehen die Array-Länge endgültig einstellen.

Oder nimm gleich TList, oder eine der Varianten. Hier müssen nur die Pointer umkopiert werden, und außerdem kann man da auch per "Capacity" die "Häppchen"-Größe einstellen.

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Mathias hat geschrieben:
kann man dynamische Arrays verschachteln?

Ja, dies sollte gehen, man muss einfach mit SetLength gewisse Sachen beachten.

Da iel mehrmals in elemconn vor kommt, muss es auch mehrmals mit SetLength definiert werden.

Beispiel:

Code: Alles auswählen

var
  test: TElementConnectivity;
begin
  SetLength(test.elemconn, 4);
  SetLength(test.elemconn[3].iel, 123);
end;


Hallo mathias,

iel kommt in elemconn ja genau numel-mal vor. Allerdings wird selbst im Original-Datensatz immer die Länge nnodmx (maximale Anzahl der Knoten) verwendet(*); der rest wird mit "0" aufgefüllt. Das macht es einfacher, da wenigsten so alle Einträge im elemconn-Array alle gleich groß sind. So müsste sich dieses eigentlich schon zu Beginn dimensionieren lassen. Das wäre zunächst auch mein 1. Angang - später könnte man dann nochmal optimieren.

Ciao,
Photor

(*) plus der Bei-Info, die nur je einmal in der Struktur vorkommt

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von Mathias »

Im zweiteren Fall ist es wichtig, das Array nicht immer um 1 wachsen zu lassen, weil bei jeder Größenänderung das alte Array an einen neuen Platz kopiert wird, was ganz schön lange dauert, wenn du schon ein paar GByte eingeladen hast.

Die Umkopiererrei ist nur den Fall, wen bei der aktuellen Array hinten kein Platz mehr vorhanden ist. Aber du hast schon recht, bei der Grösse ist jedes Umkopieren zu viel.
Was auch noch eine Alternative zu TList ist, das währe eine verkette Liste mit Pointern.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Hallo wp_xyz,

dein Post hat sich mit meiner Antwort überschnitten.
wp_xyz hat geschrieben:
photor hat geschrieben:... ob es sinnvoll ist. Oder ob man lieber mit TList arbeiten sollte; die Listen kann man ja dynamisch erweitern. Da es sehr viele Einträge sind, ist Geschwindigkeit und Speicherverbrauch auch immer eine Aspekt.

Ich möchte noch anmerken, dass es wichtig ist, ob die Arraygröße konstant ist, oder sich z.B. während des Einlesens erst sukzessive ergibt. Im zweiteren Fall ist es wichtig, das Array nicht immer um 1 wachsen zu lassen, weil bei jeder Größenänderung das alte Array an einen neuen Platz kopiert wird, was ganz schön lange dauert, wenn du schon ein paar GByte eingeladen hast. Mache stattdessen das Array in größeren Häppchen (1000 Elemente meinetwegen) größer und lasse einen Zähler mitlaufen, der protokolliert wieviele Einträge tatsächlich benutzt worden sind. Dann kannst du am Ende, wenn alle Elemente feststehen die Array-Länge endgültig einstellen.

Die Anzahl der Einträge in den Arrays steht fest (wächst also nicht mehr) und die Info ist im einzulesenden File auch "rechtzeitig" vermerkt; die Größe der Arrays sollte also nicht wachsen müssen. (und ich denke, es ist das sinnvollste, direkt die gebrauchte Größe zu allociere, richtig?).

wp_xyz hat geschrieben:Oder nimm gleich TList, oder eine der Varianten. Hier müssen nur die Pointer umkopiert werden, und außerdem kann man da auch per "Capacity" die "Häppchen"-Größe einstellen.

Genau darüber denke ich gerade nach. TList hätte auch den Vorteil, dass ich nicht den Speicher am Stück brauche. Der Implementationsaufwand ist aber - glaube ich - höher.

Ciao,
Photor

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von Mathias »

Die Anzahl der Einträge in den Arrays steht fest (wächst also nicht mehr)

Dann könntest doch auch eine statische Array nehmen.
Oder wird die Grösse erst bei Begin des Programmes bekannt ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Mathias hat geschrieben:
Die Anzahl der Einträge in den Arrays steht fest (wächst also nicht mehr)

Dann könntest doch auch eine statische Array nehmen.
Oder wird die Grösse erst bei Begin des Programmes bekannt ?

Genau so. Eigentlich ändert sich das sogar von File zu File. Allerdings sollten die Files, die ich für einen Rechnungslauf brauche, gleichartig sein (gleiches Ausgangsmodel und somit gleicher Aufbau der Ergebnisfiles).

Ciao,
Photor

Mathias
Beiträge: 6167
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von Mathias »

Genau so. Eigentlich ändert sich das sogar von File zu File.

Dann würde ich es mit einer dynamischen Array lösen. Listen sind nur interessant wen die Grösse zur Laufzeit immer ändert. Das ist zB. bei einer Datenbank der Fall.
Aber wen nur bei der Initialisierung die Grösse einmal festgelegt wird, dann ist eine Array immer der bessere Weg.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Mathias hat geschrieben:Aber wen nur bei der Initialisierung die Grösse einmal festgelegt wird, dann ist eine Array immer der bessere Weg.

Das denke ich aun und werde es so versuchen. Danke für den Input. Melde mich, wenn's tut - oder wenn noch Fragen auftauchen.

Ciao
Photor

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Hallo Forum,

bei dem Versuch, das ganze in Code zu gießen, treten dann doch noch Fragen auf - entweder rein technische oder doch noch Verständnisfragen. Die Struktur sieht im Moment wie folgt aus:

Code: Alles auswählen

 
  PIPEntry = ^TIPEntry;
  TIPEntry = Array of TMyReal;                                    { variable number of entries: npost }
 
  PElementIPValue = ^TElementIPValue;
  TElementIPValue = Array of TIPEntry;  { variable number of entries: nstres = #IPperElement }
 
  T52300ElementIntegrationPointValues = Record
    npost : integer;    { number of postcodes (from BLOCK 50200) }
    numel : integer;    { number of elements (from BLOCK 50200) }
    jantyp : integer;   { analysis type (from BLOCK 51700) }
    nstres : integer;   { number of integration points per element (from BLOCK 50200) }
    elementvalues : Array of TElementIPValue;   { Array with numel entries = #elements }
  End;
 

Also es gibt
  • ein Record, das neben den Parametern, die die Geometrie der Arrays (= die Anzahl der Einträge)
  • ein dynamisches Array elementvalues vom Typ TElementIPValue enthält - numel Einträge;
  • der Typ TElementIPValue selbst ist ein (dynamisches) Array vom Typ TIPEntry; die Größe (für alle Einträge): nstres
  • wobei TIPEntry-Array vom Typ double (TMyReal) ist, das die Dimension npost bekommen soll.
Wie muss ich die jetzt dimensionieren? Folgendes scheint mir noch logisch:

Code: Alles auswählen

 
var
  blub : T52300ElementIntegrationPointValues
begin
  ...
  SetLength(blub.elementvalues,numel);
  ...
end;
 

Aber wann und wie werden die Arrays in TIPEntry und TElementIPValue dimensioniert? Für mein Verständnis müsste dies vor dem obigen Aufruf passieren. Bloß wie schreibe ich das auf? Vielleicht habe ich auch nur ein Brett vor'm Kopf.

Ciao,
Photor

PS1: typische Werte: npost = 6; nstres = 8; numel = 772341;
PS2: die Daten liegen etwa so im ASCII-File vor:

Code: Alles auswählen

 
=beg=52300 (Element Integration Point Values)                       
-0.221872E+01 0.247622E+01-0.719599E+00 0.249108E+01-0.184944E+01 0.119872E+01
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
-0.137885E+01 0.550887E+00-0.297603E+00 0.414989E+00-0.525047E+00 0.478315E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
-0.814422E+00 0.130095E+01-0.532020E+00 0.247945E+00 0.156972E+00-0.628050E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
-0.209306E+01 0.295292E+01-0.695951E+00 0.282354E+01-0.189412E+01 0.147181E+01
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
...
 

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von wp_xyz »

Zuerst ein paar Bemerkungen, die mir beim Durchsehen deines Code-Fragments aufgefallen sind:
  • Ich nehme an, dass die Pointer auf die Arrayelemente (z.B. PElementIPValue) Relikte aus der Version ohne dynamische Arrays sind. Bei statisch dimensionierten Arrays (TDataStat = array[0..10] of Integer, und var dataStat: TDataStat) sprichst du mit @dataStat das erste Element an. Nicht so bei dynamischen Arrays. Da diese selbst schon Pointer sind (wobei aber das Pointer-Häkchen durch Compiler-Tricks unterdrückt ist), wäre bei TDataDyn: array of integer der Ausdruck @datDyn die Adresse des Pointers, der auf das 1.Element zeigt; das 1.Element würdest du mit @dataDyn[0] ansprechen. Aber die Pointer brauchst du bei dynamischen Arrays in der Regel gar nicht.
  • Die Elemente für die Arraylängen brauchst du auch nicht. In der Regel greift man über Length(...) auf die Länge zu, oder über High(...) auf das letzte Element.
  • Beachte: Der unterste Index ist immer 0, nicht 1. Falls deine Rechnung bei 1 beginnt, hast du ein Problem, das nur mit äußerster Konzentration zu lösen ist!
Die Details deiner Frage sind mir zu kompliziert, nimm stattdessen das folgende Modell einer Anordnung von 3D-Körpern, also ein Modell bestehend aus 3D-Objekten, die wiederum aus Eckpunkten und Kanten (die Indices der Eckpunkte am Anfang und Ende der Verbindungslinie) bestehen:

Code: Alles auswählen

type
  TEcke = record
    X,Y,Z; Extended;
  end;           
  TKante = record
    i1, i2: Integer;
  end;
  T3DObjekt = record
    Ecken: array of TEcke;
    Kanten: array of TKante;
  end;
  TModell = record
    Obj: array of T3DObjekt;
  end;

Ein Modell bestehend aus einem Würfel und einem Tetraeder wird dann so dimensioniert:

Code: Alles auswählen

var Modell: TModell;
...
  // Das Modell enthält zwei 3D-Objekte
  SetLength(Modell, 2)
  // Dimensionierung des Würfels: Ein Würfen hat 8 Ecken und 12 Kanten
  SetLength(Modell.Obj[0].Ecken, 8);
  SetLength(Modell.Obj[0].Kanten, 12);
  // Dimensionierung des Tetraeders: Ein Tetraeder hat 4 Ecken und 6 Kanten
  SetLength(Modell.Obj[1].Ecken, 4);
  SetLength(Modell.Obj[1].Kanten, 6);

Auf die x-Koodinate 1.Ecke des Würfels greifst du so zu:

Code: Alles auswählen

x := Modell.Obj[0].Ecke[0].X;

und so auf die x-Koordinate des Anfangspunktes der letzten Kante des Tetraeders

Code: Alles auswählen

x := Modell.Obj[1].Ecke[Modell.Obj[1].Kanten[High(Modell.Obj[1].Kanten)].i1].x; 
 
// oder lesbarer
var
  Tetraeder: T3DObjekt;
  TetraedeKante: TKante;
  TetraederEckpunkt: TEcke;
...
  Tetraeder := Modell.Obj[1];
  TetraederKante := Tetrader.Kanten[High(Tetraeder.Kanten)];
  TetraederEckpunkt := Tetraeder.Ecken[TetraederKante,i1].X;
 

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: "Verschachtelte" dynamische Arrays of records

Beitrag von photor »

Hallo wp_xyz,

danke für Deine ausführliche Antwort,

wp_xyz hat geschrieben:Zuerst ein paar Bemerkungen, die mir beim Durchsehen deines Code-Fragments aufgefallen sind:
  • Ich nehme an, dass die Pointer auf die Arrayelemente (z.B. PElementIPValue) Relikte aus der Version ohne dynamische Arrays sind. Bei statisch dimensionierten Arrays (TDataStat = array[0..10] of Integer, und var dataStat: TDataStat) sprichst du mit @dataStat das erste Element an. Nicht so bei dynamischen Arrays. Da diese selbst schon Pointer sind (wobei aber das Pointer-Häkchen durch Compiler-Tricks unterdrückt ist), wäre bei TDataDyn: array of integer der Ausdruck @datDyn die Adresse des Pointers, der auf das 1.Element zeigt; das 1.Element würdest du mit @dataDyn[0] ansprechen. Aber die Pointer brauchst du bei dynamischen Arrays in der Regel gar nicht.

Ja. Diese Pointer sind "Überbleibsel" in sofern, als dass das zum vorgefundenen Programmierstil passte. Wenn es geht, will ich schon "moderner" (= in meinen Augen übersichtlicher) programmieren.

wp_xyz hat geschrieben:
  • Die Elemente für die Arraylängen brauchst du auch nicht. In der Regel greift man über Length(...) auf die Länge zu, oder über High(...) auf das letzte Element.

  • Die Variablen, die die Arraylängen liefern sind Bestandteil des Postcode-Designs des Originalprogramms (garantiert ein FORTRAN-Programm, also wahrscheinlich ein COMMON-Block), dass die ASCII-Dateien liefert. Die wollte ich in der Delphi-Repräsentation der Struktur aus Verständnisgründen und Kompatibilität zur Dokumentation behalten. Sicher ist diese Information redundant, was aber den Kohl auch nicht fetter macht.

    wp_xyz hat geschrieben:
  • Beachte: Der unterste Index ist immer 0, nicht 1. Falls deine Rechnung bei 1 beginnt, hast du ein Problem, das nur mit äußerster Konzentration zu lösen ist!

  • Das ist mir bewußt: die Zählvariable läuft daher üblicherweise von 0 bis numel-1 oder so. Bzw. ich nutze viellecht auch High() und Low(), was aber für mich noch gewöhnungsbedürftig ist.

    wp_xyz hat geschrieben:Die Details deiner Frage sind mir zu kompliziert, nimm stattdessen das folgende Modell einer Anordnung von 3D-Körpern, also ein Modell bestehend aus 3D-Objekten, die wiederum aus Eckpunkten und Kanten (die Indices der Eckpunkte am Anfang und Ende der Verbindungslinie) bestehen:

    Code: Alles auswählen

     ... 

    Ich glaube, ich habe verstanden, wie es aufgebaut werden muss. Ich werde mir das morgen(? hoffentlich) genauer ansehen probieren (können).

    Danke,
    Photor

    Antworten