License delivery maintenance is planned for Saturday, July 26, between 12:00 and 20:00 CEST. During this time, you may experience outages or limited availability across our services, including BIMcloud SaaS, License Delivery, Graphisoft ID (for customer and company management), Graphisoft Store, and BIMx Web Viewer. More details…

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

Replacing one BIM Object with Another Object in the Archicad Project.

KirthikaSrinivasan-L
Contributor

Hi there! I'm trying to replace one BIM Object (which is already available in the Embedded Library) with another BIM Object using the code below. I'm finding the Lib_Part indices of both objects and setting the libInd of the old object to the new object's libInd (element.object.libInd = replacementLibPart.index;).

 

I'm facing APIERR_REFUSEDCMD error or APIERR_BADPARS error, when the code reaches ACAPI_Element_Change(). No Matter what I try, I'm unable to fix this. Can you please help me fix this?

 

Please let me know if my approach has any issues.

 

Thanks in Advance!.

 

 

// Function to find an object by name
API_LibPart FindLibPartByName(const char* partName) {
	API_LibPart libPart;
	BNZeroMemory(&libPart, sizeof(API_LibPart));

	GSErrCode err;
	Int32 numLibParts;
	ACAPI_LibraryPart_GetNum(&numLibParts);

	for (Int32 i = 1; i <= numLibParts; i++) {
		BNZeroMemory(&libPart, sizeof(API_LibPart));
		libPart.index = i;

		err = ACAPI_LibraryPart_Get(&libPart);
		char	docuname[256];
		GS::UniString docName = GS::UniString(libPart.docu_UName);
		const char* cString = docName.ToCStr().Get();

		if (err == NoError && strcmp(cString, partName) == 0) {
			return libPart;
		}
	}

	libPart.index = 0; // Return invalid index if not found
	return libPart;
}

// Function to replace all instances of an old object with a new one
GSErrCode BrowserPalette::ReplaceBIMObjects(const char* oldObjectName, const char* newObjectName) {

	// Get current object's library part
	API_LibPart oldLibPart;
	BNZeroMemory(&oldLibPart, sizeof(API_LibPart));

	//Adding oldobjectname's libpart
	oldLibPart = FindLibPartByName(oldObjectName);
	GS::UniString OldLibpartName(oldLibPart.docu_UName);

	API_LibPart replacementLibPart;
	BNZeroMemory(&replacementLibPart, sizeof(API_LibPart));

	replacementLibPart = FindLibPartByName(newObjectName);
	GS::UniString newLibpartName(replacementLibPart.docu_UName);

	if (ACAPI_LibPart_Get(&oldLibPart) == NoError) {

		ACAPI_WriteReport("Found Object: %s", true, OldLibpartName);

		if (ACAPI_LibPart_Get(&replacementLibPart) == NoError) {

			ACAPI_WriteReport("Replacing %s with %s", true, OldLibpartName.ToCStr().Get(), newLibpartName.ToCStr().Get());

			// Update the object's library part reference
			GS::Array<API_Guid> objectList;
			ACAPI_Element_GetElemList(API_ObjectID, &objectList);

			for (const auto& objGuid : objectList) {
				API_Element element;
				BNZeroMemory(&element, sizeof(API_Element));
				element.header.guid = objGuid;

				if (ACAPI_Element_Get(&element) == NoError) {

					if (element.object.libInd == oldLibPart.index) {
						//ACAPI_WriteReport("Found Element: %s", true, element.object.libInd);

						element.object.libInd = replacementLibPart.index; // Replace with new object index

						GSErrCode err = ACAPI_CallUndoableCommand("Change Object",
							[&]() -> GSErrCode {
							return ACAPI_Element_Change(&element, nullptr, nullptr, 0, false);
						});
						
						//GSErrCode err = ACAPI_Element_Change(&element, nullptr, nullptr, 0, true);

						if (err != NoError) {
								ACAPI_WriteReport("Error updating object: %d", true, err);
						}

					}
				}
			}

		}
		else {
			ACAPI_WriteReport("Replacement object %s not found in Embedded Library.", true, newLibpartName.ToCStr().Get());
		}
	}

	return NoError;
	}

 

1 ACCEPTED SOLUTION

Accepted Solutions
Solution
LChen
Graphisoft
Graphisoft

Hi, When you'd change an object, the index(libInd) only seems not enough. I think you need to set the mask ACAPI_ELEMENT_MASK_SET() as first, and pass the new object memo like:
ACAPI_Element_Change (&element, &mask, &memo, APIMemoMask_AddPars, true);
Please check the API Examples, you can find similar code which is using the command above.
HTH.

View solution in original post

1 REPLY 1
Solution
LChen
Graphisoft
Graphisoft

Hi, When you'd change an object, the index(libInd) only seems not enough. I think you need to set the mask ACAPI_ELEMENT_MASK_SET() as first, and pass the new object memo like:
ACAPI_Element_Change (&element, &mask, &memo, APIMemoMask_AddPars, true);
Please check the API Examples, you can find similar code which is using the command above.
HTH.