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

bug in program API 21.22 ACAPI_Element_Create

Anonymous
Not applicable
Hello, help me find a solution, the ACAPI_Element_Create function in the Archicad version 21, 22 does not work for the zone surrounded by walls. Finding an error on my own led to the fact that I created a program that can be inserted into a standard “Geometry Test”. Result of experiments up to version 21 everything works, in 21 and 22 everything works except for the zone surrounded by walls, (the zone of lines and the zone with manual construction works) the result of work on the debager in version 21 or 22 crash somewhere in the Archicad module itself. Just in case I will give all the code.

// *****************************************************************************
// Source code for the Geometry Test Add-On
// API Development Kit 21; Mac/Win
//
// Namespaces:		Contact person:
//	-None-
//
// [SG compatible] - Yes
// *****************************************************************************

#include "APIEnvir.h"
#define	_Geometry_Test_TRANSL_


// ---------------------------------- Includes ---------------------------------

//#include	<stdio>
#include	<string>

#include	"ACAPinc.h"					// also includes APIdefs.h
#include	"APICommon.h"
#include	"basicgeometry.h"

// ---------------------------------- Types ------------------------------------


// ---------------------------------- Variables --------------------------------


// ---------------------------------- Prototypes -------------------------------
bool GetZoneElement(API_Guid	 &OutGuid)
{
	API_SelectionInfo 	selectionInfo; // Get selection
	API_Neig			**selNeig; // Get selection
	GSErrCode			err;
	UInt32		nSel;
	UInt32		k = 0;

	err = ACAPI_Selection_Get(&selectionInfo, &selNeig, true);
	BMKillHandle((GSHandle *)&selectionInfo.marquee.coords); 

	if (err != NoError && err != APIERR_NOSEL) {	
		ErrorBeep("ACAPI_Selection_GetInfo", err);  
		BMKillHandle((GSHandle *)& selNeig);
		return false;
	}
	if (selectionInfo.typeID != API_SelEmpty) {		
		nSel = BMGetHandleSize((GSHandle)selNeig) / sizeof(API_Neig);
		for (UInt32 i = 0; i < nSel && err == NoError; i++) {		
			if (!ACAPI_Element_Filter((*selNeig).guid, APIFilt_IsEditable))
				continue;
			OutGuid = (*selNeig).guid; 
			WriteReport("Guid select: %s", static_cast<const char *> (APIGuid2GSGuid(OutGuid).ToUniString().ToCStr()));
			++k;
		}
	} 
	if (k == 0)
		WriteReport("No select %ld", k);
	BMKillHandle((GSHandle *)&selNeig);
	return k > 0 ? true : false;
}

GSErrCode	ModifyZonePos(const API_Guid& guid)
{
	API_Element			element;
	API_ElementMemo		memo;
	GSErrCode			err;

	BNZeroMemory(&element, sizeof(API_Element));
	BNZeroMemory(&memo, sizeof(API_ElementMemo));

	// get actual zone
	element.header.guid = guid;

	err = ACAPI_Element_Get(&element);
	if (err == NoError)
		err = ACAPI_Element_GetMemo(element.header.guid, &memo);
	if (err != NoError)
		return err;
	// delete original zone, before create a new zone, if not want get alert
	API_Elem_Head** heads = (API_Elem_Head**)BMhAllClear(sizeof(API_Elem_Head));
	(*heads)[0].guid = guid; // 0  -1 zones
	ACAPI_Element_Delete(heads, 1);
	BMhKill((GSHandle*)&heads);

	// modify pos and create a new zone
	WriteReport("Create %s:  %s", (ElemID_To_Name (element.header.typeID)).ToCStr().Get(), static_cast<const char *> (APIGuid2GSGuid(guid).ToUniString().ToCStr()));
	err = 	ACAPI_Element_Create (&element, &memo);
	ACAPI_DisposeElemMemoHdls(&memo);
	return err;
}

// =============================================================================
//
// Main functions
//
// =============================================================================


static void		Do_Test (void)
{

	ACAPI_CallUndoableCommand ("Geometry Test -- Create elements",
		[&] () -> GSErrCode {

		GSErrCode err;
		API_Guid  guid;

		GetZoneElement (guid);
		err = ModifyZonePos(guid);
			return err;
		});

	return;
}		/* Do_Test */

// -----------------------------------------------------------------------------
// Entry points to handle Archicad events
//
// -----------------------------------------------------------------------------

GSErrCode __ACENV_CALL	MenuCommandHandler (const API_MenuParams *params)
{
	switch (params->menuItemRef.itemIndex) {
		case 1:		Do_Test ();				break;
	}

	return NoError;
}		// DoCommand


// =============================================================================
//
// Required functions
//
// =============================================================================


//------------------------------------------------------
// Dependency definitions
//------------------------------------------------------
API_AddonType	__ACENV_CALL	CheckEnvironment (API_EnvirParams* envir)
{
	RSGetIndString (&envir->addOnInfo.name, 32000, 1, ACAPI_GetOwnResModule ());
	RSGetIndString (&envir->addOnInfo.description, 32000, 2, ACAPI_GetOwnResModule ());

	return APIAddon_Normal;
}		/* CheckEnvironment */


//------------------------------------------------------
// Interface definitions
//------------------------------------------------------
GSErrCode	__ACENV_CALL	RegisterInterface (void)
{
	ACAPI_Register_Menu (32500, 0, MenuCode_UserDef, MenuFlag_Default);

	return NoError;
}		/* RegisterInterface */


//------------------------------------------------------
// Called when the Add-On has been loaded into memory
// to perform an operation
//------------------------------------------------------
GSErrCode	__ACENV_CALL Initialize	(void)
{
	GSErrCode err = ACAPI_Install_MenuHandler (32500, MenuCommandHandler);
	if (err != NoError)
		DBPrintf ("Geometry_Test:: Initialize() ACAPI_Install_MenuHandler failed\n");

	return err;
}		/* Initialize */


// -----------------------------------------------------------------------------
// FreeData
//		called when the Add-On is going to be unloaded
// -----------------------------------------------------------------------------

GSErrCode __ACENV_CALL	FreeData (void)
{
	return NoError;
}		// FreeData
1 ACCEPTED SOLUTION

Accepted Solutions
Solution
sznagy
Graphisoft Alumni
Graphisoft Alumni
Hi,
I believe the issue is not within ACAPI_Element_Create, but with the CallUndoAbleCommand. The CallUndoAbleCommand scope encapsulates a series of undoable steps, normally database modification operations. In ModifyZonePos you delete the zone element, then you try to create an element with the same guid. This happens within the same database transaction scope, and causes a collision.
To fix the issue, you can use either ACAPI_Element_Change, that way you keep the guid, or in ModifyZonePos you can set the element.header.guid to APINULLGuid, since ACAPI_Element_Create fills the guid field when it's empty.

View solution in original post

2 REPLIES 2
Solution
sznagy
Graphisoft Alumni
Graphisoft Alumni
Hi,
I believe the issue is not within ACAPI_Element_Create, but with the CallUndoAbleCommand. The CallUndoAbleCommand scope encapsulates a series of undoable steps, normally database modification operations. In ModifyZonePos you delete the zone element, then you try to create an element with the same guid. This happens within the same database transaction scope, and causes a collision.
To fix the issue, you can use either ACAPI_Element_Change, that way you keep the guid, or in ModifyZonePos you can set the element.header.guid to APINULLGuid, since ACAPI_Element_Create fills the guid field when it's empty.
Anonymous
Not applicable
Thanks, APINULLGuid really worked.

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!