Archicad C++ API
About Archicad add-on development using the C++ API.

Writing back an array

runxel
Legend
I'm working on a GDL add-on (you know, the thing you call with "open("NAME", "", ...)").
What I want to achieve is to yield an array, in the best case a two-dimensional one, back to GDL.

I know I have to write inside the `InputFromDataFile` function to the GDLRequestResult param.
So far, so good. But how to construct the array?
And how to declare the variable in GDL beforehand? Mind you: The user doesn't know how big the array is!
Lucas Becker | AC 27 on Mac | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text |
«Furthermore, I consider that Carth... yearly releases must be destroyed»
10 REPLIES 10
what file type are you opening to extra the data?
Creator of Cadswift's parametric GDL libraries
Creator of Infinite Openings and Component Catalogues
Push the envelope & watch it bend
website: https://cadswift.com.au/
YouTube: https://www.youtube.com/user/CADSwift/playlists
runxel
Legend
Kristian wrote:
what file type are you opening to extra the data?
None actually, haha.
I need the GDL add-on purely for calculations I can't do in GDL.
So, the add-on gets some input and performs calculations on that, and then shall return a multidimensional array.
To make this extra spicy: I can't determine beforehand what size the array will have.

I know that I could do e.g. a
dim myarray[5]
in GDL, then use
value.AddDouble(123.45)
value.AddDouble(42.0)
...
in the add-on.
But this only fills one dimension, and also I need to initialize the array in GDL with either a fixed size, or
dim myarray[] ! dynamic
myarray[1] = 0.0 ! init cell with value


My consideration right now is to instead use a dict in GDL (needs no init!), which then can be filled with an array in the add-on. But I can't figure out how to setup a dict in the GS c++ style either

By the way: can you explain me what type 'GdlValueRecord' is? What it is that for?
Lucas Becker | AC 27 on Mac | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text |
«Furthermore, I consider that Carth... yearly releases must be destroyed»
Ralph Wessel
Mentor
In what context will the GDL add-on be called, e.g. within the parameter script? This is important because you can't really make any parameter changes outside of that scope.
Ralph Wessel BArch
runxel
Legend
Ralph wrote:
In what context will the GDL add-on be called, e.g. within the parameter script? This is important because you can't really make any parameter changes outside of that scope.
Hi Ralph, thanks for tuning in!
From the 2D script. No parameters need to be changed. The values from the calculation add-on shall be used directly for drawing things
Lucas Becker | AC 27 on Mac | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text |
«Furthermore, I consider that Carth... yearly releases must be destroyed»
Ralph Wessel
Mentor
Could you simply define an empty array and 2 variables for the number of rows/columns in the GDL script, then pass those to the GDL add-on? The GDL add-on adds the rows/columns to the result and the list of array values. The GDL script can then unpack the returned array as required using the returned row/column count.
Ralph Wessel BArch
runxel
Legend
Ralph wrote:
Could you simply define an empty array in the GDL script
Are you sure that this is the way? I couldn't get it to work in my tests. If there was an empty dynamic array passed to the GDL add-on it refused to return anything.
If I try to access the array in GDL again it always says "out of bounds" which means there is nothing in there.
Lucas Becker | AC 27 on Mac | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text |
«Furthermore, I consider that Carth... yearly releases must be destroyed»
I don't know exactly how to achieve what you want as i don't know the structure of the resulting data/array you are working with. However, with all my data extractions into an array (GDL XML Extension and earlier GDL Text I/O Add-on) I always have to;
> as Ralph said, declare a dynamic array first in the GDL script, then
> open the data and use loop functions and the INPUT commands to navigate through the data to each value I wish to extract. These values populate the previously declared dynamic array during the INPUT commands. to use the 2D aspect of the dynamic array you have to tell it when to move to the next row, which is what you base the structure of your loop statements on; you can set this based on info you pick up out of the data your are importing.

I am not sure if all this works for what you are doing but hope the logic is somehow applicable.
Creator of Cadswift's parametric GDL libraries
Creator of Infinite Openings and Component Catalogues
Push the envelope & watch it bend
website: https://cadswift.com.au/
YouTube: https://www.youtube.com/user/CADSwift/playlists
Ralph Wessel
Mentor
runxel wrote:
I couldn't get it to work in my tests. If there was an empty dynamic array passed to the GDL add-on it refused to return anything.
If I try to access the array in GDL again it always says "out of bounds" which means there is nothing in there.
We are eliminating the use of GDL add-ons from our toolset because they cause too many problems for customers. But from previous tools, we did the following in GDL (rough pseudocode):
dim incomingValues[]
rowCount = 0
colCount = 0
unused = input(presetChannel, "Get_Array_Par", "requiredParameterName", rowCount, colCount, incomingValues)
…and the following in the addon (again, rough pseudocode):
GSErr __GDLEXT_CALL InputFromDataFile(Int32 channel, GS::UniString const &recordID, GS::UniString const &fieldID, Int32 inCount, Int32* outCount, GS::Array<GdlValueRecord> &values, GS::Array<GS::UniString> &strings)
{
	//...code to define rows, cols etc here
	
	*outCount = rows * cols + 2;
	values.SetCapacity(*outCount);
	
	GdlValueRecord rowRecord, colRecord;
	rowRecord.SetLong(rows);
	colRecord.SetLong(cols);
	values.Push(rowRecord);
	values.Push(colRecord);
	
	for (…however you iterate through your array data) {
		GdlValueRecord record;
		switch (…whatever data type…) {
			case intType: 
				record.SetLong(…int value…); 
				break;
			case realType: 
				record.SetDouble(…double value…); 
				break;
			case strType: 
				record.SetString(…next string index…);
				strings.Push(…string value…);
				upto++;
				break;
		}
		values.Push(record);	
	}
}
This is a bit rough, but might point you in the right direction. Depends a lot on what you want to do.
Ralph Wessel BArch
runxel
Legend
Thanks a lot to both of you, and especially to you, Ralph, for finally some code!

I read that statement of yours already somewhere here. What is your recommendation for replacement then? A normal add-on that somehow populates an object after reading it's parameters? If that's possible (I guess with ACAPI_​Element_​Change, but how to "auto"-call it?), are there code examples for this? Code examples is something the documentation is lacking a lot.

Regarding your code example:
When I replace GDLRequestResult with GS::Array<GdlValueRecord> the compiling will give me linking errors (LNK2001) in the GDLDev.lib – but not declaring the return value an array isn't what I am after, either. Obviously. 😕
Lucas Becker | AC 27 on Mac | Author of Runxel's Archicad Wiki | Editor at SelfGDL | Developer of the GDL plugin for Sublime Text |
«Furthermore, I consider that Carth... yearly releases must be destroyed»