[Вопрос] PythonPart 3D Punkte

Теги:

Hallo,

ich versuche zum Testen einfach nur ein PythonPart zu entwickeln in dem ich einen 3D Punkt mittels Koordinaten erstellen kann.
Dafür habe ich einen Code geschrieben, siehe Anhang.

Das Problem ist hier das Tuple das ich über GetCoords() eingebaut habe.

Hier die Fehlermeldung aus dem Trace:
File "\\NB-LA-032\Nemdaten\Allplan\prj\Masterarbeit.prj\PythonPartsScripts\PythonPartsTraining\Point3D.py", line 36, in create_element
point= AllplanGeometry.Point3D.GetCoords(tuple(build_ele.Punkt1_X.value,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: tuple expected at most 1 argument, got 3

Was mache ich hier falsch?

Вложения (1)

Type: image/png
Загружено 56 раз
Size: 118,15 KiB

Show most helpful answer Hide most helpful answer

Hello,

with your definition of X,Y,Z parameter for the coordinates, the correct implementation would be:

def create_element(build_ele: BuildingElement,
                   doc: AllplanElementAdapter.DocumentAdapter) -> CreateElementResult:

    point = AllplanGeometry.Point3D(x = build_ele.Punkt1_X.value,
                                    y = build_ele.Punkt1_Y.value,
                                    z = build_ele.Punkt1_Z.value)

    point_symbol_properties = AllplanBasisElements.Symbol3DProperties()
    common_props = AllplanSettings.AllplanGlobalSettings.GetCurrentCommonProperties()
    point_symbol = AllplanBasisElements.Symbol3DElement(common_props,point_symbol_properties,point)
    model_ele_list = ModelEleList()
    model_ele_list.append(point_symbol)

    return CreateElementResult(model_ele_list,placement_point= AllplanGeometry.Point3D())

The reason your implementation didn't work is because you tried to use the GetCoords as a point constructor. But this an instance method - you need an object instance (a point) to call it on this instance. Proper usage would be:

x, y, z = point.GetCoords()

Assuming you would have fixed this problem, the next is, that you used the point in the append_geometry_3d. This method does not accept a Point3D as an argument. It would throw a type error.

If you want to create a point in Allplan, you need to create a Terrain Point. In the API , it is represented by Symbol3DElement. So you have to construct an instance of this class. But it need more, than just a point. It also needs common properties (so Allplan knows with which pen/stroke and color to draw the point) and Symbol3DProperties so Allplan knows, which symbol to use to draw the Point (a cross, a point, a circle, etc...).

Hope that helps.

Best,
Bart

Hello,

in order to to create using constructor you need to wrap it like following:
thistuple = tuple(("apple", "banana", "cherry")) # note the double round-brackets

so in your case when passing it to the function GetCoords:
tuple((build_ele.Punkt1_X.value, build_ele.Punkt1_Y.value, build_ele.Punkt1_Z.value))

Hello,

Unfortunately, it did not work and I received the following error message:

Import script: PythonPartsTraining\Point3D
Traceback (most recent call last):
File "C:\ProgramData\Nemetschek\Allplan\2024\Etc\PythonPartsFramework\GeneralScripts\BuildingElementInputService.py", line 55, in create_element
create_ele_result = create_element(input_data.build_ele_list[0],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "\\NB-LA-032\Nemdaten\Allplan\prj\Masterarbeit.prj\PythonPartsScripts\PythonPartsTraining\Point3D.py", line 36, in create_element
point= AllplanGeometry.Point3D.GetCoords(tuple((build_ele.Punkt1_X.value,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Boost.Python.ArgumentError: Python argument types in
None.GetCoords(tuple)
did not match C++ signature:
GetCoords(class Allplan::Geometry:oint3D)

Could you please assist me further?

Best regards,
Veit

Hello,

with your definition of X,Y,Z parameter for the coordinates, the correct implementation would be:

def create_element(build_ele: BuildingElement,
                   doc: AllplanElementAdapter.DocumentAdapter) -> CreateElementResult:

    point = AllplanGeometry.Point3D(x = build_ele.Punkt1_X.value,
                                    y = build_ele.Punkt1_Y.value,
                                    z = build_ele.Punkt1_Z.value)

    point_symbol_properties = AllplanBasisElements.Symbol3DProperties()
    common_props = AllplanSettings.AllplanGlobalSettings.GetCurrentCommonProperties()
    point_symbol = AllplanBasisElements.Symbol3DElement(common_props,point_symbol_properties,point)
    model_ele_list = ModelEleList()
    model_ele_list.append(point_symbol)

    return CreateElementResult(model_ele_list,placement_point= AllplanGeometry.Point3D())

The reason your implementation didn't work is because you tried to use the GetCoords as a point constructor. But this an instance method - you need an object instance (a point) to call it on this instance. Proper usage would be:

x, y, z = point.GetCoords()

Assuming you would have fixed this problem, the next is, that you used the point in the append_geometry_3d. This method does not accept a Point3D as an argument. It would throw a type error.

If you want to create a point in Allplan, you need to create a Terrain Point. In the API , it is represented by Symbol3DElement. So you have to construct an instance of this class. But it need more, than just a point. It also needs common properties (so Allplan knows with which pen/stroke and color to draw the point) and Symbol3DProperties so Allplan knows, which symbol to use to draw the Point (a cross, a point, a circle, etc...).

Hope that helps.

Best,
Bart

In Allplan model, you don't create pure geometries (like point, line or circle). You create Allplan elements, that have geometry: a line element has a line geometry, but a wall also has a line as a geometry (its axis). We recently published an article about Allplan elements, see here.

Best,
Bart

Hello Bart, thank you, that worked. Now I have tried to create a cube that is generated between two points. Unfortunately, the coordinates I enter are not related to the coordinate origin but to the position of the mouse. How can this be changed?

def create_element(build_ele: BuildingElement,
doc: AllplanElementAdapter.DocumentAdapter) -> CreateElementResult:
"""Function for the element creation

Args:
build_ele: the building element.
doc: input document

Returns:
created element result
"""

punkt1 = AllplanGeometry.Point3D()

punkt2 = AllplanGeometry.Point3D()

punkt1.Set(
x= build_ele.Punkt1_X.value,
y= build_ele.Punkt1_Y.value,
z= build_ele.Punkt1_Z.value)

punkt2.Set(
x= build_ele.Punkt2_X.value,
y= build_ele.Punkt2_Y.value,
z= build_ele.Punkt2_Z.value)

cuboid_geo = AllplanGeometry.Polyhedron3D.CreateCuboid(
p1= punkt1,
p2= punkt2)

model_ele_list = ModelEleList()
model_ele_list.append_geometry_3d(cuboid_geo)

return CreateElementResult(elements = model_ele_list)

Hi,
In the CreateElementResult class, there is a parameter defined for setting the placement point, which allows elements to be placed within the global coordinate system by specifying the placement_point parameter.

The example above demonstrates this:

return CreateElementResult(elements=self.model_ele_list, placement_point=AllplanGeo.Point3D(100, 200, 300))

Hi, but for that, I need an Interactor PythonPart, right?

Hi,

you don't necessarily need an interactor for this. Just adapt your code like:

def create_element(build_ele: BuildingElement,
                   doc: AllplanElementAdapter.DocumentAdapter) -> CreateElementResult:
    ...
    return CreateElementResult(elements = model_ele_list, placement_point = AllplanGeo.Point3D())

The additional keyword argument in the CreateElementResult prevents the elements in the model_ele_list to be translated to the position of the mouse. They are basically created in the origin (Point3D() equals to the point (0,0,0)).

The interaction looks the same though: you still have to click in order to place the elements, although they are actually already placed in the origin. You would need an interactor if you would like to change this behavior.

Best,
Bart