Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2017-09

Syntax to select constant or variable with function call

10 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

James Richters

I have several Similar arrays as follows for translating various color schemes into RGB565, I currently have 5 arrays but may add more.

ACI256: Array[0..255] of VGARGBRec = (
(R:$00; G:$00; B:$00; RGB:$0000), //[ 0]
(R:$FF; G:$00; B:$00; RGB:$F800), //[ 1]
(R:$FF; G:$FF; B:$00; RGB:$FFE0), //[ 2]
(R:$00; G:$FF; B:$00; RGB:$07E0), //[ 3]
(R:$00; G:$FF; B:$FF; RGB:$07FF), //[ 4]
..

      (R:$FF; G:$FF; B:$FF; RGB:$FFFF)); //[255]

VGA256: Array[0..255] of VGARGBRec = (
(R:$00; G:$00; B:$00; RGB:$0000), //[000]
(R:$00; G:$00; B:$AA; RGB:$0015), //[001]
(R:$00; G:$AA; B:$00; RGB:$0540), //[002]
(R:$00; G:$AA; B:$AA; RGB:$0555), //[003]
(R:$AA; G:$00; B:$00; RGB:$A800), //[004]
..

      (R:$00; G:$00; B:$00; RGB:$0000)); //[255]

I have some simple functions that use these arrays for example this one to find the closest value to specified Red, Green, and Blue values:

Function Find_VGA(r ,g ,b : Word) : Byte;
Var
  Dist,closest:Double;
  i,bestchoice:Byte;
Begin
   Closest:=200000;
   For i:= 0 to 255 do
      Begin
         Dist :=  ((R-VGA256[i].R))*((R-VGA256[i].R)) + ((G-VGA256[i].G)*(G-VGA256[i].G)) + ((B-VGA256[i].B)*(B-VGA256[i].B));
         If Dist<Closest Then
            Begin
               Closest:=Dist;
               BestChoice:=i;
            End;
      End;
   Find_VGA:=BestChoice;
End;

Instead of having a bunch of separate functions,
I would like to know if there is a way I can specify which constant to use directly so the one function could use any of the arrays.

Something like
function Find_Color(Array_to_use:var ;r ,g ,b : Word) : Byte;

then use Array_to_use[i] instead of VGA256[i] in my formula...

so calling Find_Color(VGA256,$00,$FF,$FC) would use the VGA256 array and calling Find_Color(ACI256,$00,$FF,$FC) would use the ACI256 array.. etc..

Is this kind of thing even possible? Or do I just need separate functions?

James

Michael Van Canneyt
to James Richters
James Richters wrote 55 lines
I have several Similar arrays as follows for translating various color schemes into RGB565, I currently have 5 arrays but may add more. ACI256: Array[0..255] of VGARGBRec = ( (R:$00; G:$00; B:$00; RGB:$0000), //[ 0] (R:$FF; G:$00; B:$00; RGB:$F800), //[ 1] (R:$FF; G:$FF; B:$00; RGB:$FFE0), //[ 2] (R:$00; G:$FF; B:$00; RGB:$07E0), //[ 3] (R:$00; G:$FF; B:$FF; RGB:$07FF), //[ 4] .. (R:$FF; G:$FF; B:$FF; RGB:$FFFF)); //[255] VGA256: Array[0..255] of VGARGBRec = ( (R:$00; G:$00; B:$00; RGB:$0000), //[000] (R:$00; G:$00; B:$AA; RGB:$0015), //[001] (R:$00; G:$AA; B:$00; RGB:$0540), //[002] (R:$00; G:$AA; B:$AA; RGB:$0555), //[003] (R:$AA; G:$00; B:$00; RGB:$A800), //[004] .. (R:$00; G:$00; B:$00; RGB:$0000)); //[255] I have some simple functions that use these arrays for example this one to find the closest value to specified Red, Green, and Blue values: Function Find_VGA(r ,g ,b : Word) : Byte; Var Dist,closest:Double; i,bestchoice:Byte; Begin Closest:=200000; For i:= 0 to 255 do Begin Dist := ((R-VGA256[i].R))*((R-VGA256[i].R)) + ((G-VGA256[i].G)*(G-VGA256[i].G)) + ((B-VGA256[i].B)*(B-VGA256[i].B)); If Dist<Closest Then Begin Closest:=Dist; BestChoice:=i; End; End; Find_VGA:=BestChoice; End; Instead of having a bunch of separate functions, I would like to know if there is a way I can specify which constant to use directly so the one function could use any of the arrays. Something like function Find_Color(Array_to_use:var ;r ,g ,b : Word) : Byte; then use Array_to_use[i] instead of VGA256[i] in my formula... so calling Find_Color(VGA256,$00,$FF,$FC) would use the VGA256 array and calling Find_Color(ACI256,$00,$FF,$FC) would use the ACI256 array.. etc.. Is this kind of thing even possible? Or do I just need separate functions?

This is certainly possible.

First, define
Type
   TVGA256Array = Array[0..255] of VGARGBRec;
   PVGA256Array = ^TVGA256Array;

And redeclare your arrays as:
ACI256: TVGA256Array = (

   // etc
    VGA256: TVGA256Array  = (
   // etc
Then define
function Find_Color(anArray :PVGA256Array; r ,g ,b : Word) : Byte;
  Var
   Dist,closest:Double;
   i,bestchoice:Byte;
begin
    Closest:=200000;
    For i:= 0 to 255 do
       Begin
          Dist :=  ((R-AnArray^[i].R))*((R-AnArray^[i].R))
                     + ((G-AnArray^[i].G)*(G-Anarray^[i].G))
                     + ((B-AnArray^[i].B)*(B-AnArray^[i].B));
          If Dist<Closest Then
             Begin
                Closest:=Dist;
                BestChoice:=i;
             End;
       End;
    Find_VGA:=BestChoice;
end;

Call as
Find_Color(@VGA256,$00,$FF,$FC)
etc.

Alternatively, you can avoid the pointer if you declare the function as

function Find_Color(constref anArray :TVGA256Array; r ,g ,b : Word) : Byte;
you can then get rid of the dereferencing:
          Dist :=  ((R-AnArray[i].R))*((R-AnArray[i].R))
                     + ((G-AnArray[i].G)*(G-Anarray[i].G))
                     + ((B-AnArray[i].B)*(B-AnArray[i].B));

The loop can still be optimized, but that is another topic.

Michael.

Unknown author
to Unknown author: should that be Find_Color:=BestChoice; ?? NOTE: No off-list assistance is given without…
should that be Find_Color:=BestChoice; ??

Yes, it should be, Also noticed a typo in my groupings, it wouldn't affect anything but I like to make it clear.

So now I have this for the function:

function Find_Color(Constref ColorArray :TVGA256Array; R ,G ,B : Word) : Byte;
Var
   Dist,Closest:Double;
   I,BestChoice:Byte;
Begin
    Closest:=200000;
    For I:= 0 to 255 do
       Begin
          Dist := ((R-ColorArray[i].R)*(R-ColorArray[i].R))
                + ((G-ColorArray[i].G)*(G-ColorArray[i].G))
                + ((B-ColorArray[i].B)*(B-ColorArray[i].B));
          If Dist < Closest Then
             Begin
                Closest:=Dist;
                BestChoice:=I;
             End;
       End;
    Find_Color:=BestChoice;
end;

I have 2 arrays that are not [0..255], one is [1..14] the other is [0..15] is there a way I could expand this scheme to use those arrays as well? The For loop would need to adjust to the size of the arrays somehow.

James

Unknown author
to Michael Van Canneyt: This is certainly possible. First, define Type TVGA256Array = Array[0..255] of VGARGBRec;…
Michael Van Canneyt wrote 21 lines
Then define function Find_Color(anArray :PVGA256Array; r ,g ,b : Word) : Byte;  Var   Dist,closest:Double;   i,bestchoice:Byte; begin    Closest:=200000;    For i:= 0 to 255 do       Begin          Dist :=  ((R-AnArray^[i].R))*((R-AnArray^[i].R))                     + ((G-AnArray^[i].G)*(G-Anarray^[i].G))                     + ((B-AnArray^[i].B)*(B-AnArray^[i].B));          If Dist<Closest Then             Begin                Closest:=Dist;                BestChoice:=i;             End;       End;    Find_VGA:=BestChoice; end;
should that be Find_Color:=BestChoice; ??
NOTE: No off-list assistance is given without prior approval. *Please keep mailing list traffic on the list unless* *a signed and pre-paid contract is in effect with us.*
James Richters
to Unknown author

Thank you for explaining how to achieve this.
I am curious about the meaning behind the prefixes you used:

TVGA256Array = Array[0..255] of VGARGBRec; PVGA256Array = ^TVGA256Array;

Do the T and P in front of VGA256Array have a special meaning or significance? I see things like that all the time, but never really understood why there are these designations.

I should have mentioned that not all my arrays are [0..255], Most are, but I have some that are [0..15] and one that is [1..14] Is there a way to implement a variable size array and somehow use the array minimum and maximum element in the for loop?

The loop can still be optimized, but that is another topic.

Please elaborate, how this loop could be optimized? I've been trying to think of ways to improve it, and suggestions would be most welcome.

James

Sven Barth
to James Richters
James Richters wrote 5 lines
Thank you for explaining how to achieve this. I am curious about the meaning behind the prefixes you used: > TVGA256Array = Array[0..255] of VGARGBRec; > PVGA256Array = ^TVGA256Array; Do the T and P in front of VGA256Array have a special meaning or significance? I see things like that all the time, but never really understood why there are these designations.

"T" and "P" are simply the typical Hungarian notations in Pascal for ordinary types and pointer types respectively.

I should have mentioned that not all my arrays are [0..255], Most are, but I have some that are [0..15] and one that is [1..14] Is there a way to implement a variable size array and somehow use the array minimum and maximum element in the for loop?

If you use open array parameters you can do that. E.g.

=== code begin ===

program tdynarr;
const
  Array1: array[0..3] of LongInt = (1, 2, 3, 4);
  Array2: array[2..6] of LongInt = (1, 2, 3, 4, 5);
{ Important: a dynamic array type (aka "TArray = array of LongInt") for
the array parameter will only work with 0 based array constants (in this
case Array1) }
procedure DoArray(aArr: array of LongInt);
begin
  Writeln(Low(aArr), '..', High(aArr));
end;
begin
  DoArray(Array1);
  DoArray(Array2);
end.

=== code end ===

Please note that an open array is always zero based so the output of the above example will be:

=== output begin ===

0..3
0..4

=== output end ===

Regards,
Sven

Ralf Quint
to James Richters: Thank you for explaining how to achieve this. I am curious about the meaning behind the…
James Richters wrote 5 lines
Thank you for explaining how to achieve this. I am curious about the meaning behind the prefixes you used: > TVGA256Array = Array[0..255] of VGARGBRec; > PVGA256Array = ^TVGA256Array; Do the T and P in front of VGA256Array have a special meaning or significance? I see things like that all the time, but never really understood why there are these designations.

It is called (IMHO a bad form of) "Hungarian Notation", an identifier naming convention that should help to make source code more readable. In [Borland,Turbo,Free]Pascal, the first latter is indicating what kind of indentifier it is.
 "t" denotes a Type
 "p" denotes a pointer to a Type
"c" denotes a constant
(I personally prefer to use low case letters for that preceding character, it is IMHO much better readable).

So yes, in this case, the T and P do have a special meaning, but are of
no significance...

Ralf

---
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

James Richters
See what I wrote yesterday :)

Sorry I had a duplicate message, I was having difficulty with my email and accidentally sent a mail with an alias, I thought it was rejected but it was just delayed.

Here is what I have now, and it's working great, thanks for the help.

Function Find_Color(ColorArray : Array of VGARGBRec; R ,G ,B : Word) : Byte;
Var
   Dist,Closest:Double;
   i,BestChoice:Byte;
Begin
   Closest:=200000;
   For i:= Low(ColorArray) to High(ColorArray) do
      Begin
         Dist := ((R-ColorArray[i].R)*(R-ColorArray[i].R))
               + ((G-ColorArray[i].G)*(G-ColorArray[i].G))
               + ((B-ColorArray[i].B)*(B-ColorArray[i].B));
         If Dist <= Closest Then
            Begin
               Closest:=Dist;
               BestChoice:=i;
            End;
      End;
   Find_Color:=BestChoice;
end;
Call with:
Find_Color(Arrayname, Red, Green, Blue);
The loop can still be optimized, but that is another topic.

Please elaborate, I would be very interested in how this could be optimized.

James

Michael Van Canneyt
to James Richters
James Richters wrote 33 lines
> See what I wrote yesterday :) Sorry I had a duplicate message, I was having difficulty with my email and accidentally sent a mail with an alias, I thought it was rejected but it was just delayed. Here is what I have now, and it's working great, thanks for the help. Function Find_Color(ColorArray : Array of VGARGBRec; R ,G ,B : Word) : Byte; Var Dist,Closest:Double; i,BestChoice:Byte; Begin Closest:=200000; For i:= Low(ColorArray) to High(ColorArray) do Begin Dist := ((R-ColorArray[i].R)*(R-ColorArray[i].R)) + ((G-ColorArray[i].G)*(G-ColorArray[i].G)) + ((B-ColorArray[i].B)*(B-ColorArray[i].B)); If Dist <= Closest Then Begin Closest:=Dist; BestChoice:=i; End; End; Find_Color:=BestChoice; end; Call with: Find_Color(Arrayname, Red, Green, Blue); > The loop can still be optimized, but that is another topic. Please elaborate, I would be very interested in how this could be optimized.

1. Use a pointer to the element in the array.
2. Use SQR instead of x*x
2. Use With to calculate your distance

     With ColorArray[i] do
       Dist :=Sqr(aR-R)+Sqr(aG-G)+Sqr(aB-B);

I would think that something like the following is the most optimal:

  Function Find_Color(ColorArray : Array of VGARGBRec; aR ,aG ,aB : Word) : Byte;
  Var
    Dist,Closest:Double;
    i,BestChoice:Byte;
    P : ^VGARGBRec;
  Begin
    BestChoice:=255;
    Closest:=200000;
    (ColorArray)];
    For i:= Low(ColorArray) to High(ColorArray) do
      begin
      With P^ do
        Dist:=Sqr(aR-R)+Sqr(aG-G)+Sqr(aB-B);
      If Dist<=Closest Then
        Begin
        Closest:=Dist;
        BestChoice:=i;
        End;
      Inc(P);
      end;
    Find_Color:=BestChoice;
  end;

I didn't test the code, but you catch my drift, I suppose...

Michael.