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

Change Wall parameters through ACAPI_Element_Change

Anonymous
Not applicable
Hi All,

I would like to change the volume (height,width,length), and the filler material of a wall. How is it possible through ACAPI_Element_Change, currently I have the API_Guid both GSGuid of an element?

Please also attend some example code to start with if possible.

Thank you: Andor
8 REPLIES 8
Anonymous
Not applicable
This is my current code (almost the same as in the documentation), but it does not work. Any help is appreciated.

void changeWall(const API_Guid* ArchAPIGUID){
	API_Element         element, mask;
	API_Coord           c1, c2;
	GSErrCode           err = NoError;
	double				height;
	double				width;

	BNZeroMemory (&element, sizeof (API_Element));
	API_Guid currAPIGuid = *ArchAPIGUID;
	element.header.guid = currAPIGuid;
	err = ACAPI_Element_Get (&element);
	if (err != NoError)
		DBPrintf("hiba");

	c1 = element.wall.begC;
	c2 = element.wall.endC;
	height = element.wall.height;
	width = element.wall.thickness;
	DBPrintf("width XXXXXX %d", width);

	if (err == NoError) {
		ACAPI_ELEMENT_MASK_CLEAR (mask);
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, begC);
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, endC);
		//ACAPI_ELEMENT_MASK_SET (mask, API_WallType, height);
		//ACAPI_ELEMENT_MASK_SET (mask, API_WallType, thickness);

		element.wall.begC = c2;
		element.wall.endC = c1;
		//element.wall.height = 100*height;
		//element.wall.thickness = width;

		err = ACAPI_Element_Change (&element, &mask, NULL, 0, true);
		if (err == NoError) {
			DBPrintf("Fal megvan");
			err = ACAPI_Element_Get (&element);
			width = element.wall.thickness;
			DBPrintf("width YYYYYY %d", width);
		}

	}


}

//getelements

void getElements (void) 
{ 
	API_Quantity      quantity, mask; 
	API_Quantities    quantities; 
	API_QuantityPar   params; 
	GSErrCode         err; 



	GS::Array<API_Guid> elemList;
	ACAPI_Element_GetElemList(API_WallID,&elemList);

	ACAPI_ELEMENT_QUANTITY_MASK_CLEAR (mask); 
	ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, surface1); 
	ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, surface2); 
	ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, volume);
	quantities.quantityData = &quantity; 
	params.minOpeningSize = EPS; 

	DBPrintf ("number of walls = %ld,", elemList.GetSize ());

	short visible = 0;
	short onStory = 0;
	short inView = 0;
	for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate (); it != NULL; ++it) {

		if (ACAPI_Element_Filter (*it, APIFilt_OnVisLayer))
			++visible;
		if (ACAPI_Element_Filter (*it, APIFilt_OnActFloor))
			++onStory;
		if (ACAPI_Element_Filter (*it, APIFilt_InCroppedView))
			++inView;


		//get quantities
		err = ACAPI_Element_GetQuantities (*it, &params, &quantities, &mask);
		if (err == NoError) { 
			DBPrintf ("surface1: %.2lf  surface2: %.2lf  volume: %.2lf", quantity.wall.surface1, quantity.wall.surface2, quantity.wall.volume); 	   
		}
		changeWall(&it.GetCurrent());
	}
	//DBPrintf ("%d visible, %d on the view\'s floor, %d in the cropped view\n", visible, onStory, inView);
} 
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
Szia Andor,

Your code is absolutely perfect. It works good, it switches the beginning and end coordinates of the walls.

If you check in ArchiCAD on the Wall Settings dialog you can't modify the thickness of the walls in the user interface also. That is because those wall's type is APIWtyp_Normal.
Check API_WallType, there are thickness (at the beginning point) and thickness1 (at the end point) and type (the geometry of the wall) attributes.
If the type is APIWtyp_Normal, it means that the wall has parallel sides, so you can't change thickness because the sides won't be parallel after the modification.
So if you want to change thickness you must change the type too.
void changeWall (const API_Guid* ArchAPIGUID) 
{ 
	API_Element			element, mask; 
	API_Coord			c1, c2; 
	GSErrCode			err = NoError; 
	double				height; 
	double				width; 
 
	BNZeroMemory (&element, sizeof (API_Element)); 
	API_Guid currAPIGuid = *ArchAPIGUID; 
	element.header.guid = currAPIGuid; 
	err = ACAPI_Element_Get (&element); 
	if (err != NoError) 
		DBPrintf("hiba"); 
 
	c1 = element.wall.begC; 
	c2 = element.wall.endC; 
	height = element.wall.height; 
	width = element.wall.thickness; 
	DBPrintf("width XXXXXX %d", width); 
 
	if (err == NoError) { 
		ACAPI_ELEMENT_MASK_CLEAR (mask); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, begC); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, endC); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, height); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, thickness); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, thickness1); 
		ACAPI_ELEMENT_MASK_SET (mask, API_WallType, type); 
 
		element.wall.begC = c2; 
		element.wall.endC = c1; 
		element.wall.height = height*2; 
		element.wall.thickness = width*2; 
		element.wall.thickness1 = width*2; 
		element.wall.type = APIWtyp_Trapez; 
 
		err = ACAPI_Element_Change (&element, &mask, NULL, 0, true); 
		if (err == NoError) { 
			DBPrintf("Fal megvan"); 
			err = ACAPI_Element_Get (&element); 
			width = element.wall.thickness; 
			DBPrintf("width YYYYYY %d", width); 
		} 
	} 
}


Best Regards,
Tibor
Anonymous
Not applicable
Szia!

Thank you for the code, but it still does not work. It gives me the error: APIERR_REFUSEDCMD.

If I try to modify the database with the following code gives the error: APIERR_BADDATABASE:


		err = ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &element.detail.databaseID);
		if(err == NoError){
		}
		else {
			DBPrintf("%d",(Int32)err);
		}
What could be the problem?
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
Szia Andor,

Your code worked good for me, so the context of the API function call could be wrong.
Which API function call gives you APIERR_REFUSEDCMD error code?

Can you describe me the situation when you call your AddOn function? (view type, placed elements, maybe a screenshot could help also)

Regards,
Tibor
Ralph Wessel
Mentor
AndorSzamos wrote:
It gives me the error: APIERR_REFUSEDCMD.
Are you bounding this operation with ACAPI_OpenUndoableSession and ACAPI_CloseUndoableSession?
Ralph Wessel BArch
Software Engineer Speckle Systems
Anonymous
Not applicable
Hi,

Actually I have a very simple code. I just try to draw a wall in ArchiCAD, and then modify the parameters of it.

#include "APIEnvir.h" 

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

#include   <math.h> 

#include   <string.h> 


#include   "ACAPinc.h"               // also includes APIdefs.h 
//#include   "Model.hpp" 
#include   "APICommon.h" 

#include   "DGModule.hpp" 

#include   "DG.h" 



#include   "MDIDs_APICD.h" 


//non-AC 
#include <iostream> 
#include <fstream> 
#include <string> 


//program includes 



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

#define EvaluateButton          1 
#define CancelButton          2 
#define   UserArea             3 
#define Consumption1          5 
#define Consumption2          7 



using namespace std; 



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


// ---------------------------------- Prototypes ------------------------------- 




// ============================================================================= 
// 
// Dialog control functions 
// 
// ============================================================================= 


void doEvaluation(void){ 
   DBPrintf("bla"); 
} 



// ----------------------------------------------------------------------------- 
// Main dialog callback function 
// ----------------------------------------------------------------------------- 

static short DGCALLBACK   DialogMessageHandler (short message, 
   short dialId, 
   short itemId, 
   DGUserData userData, 
   DGMessageData msgData) 
{ 
   UNUSED_PARAMETER (msgData); 
   UNUSED_PARAMETER (dialId); 
   UNUSED_PARAMETER (userData); 
   //INNEN FOLYTASD A GOMBOKRA A REAGALAST 

   switch (message) { 
   case DG_MSG_CLOSE: 
      break; 
   case DG_MSG_CLICK: 
      switch (itemId) { 
         //case 2: // Close button 
      case EvaluateButton: 
         doEvaluation(); 
         break; 
      case CancelButton: 
         return(1); 
         break; 
      default: 
         return(1); 
         break; 
      } 
   default: 
      break; 
   } 
   return 0; 
}       // DialogMessageHandler 





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

#ifdef __APPLE__ 
#pragma mark - 
#endif 

// ----------------------------------------------------------------------------- 
// Call the list data dialog 
// ----------------------------------------------------------------------------- 


//------------------------------------------------------------------------------ 
// Get Element properties 2 
//------------------------------------------------------------------------------ 




//change properties 

void changeWall (const API_Guid* ArchAPIGUID) 
{ 
   API_Element         element, mask; 
   API_Coord         c1, c2; 
   GSErrCode         err = NoError; 
   double            height; 
   double            width; 

   BNZeroMemory (&element, sizeof (API_Element)); 
   API_Guid currAPIGuid = *ArchAPIGUID; 
   element.header.guid = currAPIGuid; 
   err = ACAPI_Element_Get (&element); 
   if (err != NoError) 
      DBPrintf("hiba"); 

   c1 = element.wall.begC; 
   c2 = element.wall.endC; 
   height = element.wall.height; 
   width = element.wall.thickness; 
   DBPrintf("width XXXXXX %d", width); 

   if (err == NoError) { 
      //we need to change the database we are working with to the current database of the current element 
      err = ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &element.detail.databaseID); 
      if(err == NoError){ 
      } 
      else { 
         DBPrintf("%d",(Int32)err); 
      } 

      ACAPI_ELEMENT_MASK_CLEAR (mask); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, begC); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, endC); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, height); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, thickness); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, thickness1); 
      ACAPI_ELEMENT_MASK_SET (mask, API_WallType, type); 

      element.wall.begC = c2; 
      element.wall.endC = c1; 
      element.wall.height = height*2; 
      element.wall.thickness = width*2; 
      element.wall.thickness1 = width*2; 
      element.wall.type = APIWtyp_Trapez; 

      err = ACAPI_Element_Change (&element, &mask, NULL, 0, true); 
      if (err == NoError) { 
         DBPrintf("Fal megvan"); 
      } 
      else{ 
         DBPrintf("%d",(Int32)err); 
      } 
      err = ACAPI_Element_Get (&element); 
      width = element.wall.thickness; 
      DBPrintf("width YYYYYY %d", width); 
   } 
} 


void getElements (void) 
{ 
   API_Quantity      quantity, mask; 
   API_Quantities    quantities; 
   API_QuantityPar   params; 
   GSErrCode         err; 



   GS::Array<API_Guid> elemList; 
   ACAPI_Element_GetElemList(API_WallID,&elemList); 

   ACAPI_ELEMENT_QUANTITY_MASK_CLEAR (mask); 
   ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, surface1); 
   ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, surface2); 
   ACAPI_ELEMENT_QUANTITY_MASK_SET (mask, wall, volume); 
   quantities.quantityData = &quantity; 
   params.minOpeningSize = EPS; 

   DBPrintf ("number of walls = %ld,", elemList.GetSize ()); 

   short visible = 0; 
   short onStory = 0; 
   short inView = 0; 
   for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate (); it != NULL; ++it) { 

      if (ACAPI_Element_Filter (*it, APIFilt_OnVisLayer)) 
         ++visible; 
      if (ACAPI_Element_Filter (*it, APIFilt_OnActFloor)) 
         ++onStory; 
      if (ACAPI_Element_Filter (*it, APIFilt_InCroppedView)) 
         ++inView; 


      //get quantities 
      err = ACAPI_Element_GetQuantities (*it, &params, &quantities, &mask); 
      if (err == NoError) { 
         DBPrintf ("surface1: %.2lf  surface2: %.2lf  volume: %.2lf", quantity.wall.surface1, quantity.wall.surface2, quantity.wall.volume);        
      } 
      changeWall(&it.GetCurrent()); 
   } 
   //DBPrintf ("%d visible, %d on the view\'s floor, %d in the cropped view\n", visible, onStory, inView); 
} 

static void   Evaluate (void) 
{ 
   API_ListData   param; 
   GSResModule    saveResModule; 

   BNZeroMemory (&param, sizeof (param)); 
   param.header.setIndex = 1; 
   param.header.typeID   = API_ComponentID; 

   saveResModule = ACAPI_UseOwnResModule (); 
   DGModalDialog (32510, DialogMessageHandler, (DGUserData) (&param)); 
   ACAPI_ResetResModule (saveResModule); 

   getElements(); 
   return; 
}      //Evaluate 


// ----------------------------------------------------------------------------- 
// MenuCommandHandler 
//      called to perform the user-asked command 
// ----------------------------------------------------------------------------- 

GSErrCode __ACENV_CALL   MenuCommandHandler (const API_MenuParams *params) 
{ 
   UNUSED_PARAMETER (params); 

   Evaluate (); 

   return NoError; 
}   // DoCommand 


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


//------------------------------------------------------ 
// Dependency definitions 
//------------------------------------------------------ 
API_AddonType   __ACENV_CALL   CheckEnvironment (API_EnvirParams* envir) 
{ 
   if (envir->serverInfo.serverApplication != APIAppl_ArchiCADID) 
      return APIAddon_DontRegister; 

   GSResModule saveResModule = ACAPI_UseOwnResModule (); 
   ACAPI_Resource_GetLocStr (envir->addOnInfo.name, 32000, 1); 
   ACAPI_Resource_GetLocStr (envir->addOnInfo.description, 32000, 2); 
   ACAPI_ResetResModule (saveResModule); 

   return APIAddon_Normal; 
}      /* CheckEnvironment */ 


//------------------------------------------------------ 
// Interface definitions 
//------------------------------------------------------ 
GSErrCode   __ACENV_CALL   RegisterInterface (void) 
{ 
   ACAPI_Register_Menu (32500, 0, MenuCode_DocExtras, 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 ("Energy-Budget Evaluator:: 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; 
} 

Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
Szia Andor,

Ralph pointed out your mistake.
If you want to change something through the API, then before the modification you must open an undoable session (ACAPI_OpenUndoableSession) and after you made the changes close the undoable session (ACAPI_CloseUndoableSession). This will guarantee that the user can click to the undo button and revert all the changes the Add-On made.

So put an ACAPI_OpenUndoableSession call in the beginning of the MenuCommandHandler function and an ACAPI_CloseUndoableSession to the end:
GSErrCode __ACENV_CALL	MenuCommandHandler (const API_MenuParams *menuParams) 
{ 
	UNUSED_PARAMETER (params); 
 
	GSErrCode err = ACAPI_OpenUndoableSession ("Undo changes"); 
	if (err != NoError) { 
		DBPrintf ("MenuCommandHandler cannot open undoable session: %d\n", err); 
		return err; 
	} 
 
	Evaluate (); 
 
	ACAPI_CloseUndoableSession (); 
 
	return NoError; 
}	// DoCommand


Regards,
Tibor
Anonymous
Not applicable
Hi,

Thanks both of you, it solved the problem.

Regards,
Andor