Skip to content

Handles examples

All the examples shown here are included into one PythonPart Handles which is available here:

  • ...\Etc\PythonPartsExampleScripts\BasisExamples\General\Handles.py
  • ...\Etc\Examples\PythonParts\BasisExamples\General\Handles.pyp

Dimension handle

Let's say we have a simple geometry (a cube), and we want to let the user control a single dimension of it (the height) with a handle. The implementation can look like this:

<Parameter>
    <Name>CubeHeight</Name>
        <ValueType>Length</ValueType>
</Parameter>
handle_parameter_data = HandleParameterData("CubeHeight", HandleParameterType.Z_DISTANCE) #(1)!

handle_height = HandleProperties("HeightHandle",
                                AllplanGeo.Point3D(0,0, build_ele.CubeHeight.value),
                                AllplanGeo.Point3D(),
                                [handle_parameter_data], #(2)!
                                HandleDirection.Z_DIR) #(3)!

handle_list.append(handle_height)
  1. The handle is connected here to the parameter CubeHeight with the Z_DISTANCE recalculation method, meaning that after every handle modification a distance vector between reference point and handle point is calculated and only the Z component is being put back a value to the parameter CubeHeigth.
  2. Here we could let one handle affect several parameters in the property palette, each in a different way.
  3. The handle should move only in local Z-direction of our PythonPart.

Coordinate handle

Let's say, we want to let the user control the ground view dimensions (length and width) of the PythonPart with a single handle.

<Parameter>
    <Name>CubeLength</Name>
    ...
    <ValueType>Length</ValueType>
</Parameter>

<Parameter>
    <Name>CubeWidth</Name>
    ...
    <ValueType>Length</ValueType>
</Parameter>
handle_parameter_data_list = [HandleParameterData("CubeLength", 
                                                    HandleParameterType.X_DISTANCE,
                                                    False), #(3)!
                                HandleParameterData("CubeWidth",
                                                    HandleParameterType.Y_DISTANCE,
                                                    False)] #(1)!

handle_length_width =  HandleProperties("LengthWidthHandle",
                                        AllplanGeo.Point3D(build_ele.CubeLength.value,
                                                            build_ele.CubeWidth.value,
                                                            0),
                                        AllplanGeo.Point3D(),
                                        handle_parameter_data_list,
                                        HandleDirection.XY_DIR)

handle_length_width.info_text = "Ground view dimensions" #(2)!
  1. Two parameters should be assigned to this handle therefore a list is defined here.
  2. The string in the optional parameter info_text will be displayed ever time the user hovers the handle with the mouse.
  3. Unlike in the first example, the input field in the model view is hidden.

Button handle

Let's say we want the handle to perform some action (mirroring the object). We can place a button in the palette or define a button handle, visible directly in the model view to do that.

<Parameter><!--(1)!-->
    <Name>MirrorCuboid</Name>
    <Value>False</Value>
    <ValueType>CheckBox</ValueType>
</Parameter>
  1. To be able to temporarily save the mirrored-status of the PythonPart a hidden parameter must be defined. In an Interactor PythonPart we could save this information ex. in a property of the interactor class.
mirror_handle = HandleProperties("MirrorCuboid", 
                                    point5,
                                    AllplanGeo.Point3D(),
                                    [], #(1)!
                                    HandleDirection.CLICK) #(2)!

mirror_handle.handle_type  = AllplanIFW.ElementHandleType.HANDLE_ARROW
mirror_handle.info_text    = "Mirror the cuboid"
mirror_handle.handle_angle = rot_angle #(3)!

handle_list.append(mirror_handle)
  1. Note that no parameter is assigned to the handle. The handle processing is done entirely in move_handle() function by the assigned handle ID MirrorCuboid.
  2. By assigning the handle direction CLICK the handle cannot be moved. The move_handle() is called, when the handle is clicked.
  3. The handle is rotated in XY plane to align with the rotation of the object.
def move_handle(build_ele,
                handle_prop: HandleProperties,
                input_pnt: AllplanGeo.Point3D,
                doc: AllplanEleAdapter.DocumentAdapter):

if handle_prop.handle_id == "MirrorCuboid": #(1)!
    build_ele.MirrorCuboid.value = not build_ele.MirrorCuboid.value #(2)!

return create_element(build_ele, doc)
  1. The name of the handle is stored in the property handle_id
  2. We use an invisible parameter to temporarily save the mirrored status. The value of the parameter is changed here every time the handle is clicked.

List parameter

Let's say we have a parameter defined as a python list containing Point3D and we want to define a handle for each of these points.

<Parameter>
    <Name>PolyPoints</Name>
        <Value>[Point3D(500,-2000,0);
            Point3D(1000,-4000,0);
            Point3D(5000,-5000,0);
            Point3D(5000,-1000,0)]</Value>
    <ValueType>Point3D</ValueType>
</Parameter>
handle_list = []

for index, pnt in enumerate(build_ele.PolyPoints.value): #(2)!

    handle_param_data = HandleParameterData("PolyPoints",
                                            HandleParameterType.POINT,
                                            False, #(4)!
                                            list_index = index) #(1)!

    handle_list.append(HandleProperties("PolyPoints",
                                        pnt,
                                        AllplanGeo.Point3D(),
                                        [handle_param_data],
                                        HandleDirection.XYZ_DIR))

    handle_list[-1].info_text = "Point " + str(index + 1) #(3)!
  1. As the parameter is defined as list, this argument is now required. The parameter PolyPoints is a one-dimensional list, therefore the list_index is an integer. In case of a two-dimensional list, a list of two integer values must be provided: [index_row, index_column].
  2. As separate handle must be generated for each point, implementation in a loop is the best solution.
  3. Here we change the info text for the appended handle.
  4. We don't want the input fields to be shown for these handles.

Value decrement / increment

Let's say we do not want to allow the user to set a value of a certain parameter (ex. wall thickness) freely, but only increment or decrement it by 100 mm instead.

<Parameter>
    <Name>Thickness</Name>
    <Text>Thickness</Text>
    <Value>1000.</Value>
    <ValueType>Length</ValueType>
    <MinValue>0</MinValue>
    <MaxValue>10000</MaxValue>
    <IntervalValue>100</IntervalValue><!--(1)!-->
</Parameter>
  1. We do want the thickness to increment in 100 mm steps, therefore we also need to constrain the parameter in the property palette separately. Otherwise, the user could change the thickness freely using the palette.
#---------- incrementation handle

increm_handle_param_data = [HandleParameterData("Thickness", #(1)!
                                                HandleParameterType.INCREMENT_BUTTON,
                                                in_decrement_value = 100.)]

increment_handle = HandleProperties(handle_id=          "IncrementHandle",
                                    handle_point=       point2 + AllplanGeo.Point3D(200, 100, 0),
                                    ref_point=          AllplanGeo.Point3D(), #(2)!
                                    handle_param_data=  increm_handle_param_data,
                                    handle_move_dir=    HandleDirection.CLICK #(3)!
                                    info_text=          "Increment thickness by 0.1m") 

handle_list.append(increment_handle)


#---------- decrementation handle

decrem_handle_param_data = [HandleParameterData("Thickness", #(4)!
                                                HandleParameterType.DECREMENT_BUTTON,
                                                in_decrement_value = 100.)]

decrement_handle = HandleProperties(handle_id=          "DecrementHandle",
                                    handle_point=       point2 + AllplanGeo.Point3D(200, -100, 0), 
                                    ref_point=          AllplanGeo.Point3D(),
                                    handle_param_data=  decrem_handle_param_data,
                                    handle_move_dir=    HandleDirection.CLICK,
                                    info_text=          "Decrement thickness by 0.1m")

decrement_handle.handle_angle = AllplanGeo.Angle(math.pi)

handle_list.append(decrement_handle)
  1. Defining the handle parameter type this way implies adding the value of 100 mm to the parameter thickness.
  2. In case of a button handle, this argument is not relevant and can be set to (0,0,0).
  3. The increment button can be clicked, but not moved. This behaviour is defined here.
  4. Decrementing a value is a different recaltulation behaviour therefore a separate handle must be defined for that and it must be assigned to the same thickness parameter.

Rotation handle

Let's say we want to allow the user to input an angle (ex. to rotate a geometry) using handle. In this case we need to implement a handle like this:

    <Parameter>
        <Name>RotAngleZ</Name>
        <Text>Z rotation</Text>
        <Value>0</Value>
        <ValueType>Angle</ValueType>
    </Parameter>
rot_handle_param_data = HandleParameterData("RotAngleZ", 
                                            HandleParameterType.ANGLE) #(1)!

handle_z_rot = HandleProperties(handle_id=          "Z_Rotation",
                                handle_point=       poly_points[1], #(2)!
                                ref_point=          poly_points[1], #(3)!
                                handle_param_data=  [rot_handle_param_data],
                                handle_move_dir=    HandleDirection.ANGLE, #(4)!
                                abs_value=          True,
                                info_text=          "Z rotation handle")

handle_z_rot.info_text = "Z rotation handle"

handle_list.append(handle_z_rot)
  1. This option implies, that an angle value is being calculated between handle_point and ref_point
  2. The handle will be drawn in this point.
  3. Reference point for the value calculation. The value of the angle will be calculated between the local X-axis with the origin in the ref_point, and the line going through the ref_point and the handle_point. This implies a rotation around the local Z-Axis. By default, the directions of the local axes are the same as the global one and can be changed by providing an optional argument angle_placement, ex. like this:

    angle_placement = AllplanGeo.AxisPlacement3D(AllplanGeo.Point3D(),
                                                    AllplanGeo.Vector3D(1000, 0, 0),
                                                    AllplanGeo.Vector3D(0, -1000, 0))
    
  4. A handle can be moved in any direction, just like with XYZ_DIR, but an arc with arrow will be drawn when hovering with the mouse over the handle to indicate a rotation.