cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 
2024 Technology Preview Program

2024 Technology Preview Program:
Master powerful new features and shape the latest BIM-enabled innovations

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

Wall Quantities Extraction

Apollos
Booster

Dear fellow Archicad C++ Users,

I am trying to extract the Quantities of walls (particularly composite walls). I followed the example folder Element_Snippets. But I am stuck, please I need help. I have tried several code setups some crashed but only this one gave me a WriteReport Dialog page but with Wall GUIDs but no Composite as output. 

Please here is my code, any useful help and guidance is appreciated.

 

void ExtractCompositeWallQuantities1() {
    GS::Array<API_Guid> wallGuids;
    ACAPI_Element_GetElemList(API_WallID, &wallGuids, APIFilt_OnActFloor);

    char reportBuffer[4096];
    BNZeroMemory(reportBuffer, sizeof(reportBuffer)); // Initialize reportBuffer with zeros

    char wallBuffer[512];
    BNZeroMemory(wallBuffer, sizeof(wallBuffer)); // Initialize wallBuffer with zeros

    strcat(reportBuffer, "Composite Wall Quantities:\n");

    for (const auto& wallGuid : wallGuids) {
        API_Quantities quantities;
        

        API_QuantitiesMask mask;
        BNZeroMemory(&mask, sizeof(mask)); // Initialize mask with zeros
        API_QuantityPar params;
        BNZeroMemory(&params, sizeof(params)); // Initialize params with zeros

        ACAPI_ELEMENT_COMPOSITES_QUANTITY_MASK_CLEAR(mask); // Clear the composites part of the mask
        ACAPI_ELEMENT_COMPOSITES_QUANTITY_MASK_SETFULL(mask); // Set the composites part of the mask to full


    	params.minOpeningSize = EPS;
        GSErrCode err = ACAPI_Element_GetQuantities(wallGuid, &params, &quantities, &mask);
        if (err == NoError) {
            const GS::Array<API_CompositeQuantity>* compositeQuantities = quantities.composites; // Dereference the pointer
            if (compositeQuantities) {
                for (UInt32 i = 0; i < compositeQuantities->GetSize(); ++i) {
                    const API_CompositeQuantity& compositeQuantity = (*compositeQuantities)[i];
                    double const wallVolume = compositeQuantity.volumes;
                    double const wallProjectedArea = compositeQuantity.projectedArea;
                    sprintf(wallBuffer, "Wall GUID: %s, Composite Index: %d, Volume: %.3lf, Projected Area: %.3lf\n",
                        APIGuidToString(wallGuid).ToCStr().Get(), i, wallVolume, wallProjectedArea);
                    strcat(reportBuffer, wallBuffer);
                }
            }
            else {
                strcat(reportBuffer, "No composite quantities available for wall GUID: ");
                strcat(reportBuffer, APIGuidToString(wallGuid).ToCStr().Get());
                strcat(reportBuffer, "\n");
            }
        }
        else {
            strcat(reportBuffer, "Failed to get quantities for wall GUID: ");
            strcat(reportBuffer, APIGuidToString(wallGuid).ToCStr().Get());
            strcat(reportBuffer, "\n");
        }
    }

    ACAPI_WriteReport(reportBuffer, true);
}

 

6 REPLIES 6
Apollos
Booster

Dear @BerndSchwarzenbacher ,

Please do you have any counsel relating to Composite Wall Quantities?

Ralph Wessel
Mentor

After this line:

API_Quantities quantities;

…add:

CompositeQuantityList composites;
quantities.composites = &composites;

ACAPI_Element_GetQuantities won't populate this variable for you - leaving it as nullptr indicates you aren't interested in those quantities.

 

Then instead of this:

const GS::Array<API_CompositeQuantity>* compositeQuantities = quantities.composites;

…just use the existing composites variable.

Ralph Wessel BArch
Software Engineer Speckle Systems

Thank you @Ralph Wessel . I will try out what you advised. Even though I also tried ACAPI_Element_GetMoreQuantities() as described in the Documentation but still not successful. I try out your suggestion I hope all goes. Please, here is the extra code I tried but no result. Please, where do you think I made a mistake?  Please I use Archicad 27 C++ API.

 

void CompositeWallQuantitiesExtraction()
{
    
    API_Element element;
	GS::Array<API_CompositeQuantity> composites;
    GS::Array<API_Quantities> quantities;
    GS::Array<API_Guid>       elemGuids;
	API_QuantitiesMask        mask;
    API_QuantityPar           params;

    ACAPI_Element_GetElemList(API_WallID, &elemGuids, APIFilt_OnActFloor);

    ACAPI_ELEMENT_COMPOSITES_QUANTITY_MASK_CLEAR(mask);
    ACAPI_ELEMENT_COMPOSITES_QUANTITY_MASK_SETFULL(mask);

    quantities.Push(API_Quantities());
    quantities[0].composites = &composites;
    elemGuids.Push(element.header.guid);
    params.minOpeningSize = EPS;

	GSErrCode err = ACAPI_Element_GetMoreQuantities(&elemGuids, &params, &quantities, &mask);
    if (err != NoError) {
        ErrorBeep("ACAPI_Element_GetQuantities", err);
        return;
    }
    WriteReport("%s GUID:%s", ElemID_To_Name(API_WallID).ToCStr(CC_UTF8).Get(),
        APIGuidToString(element.header.guid).ToCStr().Get());

    for (UInt32 i = 0; i < composites.GetSize(); i++) {
        API_Attribute	attr;
        GS::UniString	cFlags;
        GSErrCode		err;

        attr = {};
        attr.header.typeID = API_BuildingMaterialID;
        attr.header.index = composites[i].buildMatIndices;

        err = ACAPI_Attribute_Get(&attr);
        if (err == NoError) {
            if ((composites[i].flags & APISkin_Core) != 0) {
                cFlags.Assign("Core");
            } if ((composites[i].flags & APISkin_Finish) != 0) {
                if (!cFlags.IsEmpty())
                    cFlags.Append("+");
                cFlags.Append("Finish");
            }
        }

        WriteReport("  	composite:   %s[%d]		- volume: %lf		- projected area: %lf	- flag: %s", attr.header.name, composites[i].buildMatIndices, composites[i].volumes, composites[i].projectedArea, static_cast<const char*> (cFlags.ToCStr()));
    }
}

 

Dear @Ralph Wessel , please your recommendations did not achieve the expected task. May be I did not understand and therefore still omitting something. Thank you for being there to help.

Ralph Wessel
Mentor

Try processing the quantities element by element like this:

void CompositeWallQuantitiesExtraction() {
	GS::Array<API_Guid> elemGuids;
	if ((ACAPI_Element_GetElemList(API_WallID, &elemGuids, APIFilt_OnActFloor) != NoError) || elemGuids.IsEmpty())
		return;
	for (auto& guid : elemGuids ) {
		API_QuantityPar params{};
		params.minOpeningSize = eps;
		GS::Array<API_CompositeQuantity> comps;
		API_Quantities quants;
		API_ElementQuantity elemQuants{};
		GS::Array <API_ElemPartQuantity> elemPartQuantities;
		GS::Array <API_ElemPartCompositeQuantity> elemPartComposites;
		quants.elements = &elemQuants;
		quants.composites = &comps;
		quants.elemPartQuantities = &elemPartQuantities;
		quants.elemPartComposites = &elemPartComposites;
		API_QuantitiesMask mask;
		ACAPI_ELEMENT_QUANTITIES_MASK_SETFULL(mask);
		auto error = ACAPI_Element_GetQuantities(guid, &params, &quants, &mask);
		if (error != NoError)
			continue;
		for (auto& comp : comps) {
			//Process composite quants here
		}
	}
Ralph Wessel BArch
Software Engineer Speckle Systems

Thank you @Ralph Wessel . I will try you advice. I will get back to give you an update. Once again thank you.