Learn to manage BIM workflows and create professional Archicad templates with the BIM Manager Program.

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

Auto-Created sections but Viewpoint not appearing in the Navigator

Spacejoe
Participant

Hi everyone,

I’m trying to automate the creation of cut planes in front of ~200 doors, so that each door has its own section.

I compute each door’s position and then create an API_CutPlaneType element for the cut line and marker. This part works. The marker shows in plan. But no section is added to the Navigator, and the marker is locked so I can’t manually convert it into a real section viewpoint.

Here’s my (messy) code : (Devikit 25)

 

 

 

#include "APIEnvir.h"
#include "ACAPinc.h"
#include <cmath>
#pragma execution_character_set("utf-8")

static void WriteReport(const GS::UniString& message)
{
    ACAPI_WriteReport(message.ToCStr().Get(), false);
}

static GSErrCode ValidateDoors(void)
{
    GSErrCode err = NoError;

    GS::Array<API_Guid> doorGuids;
    err = ACAPI_Element_GetElemList(API_DoorID, &doorGuids);
    if (err != NoError) {
        WriteReport("Erreur lors de la récupération des GUIDs des portes.");
        return err;
    }

    WriteReport("Nombre de portes trouvées : " + GS::UniString::Printf("%d", doorGuids.GetSize()));

    Int32 doorIndex = 0;

    for (const auto& doorGuid : doorGuids) {
        API_Element doorElem{}, wallElem{};
        BNZeroMemory(&doorElem,  sizeof(API_Element));
        BNZeroMemory(&wallElem,  sizeof(API_Element));

        doorElem.header.guid = doorGuid;
        if (ACAPI_Element_Get(&doorElem) != NoError) {
            WriteReport("Erreur lors de la récupération de la porte.");
            continue;
        }
        wallElem.header.guid = doorElem.door.owner;
        if (ACAPI_Element_Get(&wallElem) != NoError) {
            WriteReport("Erreur lors de la récupération du mur parent.");
            continue;
        }

        // Points début/fin du mur
        API_Coord beg = wallElem.wall.begC;
        API_Coord end = wallElem.wall.endC;

        // Vecteur unitaire du mur
        API_Vector wallVec = {end.x - beg.x, end.y - beg.y};
        double vecLength = sqrt(wallVec.x * wallVec.x + wallVec.y * wallVec.y);
        if (vecLength < 1e-9) {
            WriteReport("Longueur mur invalide.");
            continue;
        }
        API_Vector wallUnitVec = {wallVec.x / vecLength, wallVec.y / vecLength};

        // Position porte
        double objLoc = doorElem.door.objLoc;
        API_Coord doorPos = {
            beg.x + wallUnitVec.x * objLoc,
            beg.y + wallUnitVec.y * objLoc
        };

        // Normale (perp. mur)
        API_Vector normVec = {-wallUnitVec.y, wallUnitVec.x};

        // Préparation de la coupe
        API_Element cutPlaneElem{};
        API_ElementMemo cutPlaneMemo{};
        API_SubElement cutPlaneMarker{};
        BNZeroMemory(&cutPlaneElem,    sizeof(API_Element));
        BNZeroMemory(&cutPlaneMemo,    sizeof(API_ElementMemo));
        BNZeroMemory(&cutPlaneMarker,  sizeof(API_SubElement));

        // Type coupe
        cutPlaneElem.header.typeID = API_CutPlaneID;
        // Important : copier l’étage
        cutPlaneElem.header.floorInd = doorElem.header.floorInd;
        cutPlaneMarker.subType       = APISubElement_MainMarker;

        // Récup. des defaults
        err = ACAPI_Element_GetDefaultsExt(&cutPlaneElem, &cutPlaneMemo, 1UL, &cutPlaneMarker);
        if (err != NoError) {
            WriteReport("Impossible de récupérer les defaults pour la coupe.");
            continue;
        }

        // Remplir manuellement quelques champs
        // (parfois nécessaires selon la configuration du template)
        cutPlaneElem.cutPlane.segment.segType = APISect_Normal;
        cutPlaneElem.cutPlane.segment.flags   = 0;
        cutPlaneElem.cutPlane.linkData.showOnHome = true;
        cutPlaneElem.cutPlane.linkData.refFloor   = doorElem.header.floorInd;
        cutPlaneElem.cutPlane.linkData.sourceMarker = true;

        // Nom unique
        GS::UniString coupeName = GS::UniString::Printf("Section_Porte_%d", ++doorIndex);
        GS::UniString coupeId   = GS::UniString::Printf("ID_Porte_%d", doorIndex);

        GS::ucscpy(cutPlaneElem.cutPlane.segment.cutPlName, coupeName.ToUStr());
        GS::ucscpy(cutPlaneElem.cutPlane.segment.cutPlIdStr, coupeId.ToUStr());

        // Points "main coords" (ligne de coupe)
        double halfLength = 0.5;
        API_Coord startCoord, endCoord;
        startCoord.x = doorPos.x - halfLength * normVec.x;
        startCoord.y = doorPos.y - halfLength * normVec.y;
        endCoord.x   = doorPos.x + halfLength * normVec.x;
        endCoord.y   = doorPos.y + halfLength * normVec.y;

        cutPlaneMemo.sectionSegmentMainCoords = (API_Coord*) BMAllocatePtr(2 * sizeof(API_Coord), ALLOCATE_CLEAR, 0);
        if (cutPlaneMemo.sectionSegmentMainCoords == nullptr) {
            WriteReport("Erreur d'allocation memo mainCoords.");
            ACAPI_DisposeElemMemoHdls(&cutPlaneMemo);
            ACAPI_DisposeElemMemoHdls(&cutPlaneMarker.memo);
            continue;
        }
        cutPlaneMemo.sectionSegmentMainCoords[0] = startCoord;
        cutPlaneMemo.sectionSegmentMainCoords[1] = endCoord;

        cutPlaneElem.cutPlane.segment.nMainCoord  = 2;
        cutPlaneElem.cutPlane.segment.nDepthCoord = 2;

        // Rotation manuelle à 90° pour la profondeur
        double dx = endCoord.x - startCoord.x;
        double dy = endCoord.y - startCoord.y;

        // Tourner de 90° autour de startCoord
        API_Coord rotCoord;
        rotCoord.x = startCoord.x - dy;
        rotCoord.y = startCoord.y + dx;

        // Vecteur unitaire
        API_Vector v;
        v.x = rotCoord.x - startCoord.x;
        v.y = rotCoord.y - startCoord.y;
        double len = sqrt(v.x*v.x + v.y*v.y);
        if (len < 1e-9)
            len = 1.0; // éviter division par 0
        v.x /= len;
        v.y /= len;

        // Points de profondeur
        cutPlaneMemo.sectionSegmentDepthCoords = (API_Coord*) BMAllocatePtr(2 * sizeof(API_Coord), ALLOCATE_CLEAR, 0);
        if (cutPlaneMemo.sectionSegmentDepthCoords == nullptr) {
            WriteReport("Erreur alloc memo depthCoords.");
            ACAPI_DisposeElemMemoHdls(&cutPlaneMemo);
            ACAPI_DisposeElemMemoHdls(&cutPlaneMarker.memo);
            continue;
        }
        API_Coord refCoord, deeperCoord;
        refCoord.x = startCoord.x + v.x;
        refCoord.y = startCoord.y + v.y;
        deeperCoord.x = refCoord.x + v.x;
        deeperCoord.y = refCoord.y + v.y;

        cutPlaneMemo.sectionSegmentDepthCoords[0] = refCoord;
        cutPlaneMemo.sectionSegmentDepthCoords[1] = deeperCoord;

        // Création enveloppée dans une Undoable Command :
        err = ACAPI_CallUndoableCommand("Create Section for Door", [&]() -> GSErrCode {
            return ACAPI_Element_CreateExt(&cutPlaneElem, &cutPlaneMemo, 1UL, &cutPlaneMarker);
        });

        if (err == NoError) {
            WriteReport("Coupe créée avec succès : " + coupeName);
        } else {
            WriteReport("Erreur lors de la création de la coupe pour la porte " 
                        + GS::UniString::Printf("%d", doorIndex));
        }

        // Libération
        ACAPI_DisposeElemMemoHdls(&cutPlaneMemo);
        ACAPI_DisposeElemMemoHdls(&cutPlaneMarker.memo);
    }

    WriteReport("Validation des portes terminée.");
    return NoError;
}

static GSErrCode __ACENV_CALL MenuCommandHandler(const API_MenuParams* menuParams)
{
    WriteReport("Menu sélectionné : Validation des portes + création de coupes.");
    return ValidateDoors();
}

GSErrCode __ACDLL_CALL RegisterInterface(void)
{
    return ACAPI_Register_Menu(32500, 32501, MenuCode_UserDef, MenuFlag_Default);
}

API_AddonType __ACDLL_CALL CheckEnvironment(API_EnvirParams* envir)
{
    envir->addOnInfo.description = "Valider les données des portes et créer des coupes";
    return APIAddon_Normal;
}

GSErrCode __ACDLL_CALL Initialize(void)
{
    GSErrCode err = NoError;
    err = ACAPI_Install_MenuHandler(32500, MenuCommandHandler);
    if (err != NoError) {
        WriteReport("Erreur lors de l'installation du gestionnaire de menu.");
    }
    return err;
}

GSErrCode __ACDLL_CALL FreeData(void)
{
    return NoError;
}

 

 

I must be missing something. The line is drawn, but I don’t see any new section in the Navigator. Has anyone successfully done this? Any help or guidance would be greatly appreciated!

Thanks!

0 REPLIES 0

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!