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.

Replacing Surface Materials based on MaterialName.

KirthikaSrinivasan-L
Contributor

Hi! I'm looking into ways to replace Surface Material (API_MaterialID), based on the name of the Material (after downloading the Material into the project). If I already know that my project has a material A applied to a window/door/wall/slab, and I want to download and import a material say B into the Project and replace all the instances of A in the project, with B, I'm unsure how to replace the instances. 

I tried getting the Attribute Indices of A and B and replacing B's 

Attr.header.typeID, Attr.header.index, Attr.material and Attr.material.texture.fileLoc values with A's corresponding values and deleting the A Attribute fully. But this doesn't seem to work. 

Please let me know if there is any other way to make this replacement work, on surface material level.

 

Edit: Let me rename the elements as plain A and B, as I think A1 and B1 is creating some confusions. 

Thank you in Advance.

 

 

API_AttributeIndex FindSurfaceMaterialIndex(const char* MaterialName)
{
	API_AttrTypeID	typeID;
	GSErrCode		err = NoError;
	API_AttributeIndex test;

	for (typeID = API_FirstAttributeID; typeID <= API_LastAttributeID; ((Int32&)typeID)++) {
		GS::Array<API_Attribute> attributes;
		err = ACAPI_Attribute_GetAttributesByType(typeID, attributes);
		if (err != NoError) {
			DBPrintf("Error in ACAPI_Attribute_GetAttributesByType", err);
			continue;
		}

		if (typeID == API_MaterialID)
		{
			short count = 1;
			for (API_Attribute& attrib : attributes) {
				char guidStr[64];
				APIGuid2GSGuid(attrib.header.guid).ConvertToString(guidStr);

				if (strcmp(attrib.header.name, MaterialName) == 0) {  // Match found
					test = attrib.header.index;
					return test;
				}
				count++;  //index loc for reference
			}
		}

	}
	return ACAPI_CreateAttributeIndex(0);
}

// Function to replace a surface material
GSErrCode	ReplaceSurfaceMaterial(const char* oldMaterialName, const char* newMaterialName) {
	API_AttributeIndex oldAttribute = FindSurfaceMaterialIndex(oldMaterialName);
	API_AttributeIndex newAttribute = FindSurfaceMaterialIndex(newMaterialName);

	API_Attribute oldAttr, newAttr;
	BNZeroMemory(&oldAttr, sizeof(API_Attribute));
	BNZeroMemory(&newAttr, sizeof(API_Attribute));

	oldAttr.header.typeID = API_MaterialID;
	oldAttr.header.index = oldAttribute;

	newAttr.header.typeID = API_MaterialID;
	newAttr.header.index = newAttribute;

	if (ACAPI_Attribute_Get(&oldAttr) != NoError) {
		return 0;
	}

	// Copy all properties from the new material to the old material
	newAttr.material = oldAttr.material;  
	
	newAttr.material.texture.fileLoc = oldAttr.material.texture.fileLoc;

	char guidStr[64];
	APIGuid2GSGuid(newAttr.header.guid).ConvertToString(guidStr);

	DBPrintf("\n");
	DBPrintf("  [%3s]   {%s}  \"%s\"", newAttr.header.index.ToUniString().ToCStr().Get(), guidStr, newAttr.header.name);

	GSErrCode err2 = ACAPI_Attribute_Delete(oldAttr.header);

	newAttr.header.index = oldAttr.header.index;

	GSErrCode err = ACAPI_Attribute_Modify(&newAttr, nullptr);
	if (err != NoError) {
		return err;
	}

	if (ACAPI_Attribute_Get(&newAttr) != NoError) {
		return 0;
	}

	return NoError;
}

 

 

 

 

6 REPLIES 6
Lingwisyer
Guru

The API sub can be found here for future reference.

 

@Barry Kelly or someone can move this thread for you when they see it.

AC22-28 AUS 3110Help Those Help You - Add a Signature
Self-taught, bend it till it breaksCreating a Thread
Win11 | i9 10850K | 64GB | RX6600 Win11 | R5 2600 | 16GB | GTX1660
Lingwisyer
Guru

I am no C++ coder, but are you replacing the information within each material with that of your desired one? Would you not just completely replace the material;

  1. parse material library for "const char", write result to A1 to An
  2. find index of A1 to An
  3. store string Prior to "const char" for A1 to An
  4. store string After "const char" for A1 to An
  5. delete A1 to An from material library
  6. duplicate B1 => B2 to Bn
  7. replace the index of B2 to Bn with the stored values from A1 to An?
  8. ammend name B2 to Bn with Prior "const char" After

Or is that just really memory inefficient?

Or maybe that is what you have done, I am no C++ coder...

AC22-28 AUS 3110Help Those Help You - Add a Signature
Self-taught, bend it till it breaksCreating a Thread
Win11 | i9 10850K | 64GB | RX6600 Win11 | R5 2600 | 16GB | GTX1660
LChen
Graphisoft
Graphisoft

Hi, Your code shows me that you deleted the oldAttr, then you try to use the oldAttr index to modify...

newAttr.header.index = oldAttr.header.index;
ACAPI_Attribute_Modify(&newAttr,...

If you'd modify a material attribute, the material should not be removed.
HTH.

KirthikaSrinivasan-L
Contributor

@LChen 

Thank you for your reply!

 

That doesn't fix the problem. The replacement of the Surface Material still doesn't seem to work.

 

For example, I want the Surface Material used in the API_WindowID and API_DoorID to be overwritten with a new Surface Material, based on the Material Name.

 

Please let me know how to do this. 

 

Hi @LChen @Ralph Wessel,

Can you please help?

ACAPI_Attribute_Delete has been removed as per @LChen's suggestion. It didn't seem to fix the issue. I want to replace the old surface material with new surface material, in archicad, based on the surface material's name. 

 

I have got the attribute's index using FindSurfaceMaterialIndex().

Can you please let me know how I can perform the replacement of one surface material with another surface material?

 

 

API_AttributeIndex FindSurfaceMaterialIndex(const char* MaterialName)
{
	API_AttrTypeID	typeID;
	GSErrCode		err = NoError;
	API_AttributeIndex test;

	for (typeID = API_FirstAttributeID; typeID <= API_LastAttributeID; ((Int32&)typeID)++) {
		GS::Array<API_Attribute> attributes;
		err = ACAPI_Attribute_GetAttributesByType(typeID, attributes);
		if (err != NoError) {
			DBPrintf("Error in ACAPI_Attribute_GetAttributesByType", err);
			continue;
		}

		if (typeID == API_MaterialID)
		{
			short count = 1;
			for (API_Attribute& attrib : attributes) {
				char guidStr[64];
				APIGuid2GSGuid(attrib.header.guid).ConvertToString(guidStr);

				if (strcmp(attrib.header.name, MaterialName) == 0) {  // Match found
					test = attrib.header.index;
					return test;
				}
				count++;  //index loc for reference
			}
		}

	}
	return ACAPI_CreateAttributeIndex(0);
}

// Function to replace a surface material
GSErrCode	ReplaceSurfaceMaterial(const char* oldMaterialName, const char* newMaterialName) {
	API_AttributeIndex oldAttribute = FindSurfaceMaterialIndex(oldMaterialName);
	API_AttributeIndex newAttribute = FindSurfaceMaterialIndex(newMaterialName);

	API_Attribute oldAttr, newAttr;
	BNZeroMemory(&oldAttr, sizeof(API_Attribute));
	BNZeroMemory(&newAttr, sizeof(API_Attribute));

	oldAttr.header.typeID = API_MaterialID;
	oldAttr.header.index = oldAttribute;

	newAttr.header.typeID = API_MaterialID;
	newAttr.header.index = newAttribute;

	if (ACAPI_Attribute_Get(&oldAttr) != NoError) {
		return 0;
	}

	// Copy all properties from the new material to the old material
	newAttr.material = oldAttr.material;  
	
	newAttr.material.texture.fileLoc = oldAttr.material.texture.fileLoc;

	char guidStr[64];
	APIGuid2GSGuid(newAttr.header.guid).ConvertToString(guidStr);

	DBPrintf("\n");
	DBPrintf("  [%3s]   {%s}  \"%s\"", newAttr.header.index.ToUniString().ToCStr().Get(), guidStr, newAttr.header.name);

	newAttr.header.index = oldAttr.header.index;

	GSErrCode err = ACAPI_Attribute_Modify(&newAttr, nullptr);
	if (err != NoError) {
		return err;
	}

	if (ACAPI_Attribute_Get(&newAttr) != NoError) {
		return 0;
	}

	return NoError;
}

 

Do you just want to edit the existing materials rather than reassigning the materials assigned to elements?

Ralph Wessel BArch
Central Innovation

Didn't find the answer?

Check other topics in this Forum

Back to Forum

Read the latest accepted solutions!

Accepted Solutions

Start a new conversation!