Delphi array initialization
Asked Answered
W

3

19

I currently have this, and it sucks:

type TpointArray = array [0..3] of Tpoint;

class function rotationTable.offsets(pType, rotState, dir: integer): TpointArray;
begin

  Result[0] := point(1, 1);
  Result[1] := point(1, 2);
  Result[2] := point(1, 1);
  Result[3] := point(1, 1);
end;

but instead, i want to do something like this:

class function rotationTable.offsets(pType, rotState, dir: integer): TpointArray;
begin
   Result := [Point(1,1), Point(1,2), Point(1,1), Point(1,1)];
end;

However, on compilation, it complains that the [1, 2, 3, 4] syntax can only work for Integers.

Is there a way to instantiate/initialize an array of Tpoint similar to the way that i want?

Wurth answered 20/2, 2010 at 3:24 Comment(0)
S
25

Arrays of records can be intialised in const expressions:

const
  Points : TPointArray = ((X: 1; Y: 1), (X:1; Y:2), (X:1; Y:1), (X:1; Y:1));

class function rotationTable.offsets(pType, rotState, dir: integer): TpointArray;
begin
   Result := Points;
end;

In XE7 it is possible to fill a dynamic array of records like this:

function GetPointArray: TArray<TPoint>;
begin
  Result := [Point(1,1),Point(1,2),Point(1,1),Point(1,1)];
end;
Spratt answered 20/2, 2010 at 4:44 Comment(3)
This does not work (E2010 - incompatible types) in D2006 until I change the definition of the constant to Points : TpointArray = ...Equate
thanks @Equate - I may have been using a later version at the time. Also had syntax error with , instead of ;Spratt
Added an example of what is possible with XE7, hope it is ok :-)Livre
D
10

Plainth's answer demonstrates the constructor-like syntax for dynamic arrays. You can use that directly on a TPoint array to yield a much simpler helper function:

type
  TPointDynArray = array of TPoint;
  T4PointArray = array[0..3] of TPoint;

function PointDynArrayTo4PointArray(const input: TPointDynArray): T4PointArray;
var
  i: Integer;
begin
  Assert(Length(input) = Length(Result));
  for i := 0 to High(input) do
    Result[i] := input[i];
end;

class function rotationTable.offsets(pType, rotState, dir: integer): T4PointArray;
begin
  // New dynamic-array-constructor syntax here
  Result := PointDynArrayTo4PointArray(TPointDynArray.Create(
    Point(1,1), Point(1,2), Point(1,1), Point(1,1)));
end;

But that's overkill. Delphi also lets you define open arrays inline, and there's no additional constructor call to write. The result uses your original proposed syntax, but with the array wrapped inside a function call. It will work in all Delphi versions, whereas the "Create" syntax above is fairly new.

function PointOpenArrayTo4PointArray(const input: array of TPoint): T4PointArray;
var
  i: Integer;
begin
  Assert(Length(input) = Length(Result));
  for i := 0 to High(input) do
    Result[i] := input[i];
end;

class function rotationTable.offsets(pType, rotState, dir: integer): T4PointArray;
begin
  Result := PointOpenArrayTo4PointArray(
    [Point(1,1), Point(1,2), Point(1,1), Point(1,1)]);
end;

You might want to consider using Gerry's answer just to give your arrays of points meaningful names, which might help when debugging and one of the eight magic numbers in those point definitions is wrong.


Finally, a note on what Delphi meant when it said "the [1, 2, 3, 4] syntax can only work for Integers." That syntax defines a set, not an array. You can't have a set of record values, but you can have a set of integers. A side effect is that the syntax for a set of integers is the same as the syntax for an open array of integers. I think Delphi uses context to figure out which one you mean, but it can sometimes guess wrong.

Domain answered 20/2, 2010 at 15:25 Comment(0)
G
5

You cannot because you cannot express in the code body a point in the way in which you can express it in the const section.

However you can do some tricks in order to have your life easier, especially if you have a reasonable number of points.

You can implement a simple procedure like this (code not tested):

procedure BlendDimensions(aXArray, aYArray: TIntegerDynArray; var aResult: TPointArray);
var
  nCount: integer;
  i: integer;

begin
  nCount:=High(aXArray);
  if nCount <> High(aYArray) then 
    Exception.Create('The two dimension arrays must have the same number of elements!');

  SetLength(aResult, nCount);
  for i:=0 to nCount do
  begin
    aResult[i].X:=aXArray[i]; //simple copy
    aResult[i].y:=aYArray[i];
  end;
end;

...where TIntegerDynArray is the RTL's dynamic array of integers. (In fact it will work with any dynamic array). Also, TPointArray in the above example is also dynamic.

So, in order to do your job, you can do like this:

procedure Foo;
var
  myXCoords, myYCoords: TIntegerDynArray; //temp arrays
  myPoints: TPointArray; //this is the real thing

begin
  myXCoords:=TIntegerDynArray.Create( 1, 2, 3, 4, 5, 6, 7, 8, 9,10);
  myYCoords:=TIntegerDynArray.Create(21,32,34,44,55,66,65,77,88,92); //...for example 
  BlendDimensions(myXCoords, myYCoords, myPoints); //build the real thing
 //use it...
end;

Things to note:

  • You see clearly which are your points
  • You can be very productive in this way
  • You can use BlendDimensions also on other things not only on this one
  • You can easily expand BlendDimensions for 3 (or more) dimensions
  • ...but beware because a copy is involved. :-) With today PCs, the weakpoint will be, by far, your hand. :-) You will get tired to type much more quickly till the copy time will be even noticed.

HTH

Goods answered 20/2, 2010 at 7:46 Comment(1)
I wonder if this "array constructor" may be used for "array of record"Runt

© 2022 - 2024 — McMap. All rights reserved.