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…
2025-02-25 08:11 AM - edited 2025-03-03 11:44 PM
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;
}
2025-02-25 08:33 AM
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 3110 | Help Those Help You - Add a Signature |
Self-taught, bend it till it breaks | Creating a Thread |
Win11 | i9 10850K | 64GB | RX6600 | Win11 | R5 2600 | 16GB | GTX1660 |
2025-02-25 08:48 AM - edited 2025-02-25 09:28 AM
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;
Or is that just really memory inefficient?
Or maybe that is what you have done, I am no C++ coder...
AC22-28 AUS 3110 | Help Those Help You - Add a Signature |
Self-taught, bend it till it breaks | Creating a Thread |
Win11 | i9 10850K | 64GB | RX6600 | Win11 | R5 2600 | 16GB | GTX1660 |
2025-03-04 04:29 AM
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.
2025-03-11 11:49 PM
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.
2025-05-14 02:20 AM
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;
}
2025-05-14 09:19 AM
Do you just want to edit the existing materials rather than reassigning the materials assigned to elements?