BIM Coordinator Program (INT) April 22, 2024
Find the next step in your career as a Graphisoft Certified BIM Coordinator!
Archicad C++ API
About Archicad add-on development using the C++ API.
SOLVED!

How to Export Building Elements to CSV or TXT from an Archicad Plugin?

sercet65
Booster

Hello,

I've developed a plugin for Archicad that extracts building elements from a drawing. Currently, my plugin displays the results in a pop-up window using the ACAPI_WriteReport() function. However, I now need to enhance its functionality to export these elements into a CSV or TXT file. I couldn't find any specific API functions in the Archicad API documentation to handle this type of export.

 

Does anyone have experience or suggestions on how to implement this feature? Are there alternative methods or practices within the API that I might have overlooked for exporting data into CSV or TXT formats?

Any guidance or examples would be greatly appreciated.

 

Thank you for your support.

1 ACCEPTED SOLUTION

Accepted Solutions
Solution

I've developed a solution to extract building elements (walls, slabs, doors, etc.) and their properties (including embedded doors, info strings, and bounding boxes) to a text file using the Archicad API in C++.

 

Here's an overview of the process:

 

// Function to report properties of an element
void ReportElementProperties(const API_Guid& elementGuid, API_ElemTypeID elemType, std::ofstream& outFile) {
    char reportStr[1024];
    API_Element element;
    BNZeroMemory(&element, sizeof(API_Element));
    element.header.guid = elementGuid;

    if (ACAPI_Element_Get(&element) == NoError) {
        // Construct a report string based on the element type and its properties
        // The details of this implementation will depend on what information you want to extract
        // For example: sprintf(reportStr, "Element Type: %s, GUID: %s", ...);

        outFile << reportStr << std::endl;
    }
}

 

 

Initialization:

 

// Initialize function
GSErrCode __ACENV_CALL Initialize(void) {
    GSErrCode err = ACAPI_MenuItem_InstallMenuHandler(AddOnMenuID, MenuCommandHandler);

    // Open the output file for writing
    outFile.open("ElementInfo.txt");

    return err;
}

 

// Output file for element information
std::ofstream outFile;

 

Regards...

 

View solution in original post

6 REPLIES 6
Joel Buehler
Enthusiast

this is my csv writer:

i did not test it if it works with the ac27 API since im in the middle of porting my add-on from ac26 to ac27 API.

 

 

void CsvWriter::WriteCSV(IO::Location location, GS::Array<std::wstring> towrite)
{
	GSErrCode		err;
	//UInt32			bufSize;

	IO::File csvFile(location, IO::File::Create);
	err = csvFile.GetStatus();
	if (err != NoError)
	{
		ACAPI_WriteReport("ERROR IN FILE CREATE!", true);
	}


	// Write the buffer into the file
	err = csvFile.Open(IO::File::WriteEmptyMode);
	if (err == NoError)
	{
		const char textHead[] = "EBKPHKlasse;Teilobjekt;Menge;EbkpCode\n";
		GS::USize lenHead = sizeof(textHead);
		csvFile.WriteBin(textHead, lenHead);

		for (std::wstring & wstr : towrite)
		{
			//ACAPI_WriteReport(Auxillary::ToUniString(wstr), false);

			char* outputString = (char*)malloc(100 * sizeof(char));
			outputString = convertWStringToCharPtr2(wstr, outputString);

			GS::USize len = 0;
			while (outputString[len] != '\0')
			{
				len++;
			}

			csvFile.WriteBin(outputString, len);
		}

		csvFile.Close();
	}

	ACAPI_WriteReport(Auxillary::ToUniString(err), false);

}

 

 

you might wanna optimize the case windows vs mac. 

 

" I couldn't find any specific API functions in the Archicad API documentation to handle this type of export."

there are a good examples in the example folder how wo export xml's etc.  🙂 

#include "APIEnvir.h"
#include "ACAPinc.h"   // Also includes APIdefs.h
#include "APICommon.h"
#include "ResourceIds.hpp"
#include "IO.hpp"  // Include the necessary file IO headers

// Forward declaration of functions
static GSErrCode __ACENV_CALL MenuCommandHandler(const API_MenuParams* menuParams);
void ProcessBuildingElements();
void ReportElementProperties(const API_Guid& elementGuid, API_ElemTypeID elementType);

// Unique IDs for the Add-On (change these to actual unique IDs)
static const GSResID AddOnInfoID = ID_MY_ADDON_INFO;
static const Int32 AddOnNameID = 1;
static const Int32 AddOnDescriptionID = 2;

static const short AddOnMenuID = ID_MY_ADDON;
static const Int32 AddOnCommandID = 1;
// Check environment function
API_AddonType __ACDLL_CALL CheckEnvironment(API_EnvirParams* envir)
{
    // Set the Add-On's name and description
    RSGetIndString(&envir->addOnInfo.name, 32000, 1, ACAPI_GetOwnResModule());
    RSGetIndString(&envir->addOnInfo.description, 32000, 2, ACAPI_GetOwnResModule());



    return APIAddon_Preload;
}   // CheckEnvironment

// Register interface function
GSErrCode __ACENV_CALL RegisterInterface(void)
{
    GSErrCode err = ACAPI_MenuItem_RegisterMenu(AddOnMenuID, 0, MenuCode_UserDef, MenuFlag_Default);
    return err;
}


// Initialize function
GSErrCode __ACENV_CALL Initialize(void)
{
    GSErrCode err = ACAPI_MenuItem_InstallMenuHandler(AddOnMenuID, MenuCommandHandler);
    return err;
}

// Free data function
GSErrCode __ACENV_CALL FreeData(void)
{
    return NoError;
}




// Function to process building elements
void ProcessBuildingElements()
{
    GS::Array<std::wstring> elementInfo; // Store the information you want to export to CSV

    API_ElemTypeID elementTypes[] = { API_WallID, API_SlabID };

    for (API_ElemTypeID elementType : elementTypes) {
        GS::Array<API_Guid> elementList;
        if (ACAPI_Element_GetElemList(elementType, &elementList) == NoError && !elementList.IsEmpty()) {
            for (const API_Guid& elementGuid : elementList) {
                // Retrieve element properties and format them as a string
                std::wstring elementInfoStr = GetElementInfoString(elementGuid, elementType);

                // Add the formatted string to the elementInfo array
                elementInfo.Push(elementInfoStr);
            }
        }
    }

    // Specify the location where you want to save the CSV file
    IO::Location csvLocation("C:\\API Development Kit 27.3001\\Server Add on\\YourFile.csv");

    // Call the CsvWriter::WriteCSV function to export the information to the CSV file
    CsvWriter::WriteCSV(csvLocation, elementInfo);
}

// Function to report properties of an element
void ReportElementProperties(const API_Guid& elementGuid, API_ElemTypeID elementType)
{
    char reportStr[1024];

    // Retrieve the localized name of the element type
    GS::UniString elemName;
    if (ACAPI_Element_GetElemTypeName(elementType, elemName) == NoError) {
        sprintf(reportStr, "Element Type: %s, GUID: %s", (const char*)elemName.ToCStr(), APIGuidToString(elementGuid).ToCStr().Get());
    }
    else {
        sprintf(reportStr, "Element Type: %d, GUID: %s", elementType, APIGuidToString(elementGuid).ToCStr().Get());
    }

    // Additional property retrieval can be added here using Archicad's API functions
    ACAPI_WriteReport(reportStr, true);
}

class CsvWriter
{
public:
    static void WriteCSV(IO::Location location, GS::Array<std::wstring> towrite)
    {
        GSErrCode err;
        IO::File csvFile(location, IO::File::Create);
        err = csvFile.GetStatus();
        if (err != NoError)
        {
            ACAPI_WriteReport("ERROR IN FILE CREATE!", true);
        }

        err = csvFile.Open(IO::File::WriteEmptyMode);
        if (err == NoError)
        {
            const char textHead[] = "EBKPHKlasse;Teilobjekt;Menge;EbkpCode\n";
            GS::USize lenHead = sizeof(textHead);
            csvFile.WriteBin(textHead, lenHead);

            for (std::wstring& wstr : towrite)
            {
                char* outputString = (char*)malloc(100 * sizeof(char));
                // Implement the function convertWStringToCharPtr2 to convert wstring to char*
                outputString = convertWStringToCharPtr2(wstr, outputString);

                GS::USize len = 0;
                while (outputString[len] != '\0')
                {
                    len++;
                }

                csvFile.WriteBin(outputString, len);
            }

            csvFile.Close();
        }

        ACAPI_WriteReport(Auxillary::ToUniString(err), false);
    }
    // ... Other CsvWriter class members ...
};
// Menu command handler function
static GSErrCode __ACENV_CALL MenuCommandHandler(const API_MenuParams* menuParams)
{
    if (menuParams->menuItemRef.menuResID == ID_MY_ADDON) {
        if (menuParams->menuItemRef.itemIndex == 1) {
            ProcessBuildingElements();
        }
    }
    return NoError;
}

// Main function or other necessary functions
// ...

@Joel Buehler Thank you very much for the suggestion. I tried to implement the code but received so many errors.I could not address some of these errors.I would appreciate if you could let me now how to fix some of these errors.

Severity	Code	Description	Project	File	Line	Suppression State
Error (active)	E1696	cannot open source file "IO.hpp"	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	5	
Error (active)	E0065	expected a ';'	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	106	
Error (active)	E0020	identifier "convertWStringToCharPtr2" is undefined	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	124	
Error (active)	E0020	identifier "csvFile" is undefined	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	107	
Error (active)	E0020	identifier "GetElementInfoString" is undefined	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	67	
Error (active)	E0276	name followed by '::' must be a class or namespace name	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	113	
Error (active)	E0276	name followed by '::' must be a class or namespace name	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	138	
Error (active)	E0135	namespace "IO" has no member "File"	Extraction_V2.apx - x64-Debug	C:\API Development Kit 27.3001\Server Add on\Extraction_V2\Src\Extraction_V2.cpp	106	
MudratDetector
Enthusiast

You might look into something called LibXL.

We have used it with great success.

https://www.libxl.com/home.html 

 

Best of luck,

Chris

 

Disclaimer:

And I am in no way associated with the creation or distribution of this utility, only a happy user.

 

Chris Gilmer
Intel i9-12950HX CPU @ 2.30GHz, 16 cores
NVIDIA GeForce RTX 3080
48.0 GB RAM
Windows 10 Pro 64-bit
Solution

I've developed a solution to extract building elements (walls, slabs, doors, etc.) and their properties (including embedded doors, info strings, and bounding boxes) to a text file using the Archicad API in C++.

 

Here's an overview of the process:

 

// Function to report properties of an element
void ReportElementProperties(const API_Guid& elementGuid, API_ElemTypeID elemType, std::ofstream& outFile) {
    char reportStr[1024];
    API_Element element;
    BNZeroMemory(&element, sizeof(API_Element));
    element.header.guid = elementGuid;

    if (ACAPI_Element_Get(&element) == NoError) {
        // Construct a report string based on the element type and its properties
        // The details of this implementation will depend on what information you want to extract
        // For example: sprintf(reportStr, "Element Type: %s, GUID: %s", ...);

        outFile << reportStr << std::endl;
    }
}

 

 

Initialization:

 

// Initialize function
GSErrCode __ACENV_CALL Initialize(void) {
    GSErrCode err = ACAPI_MenuItem_InstallMenuHandler(AddOnMenuID, MenuCommandHandler);

    // Open the output file for writing
    outFile.open("ElementInfo.txt");

    return err;
}

 

// Output file for element information
std::ofstream outFile;

 

Regards...

 

poco2013
Mentor

Your message is not clear as to what information you are trying to export but I suspect that you "are trying to reinvent the wheel".

Specificity what elements do you need info from? Not all elements have much info  available, i.e. MEP elements (YET)? Do want to see materials, GUID, custom properties or certain "built-in" properties? if so, which ones" And do you want to export to a CSV file, Excel SS, or a dialog or all or just selectable?

 

This is all just a basic Python script, although some certain info may also require a ADD In as in getting the parameters from GDL objects. The good part is that this completely free with Python which has those capabilities built-in, including access (read/write) to CSV text files, Excel files and user dialogs. The plus side is that you , most likely, will not have to recompile your addon, or maybe even need a addon, with every release of Archicad. Most scripts today work across versions from 25 onward. If you care to give some specific details, I could provide more guidance and/or perhaps a preliminary demo script and video.

Gerry

Windows 11 - Visual Studio 2022; ArchiCAD 27

@poco2013 Thank you very much for the suggestion.

 

I'm currently engaged in a project involving the ArchiCAD C++ API and have come across a specific challenge related to dimension elements. My task involves determining which architectural elements (such as walls, slabs, etc.) are associated with a given dimension element.

 

While I have successfully managed to extract basic properties of dimensions and write this information to a text file, my current hurdle is in understanding how to identify the building elements these dimensions are attached. I'm utilizing the API_DimensionType structure for accessing properties of the dimensions, but the process of finding links or references to the actual elements they're attached to isn't clear to me.

 

Any advice or suggestions on this aspect within the ArchiCAD C++ API would be greatly appreciated.

 

Thank you for your help!

Learn and get certified!