icon

Das Wissen aller Anwender nutzen

Im Allplan Connect Forum tauschen sich Anwender aus, geben wertvolle Tipps oder beraten sich bei ganz konkreten Aufgabenstellungen − auch international.
Und damit wirklich keine Frage unbeantwortet bleibt, unterstützen die Mitarbeiter des Technischen Supports ebenfalls aktiv das Forum.

Es erwarten Sie:

  • Foren-Vielfalt aus CAD Architektur, CAD Ingenieurbau uvm.
  • Tipps von User für User
  • international: Deutsch, Englisch, Italienisch, Französisch und Tschechisch

Melden Sie sich jetzt an und diskutieren Sie mit!

Zur Registrierung

MakeUnion


Hi there,

I am currently trying to create a script that allows me to unite different geometries from an imported IFC model. Nonetheless, my current script only works properly the first time it is called in Allplan. Let's say I have elements A and B in Position 1, and elements C and D in Position 2. When I select element A + B, the union is performed successfully and placed in Position 1. Once I try to use the same script to unite elements C + D, the union is performed and placed in position 1, instead of position 2. Furthermore, the shape of Element C + D now takes the shape of Element A + B. It seems like the initial position and the initially selected geometries cannot be overwritten once the script is restarted.

I must say that the situation remains the same when I run the script on the elements created within Allplan 2026.

Please let me know what is going on here. See my script below.

"""
Simple Element Union Script

Basic functionality:
- Select multiple elements
- Union their geometries
- Replace with single element
"""

from __future__ import annotations
from typing import TYPE_CHECKING, List

import NemAll_Python_BaseElements as AllplanBaseEle
import NemAll_Python_Utility as AllplanUtil
import NemAll_Python_Geometry as AllplanGeo
import NemAll_Python_IFW_ElementAdapter as AllplanEleAdapter

from BaseScriptObject import BaseScriptObject, BaseScriptObjectData
from CreateElementResult import CreateElementResult
from ScriptObjectInteractors.MultiElementSelectInteractor import (
MultiElementSelectInteractor,
MultiElementSelectInteractorResult,
)
from TypeCollections.ModelEleList import ModelEleList
from PythonPartUtil import PythonPartUtil

if TYPE_CHECKING:
from __BuildingElementStubFiles.InputInteractorBuildingElement import InputInteractorBuildingElement as BuildingElement
else:
from BuildingElement import BuildingElement

def check_allplan_version(_build_ele: BuildingElement, _version: str) -> bool:
return True

def create_script_object(build_ele: BuildingElement, script_object_data: BaseScriptObjectData) -> "UniteElementsScript":
return UniteElementsScript(build_ele, script_object_data)

class UniteElementsScript(BaseScriptObject):
"""Simple script object for uniting elements"""

def __init__(self, build_ele: BuildingElement, script_object_data: BaseScriptObjectData):
super().__init__(script_object_data)
self.build_ele = build_ele
self.multi_select_result = MultiElementSelectInteractorResult()

def start_input(self):
"""Start element selection"""
self.script_object_interactor = MultiElementSelectInteractor(
self.multi_select_result,
prompt_msg="Select elements to unite"
)

def start_next_input(self):
"""Process selected elements"""
self.script_object_interactor = None

selected_adapters = self.multi_select_result.sel_elements
valid_adapters = [adapter for adapter in selected_adapters if adapter.IsValid()]

if len(valid_adapters) < 2:
AllplanUtil.ShowMessageBox("Please select at least 2 elements.", AllplanUtil.MB_OK)
return None

success = self.unite_elements(valid_adapters)

if success:
AllplanUtil.ShowMessageBox("Union created successfully!", AllplanUtil.MB_OK)
else:
AllplanUtil.ShowMessageBox("Error creating union.", AllplanUtil.MB_OK)

return None

def unite_elements(self, adapters: List) -> bool:
"""Unite the selected elements"""

# Get geometries
geometries = []
base_properties = None

for adapter in adapters:
geom = adapter.GetGeometry()
print("MY GEOM",geom)
if geom is not None:
geometries.append(geom)
if base_properties is None:
base_properties = adapter.GetCommonProperties()

if len(geometries) < 2:
return False

print("MY GEOMETRIES", geometries)

# Perform union
united_geometry = self.perform_union(geometries)
if united_geometry is None:
return False

# Create new element
com_prop = base_properties or AllplanBaseEle.CommonProperties()
model_ele_list = ModelEleList(com_prop)
model_ele_list.append_geometry_3d(united_geometry)

# Delete original elements
delete_list = AllplanEleAdapter.BaseElementAdapterList()
for adapter in adapters:
delete_list.append(adapter)

AllplanBaseEle.DeleteElements(self.document, delete_list)

# Create new PythonPart
pyp_util = PythonPartUtil()
pyp_util.add_pythonpart_view_2d3d(model_ele_list)
pythonpart_elements = pyp_util.create_pythonpart(self.build_ele)

# Place in document
placement = AllplanGeo.Matrix3D()
AllplanBaseEle.CreateElements(self.document, placement, pythonpart_elements, [], [])

return True

def perform_union(self, geometries: List):
"""Perform geometry union operation"""
try:
polyhed_list = AllplanGeo.Polyhedron3DList()

for geometry in geometries:
if isinstance(geometry, AllplanGeo.Polyhedron3D):
polyhed_list.append(geometry)
print ("Geometry is Polyhedron 3D")
elif hasattr(geometry, 'ToPolyhedron3D'):
polyhed = geometry.ToPolyhedron3D()
if polyhed.IsValid():
polyhed_list.append(polyhed)

if len(polyhed_list) < 2:
return None

result, united_polyhed = AllplanGeo.MakeUnion(polyhed_list)
print("RESULTS", result)
print("UNITED POLYHED", united_polyhed)

if result and united_polyhed.IsValid():
print("COMPLETED")
return united_polyhed

else:
return None

except Exception:
return None

def execute(self) -> CreateElementResult:
"""Execute the script"""
return CreateElementResult()

Hi,

I wrote an example for the union.

""" Script UnionsScript using Script Object PythonPart

Copyright © 2025 ALLPLAN - Christophe MAIGNAN
"""
from __future__ import annotations

from typing import TYPE_CHECKING, Any

import NemAll_Python_Geometry           as Geometry
import NemAll_Python_BaseElements       as BaseElements
import NemAll_Python_BasisElements      as BasisElements
import NemAll_Python_IFW_ElementAdapter as ElementAdapter

from BaseScriptObject import BaseScriptObject
from BaseScriptObject import BaseScriptObjectData

from ScriptObjectInteractors.MultiElementSelectInteractor import MultiElementSelectInteractor
from ScriptObjectInteractors.MultiElementSelectInteractor import MultiElementSelectInteractorResult

from CreateElementResult          import CreateElementResult
from TypeCollections.ModelEleList import ModelEleList


if TYPE_CHECKING:
    from __BuildingElementStubFiles.UnionScriptBuildingElement import UnionScriptBuildingElement as BuildingElement  # type: ignore
else:
    from BuildingElement import BuildingElement


def check_allplan_version(build_ele: BuildingElement,
                          version:   float) -> bool:
    """Called when the PythonPart is started to check, if the current
    Allplan version is supported.

    Args:
        build_ele: building element with the parameter properties
        version:   current Allplan version

    Returns:
        True if current Allplan version is supported and PythonPart script can be run, False otherwise
    """
    # Support versions >= 2025
    return float(version) >= 2025


def create_script_object(build_ele:          BuildingElement,
                         script_object_data: BaseScriptObjectData) -> BaseScriptObject:
    """ Creation of the script object

    Args:
        build_ele:          building element with the parameter properties
        script_object_data: script object data

    Returns:
        created script object
    """
    return MakeUnionScript(build_ele, script_object_data)


class MakeUnionScript(BaseScriptObject):
    """ Implementation of the class
    """
    def __init__(self,
                 build_ele:          BuildingElement,
                 script_object_data: BaseScriptObjectData):
        """ Initialization

        Args:
            build_ele:          building element with the parameter properties
            script_object_data: script object data
        """
        super().__init__(script_object_data)

        self.build_ele = build_ele
        self.is_modification_mode = self.modification_ele_list.is_modification_element()

        self.multi_select_result = MultiElementSelectInteractorResult()


    def start_input(self) -> None:
        """ Selection of 3D elements
        """
        valid_ele = [ElementAdapter.Volume3D_TypeUUID]
        self.script_object_interactor = MultiElementSelectInteractor(
            interactor_result= self.multi_select_result,
            ele_filter= valid_ele,
            prompt_msg= "Select polyhedrons to unite"
            )


    def start_next_input(self) -> None:
        """ No other input
        """
        self.script_object_interactor = None


    def execute(self) -> CreateElementResult:
        """ Execute the script

        Returns:
            created element result
        """
        elements = self.multi_select_result.sel_elements

        model_ele_list = ModelEleList()
        polyhed_list = Geometry.Polyhedron3DList()

        if len(elements) > 1:
            for element in elements:
                geo = element.GetGeometry()
                if isinstance(geo, Geometry.Polyhedron3D):
                    polyhed_list.append(geo)

            _, united_polyhed = Geometry.MakeUnion(polyhed_list)

            model_ele_list.append_geometry_3d(united_polyhed)

        return CreateElementResult(
            elements= model_ele_list,
            placement_point= Geometry.Point3D()
            )

Be careful to place the code in execute() and set a placement point to the origin.

Best
Christophe

Hi Christophe,

Thank you for your timely reply.

Well this is more or less working now. The remaining issue here is that for some geometries in my model it works and for some others it doesn't. Initially I thought It was because I was try to get geometry from the parent element and it was actually stored and at child element, but the issue seems to be something else.

I am using function _get_model_geometry, and the geometry is actually capture but these two can not be united.

____________________________________________________________
def _get_model_geometry(self, adapter):
# Prefer view-independent model geometry; fall back to view-dependent geometry.
try:
if hasattr(adapter, "GetModelGeometry"):
g = adapter.GetModelGeometry()
if g is not None:
print("PRINT MODEL GEOMETRY",g)
return g
except Exception:
pass

__________________________________________________

When I run "ok, united_world = AllplanGeo.MakeUnion(poly_list)", with the these geometries and it doesn't work, I tried print("ERROR CODE",ok), but nothing is returned.

When I used ShowHierarchy.py script provided by bmarciniec I get the following from these geometries.

============================================================ Object hierarchy ============================================================

Tree | Geometry type
--------------------------------------------------------------------------------|------------------------------
UserDefinedSolid_TypeUUID | Polyhedron3D
└── AttributeContainer_TypeUUID | NoneType

Please let me know what I am missing here.

Looking forward to hearing from you.

Cheers,
Nery

Hi,

Can you try to convert these objects from UserDefinedSolid to Volume3D ?