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

Changing the parameter of a placed GDL object

BenjiDev
Enthusiast

 

I know this questions has been asked a couple of time but looking at other answers and the API docs i just still can't get this to work. 

 

I have created a dummy GDL object (just a simple 2D rect) and added a custom GDL parameter "test_param" of type length: 

BenjiDev_0-1663881167263.png

Then i created a simple function in my C++ addon that picks the selected element and changes "test_param" to 1234.0:

 

 

 

					/* TESTING: Trying to change value of parameter "test_param" to 1234.0 in selected object*/

					// 1: Get the first selected element
					API_SelectionInfo    selectionInfo;
					GS::Array<API_Neig>  selNeigs;
					auto err = ACAPI_Selection_Get(&selectionInfo, &selNeigs, true);
					BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
					if (selNeigs.GetSize() != 1)
						return NoError;
					
					API_Element  element;
					element.header.guid = selNeigs[0].guid;
					err = ACAPI_Element_Get(&element);
					if (err)
						return err;

					// 2: Open the parameter list for the selected element
					API_ParamOwnerType   paramOwner;
					BNZeroMemory(&paramOwner, sizeof(API_ParamOwnerType));
					paramOwner.libInd = 0;                      /* no library part */
					paramOwner.type.typeID = API_ObjectID;      /* object element */
					paramOwner.guid = element.header.guid;      /* selected element */
					err = ACAPI_Goodies(APIAny_OpenParametersID, &paramOwner, nullptr);
					if (err)
						return err;

					// 3: Change the param "test_param" to 1234.0 in the parameter list
					API_ChangeParamType chgParam;
					BNZeroMemory(&chgParam, sizeof(API_ChangeParamType));
					CHCopyC("test_param", chgParam.name);
					chgParam.realValue = 1234.0;
					err = ACAPI_Goodies(APIAny_ChangeAParameterID, &chgParam, nullptr);
					if (err)
						return err;

					// 4: Get the updated parameter list
					API_GetParamsType getParams;
					BNZeroMemory(&getParams, sizeof(API_GetParamsType));
					err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
					if (err)
						return err;


					// 5: VERIFICATION, check that the parameter "test_param" was updated correctly to 1234.0
					bool testParamWasChanged = false;
					for (int i = 0; i < GetHandleSize(getParams.params); i++) {
						auto param = (*getParams.params)[i];
						if (strcmp(param.name, "test_param") == 0 && param.value.real == 1234.0) {
							testParamWasChanged = true;
							break;
						}
					}
					assert(testParamWasChanged);

					// 6: Close the updated parameter list
					err = ACAPI_Goodies(APIAny_CloseParametersID, nullptr, nullptr);
					if (err)
						return err;


					// 7 Update the memo of the selected element with the updated parameter list
					API_ElementMemo  memo;
					BNZeroMemory(&memo, sizeof(API_ElementMemo));
					memo.params = getParams.params;
					API_Element mask;
					ACAPI_ELEMENT_MASK_CLEAR(mask);
					err = ACAPI_CallUndoableCommand("Change test_param to 1234.0", [&]() {
						return ACAPI_Element_Change(&element, &mask, &memo, APIMemoMask_AddPars, true);
					});
					if (err)
						return err;

					//8: VERIFICATION, Check that "test_param" was updated correctly in the memo structure after "ACAPI_Element_Change"
					err = ACAPI_Element_GetMemo(element.header.guid, &memo, APIMemoMask_AddPars);
					testParamWasChanged = false;
					for (int i = 0; i < GetHandleSize(memo.params); i++) {
						auto param = (*memo.params)[i];
						if (strcmp(param.name, "test_param") == 0 && param.value.real == 1234.0) {
							testParamWasChanged = true;
							break;
						}

					}
					assert(testParamWasChanged);
					ACAPI_DisposeAddParHdl(&getParams.params);
					return err;

 

 

 

I select the element and run the procedure, every error check passes and i can even verify that "test_param" was successfully changed to 1234.0 both in the parameter list and in the parameters of the elements memo after updating it.

But when opening up the parameter of the GDL object afterwards (in the first picture above) its initial value 10.0 is unchanged. I must have missed something obvious here, any help or thought is appretiated. 

1 ACCEPTED SOLUTION

Accepted Solutions
Solution
BenjiDev
Enthusiast

Simple mistake, the GDL object parameter is actually updated correctly if opened in the object tool (CTRL+T). 

View solution in original post

3 REPLIES 3
Solution
BenjiDev
Enthusiast

Simple mistake, the GDL object parameter is actually updated correctly if opened in the object tool (CTRL+T). 

ReignBough
Enthusiast

I am also trying to change parameters but from an array. I have this code:

 

API_ParamOwnerType owner;
BNZeroMemory(&owner, sizeof(API_ParamOwnerType));
owner.libInd = 0;
owner.typeID = elem.header.typeID;
owner.variationID = elem.header.variationID;
owner.guid = elem.header.guid;
err = ACAPI_Goodies(APIAny_OpenParametersID, &owner);

API_GetParamsType params = {};
err = ACAPI_Goodies(APIAny_GetActParametersID, &params);
API_AddParType neededPar = ...; // params[i].name = "neededPar"

for (Int32 r = 0; r < neededPar.dim1; ++r)
{
    for (Int32 c = 0; c < neededPar.dim2; ++c)
    {
        API_ChangeParamType par = {};
        CHCopyC(neededPar.name, par.name);
        par.ind1 = r;
        par.ind2 = c;
        par.realValue = realVal;
        err = ACAPI_Goodies(APIAny_ChangeAParameterID, &par); <-- returns APIERR_BADPARS
    }
}

err = ACAPI_Goodies(APIAny_CloseParametersID);

 

 But I got an APIERR_BADPARS. Where did I go wrong?

 

EDIT: added the neededPar to the code

~ReignBough~
ARCHICAD 26 INT (from AC18)
Windows 11 Pro, AMD Ryzen 7, 3.20GHz, 32.0GB RAM, 64-bit OS

I think the error occurs because the integers (r and c) are starting at 0, they should start at 1. If I'm not mistaken the indexes of GDL arrays starts at 1.

 

Additionally, calling 

 

 

 

 

ACAPI_Goodies(APIAny_CloseParametersID)

 

 

 

 

Is not enough to update the parameters of the element. You are not operating on the actual parameter list of an element when using APIAny_ChangeAParameterID , APIAny_CloseParametersID etc... but rather a copy. So when you are done you need to 

 get the parameter list using APIAny_GetActParametersID, this will contain the result of all your changes.

 

And then updating the memo of the element using the result of APIAny_GetActParametersID is what is actually updating the parameters. See step 7 in my code.