We will build more complex objects on Allplan software, but first at all a word about Object Oriented Programming (OOP)…
1) Object Oriented Programming
Object Oriented Programming (called OOP) is a way of organizing your code. It allows us to create entities called objects that we can manipulate.
With OOP, an object is an instance of a class, which is a data structure defining the attributes (variables) and methods (functions) associated with that object.
Objects can interact with each other by exchanging messages, allowing for simplified communication and modular code organization.
OOP thus makes it possible to create more flexible, maintainable and scalable programs by encapsulating complexity, facilitating code reuse and promoting modularity.
Python is a programming language perfectly adapted to OOP, now let’s see how to adapt our code…
2) GUI Script
Our work will mainly concern the Python code, so there are no major changes on the .pyp file except for the link with the main script :
<Script>
<Name>APIHub\objects_2D.py</Name>
<Title>Objects2D</Title>
<Version>1.0</Version>
</Script>
my variable for line’s length has been named correctly for the next examples :
<Parameter>
<Name>LineLength</Name>
<Text>Longueur</Text>
<FontFaceCode>4</FontFaceCode>
<Value>1000.0</Value>
<ValueType>Length</ValueType>
</Parameter>
Please note : I have inserted the FontFaceCode field which allows to customize the text (here 4 underlines the text)
You can look at this page for more informations.
Here is the complete source code :
3) Main Script
-
Import modules
Like any Python file, we start by import all the modules necessary for the proper script’s execution :
import NemAll_Python_BaseElements as BaseElements
import NemAll_Python_BasisElements as BasisElements
import NemAll_Python_Geometry as Geometry
import NemAll_Python_IFW_ElementAdapter as ElementAdapter
from BuildingElement import BuildingElement
from CreateElementResult import CreateElementResult
from PythonPartUtil import PythonPartUtil
from HandlePropertiesService import HandlePropertiesService
from HandleDirection import HandleDirection
from HandleParameterData import HandleParameterData
from HandleParameterType import HandleParameterType
from HandleProperties import HandleProperties
-
Check Allplan Version
No change for the basic function check_allplan_version, by default all versions of Allplan are allowed :
def check_allplan_version(build_ele, version):
# Support all versions
return True
-
Use Handles
Ditto for the “listening” of the handles, no change :
def move_handle(build_ele, handle_prop, input_pnt, doc):
HandlePropertiesService.update_property_value(build_ele, handle_prop, input_pnt)
return create_element(build_ele, doc)
-
Create elements
As seen previously, create_element is the 2nd required function for standards PythonParts.
I declare my objects’ list as well as my handles’ list which I also return at the end of the function :
def create_element(build_ele, doc):
model_ele_list = []
handle_list = []…
return CreateElementResult(model_ele_list, handle_list)
Then I declare my variable that will be used to create PythonParts : pyp_util.
I also assign my elements’ list to this function :
pyp_util = PythonPartUtil()
…
# Create pythonpart
model_ele_list = pyp_util.create_pythonpart(build_ele)
As in the previous examples, I get the different parameters from the Allplan’s palette :
# Extract palette parameter values
line_length = build_ele.LineLength.value
# Define common properties
if build_ele.UseGlobalProperties.value:
com_prop = BaseElements.CommonProperties()
com_prop.GetGlobalProperties()
else:
com_prop = build_ele.CommonProperties.value
Please note : previously, the condition was set up for a personalized rendering of our object.
-
Parent Class : Objects2D
This class will be generic to all our 2D objects, so I will use it as a parent class.
I set it the following variables : rendering properties then, I initialize the geometry of my object: self.geo.
class Objects2D:
def __init__(self, object_2d_prop):
self.object_2d_prop = object_2d_prop
self.geo = None
I prepare my function to generate my object’s geometry.
This function will depend on my object (line, rectangle, circle, …), so I leave it empty in my parent class.
def create_geo(self):
pass
Please note : in Python language, functions must have at least one instruction, so I place pass which has a null value.
Next comes creating the render of my object using the common properties (pen, color, etc.) and the object’s geometry :
def add_view(self):
object_2d = BasisElements.ModelElement2D(self.object_2d_prop, self.geo)
return object_2d
Before reviewing the handle’s implementation, here is a reminder on the syntax :
# Create the handles
handle = HandleProperties(“LineLengthHandle”, # handle id
Geometry.Point3D(line_length, 0, 0), # handle point
Geometry.Point3D(), # reference point
[HandleParameterData(“LineLength”, HandleParameterType.POINT_DISTANCE)], # parameter id from the palette
HandleDirection.X_DIR # handle direction)
handle.info_text = “Longueur” # text visible in Allplan
handle_list.append(handle)
We have 6 variables assigned for an unknown number of handles.
So I’m going to create a Handle class for managing these.
class Handle:
def __init__(self, handle_id, handle_point, ref_point, handle_param_data, handle_move_dir, handle_info_text):
self.handle_id = handle_id
self.handle_point = handle_point
self.ref_point = ref_point
self.handle_param_data = handle_param_data
self.handle_move_dir = handle_move_dir
self.handle_info_text = handle_info_text
Please note : we find all of our variables explicitly named.
-
Child Class : Line2D
Directly linked to Object2D, we are going to create a Line2D class which will inherit all its properties, it’s called a child class.
class Line2D(Objects2D):
def __init__(self, object_2d_prop, line_length):
Objects2D.__init__(self, object_2d_prop)
self.line_length = line_length
self.handles_prop = [Handle(« LineLengthHandle »,
Geometry.Point3D(self.line_length, 0, 0),
Geometry.Point3D(),
« LineLength »,
HandleDirection.X_DIR,
« Longueur »
)
]
Please note :
- Line2D takes all the Object2D variables and I complete with the line’s length : line_length.
- we find our 6 variables specific to the line’s handle.
Then I generate my line’s geometry by overwriting my create_geo function :
def create_geo(self):
self.geo = Geometry.Line2D(0, 0, self.line_length, 0)
-
Functions Call
Last step, I go back to my create_element function to call everything I need to create my object (here a line) :
- geometry creation ;
- rendered in plan view ;
- creation of the handles.
As all these steps have been properly prepared in the classes, the syntax is just :
-
Geometry Creation
# Create 2D object
object_2d = Line2D(com_prop, line_length)
object_2d.create_geo()
-
Rendered
# Add object to view
pyp_util.add_pythonpart_view_2d(object_2d.add_view())
-
Creation of the Handles
# Create the handles
for item in object_2d.handles_prop:
handle = HandleProperties(item.handle_id,
item.handle_point,
item.ref_point,
[HandleParameterData(item.handle_param_data, HandleParameterType.POINT_DISTANCE)],
item.handle_move_dir
)
handle.info_text = item.handle_info_text
handle_list.append(handle)
Please note : we currently don’t know how many handles have to be created. Indeed, it will depend on the future object to be created.
So I prepare a loop with for…in for all the handle instances I need and then I add them to the list of my handles.
Here is the complete source code :
In this chapter, we have seen how to prepare our code in OOP with, in particular, parent class and child class management.
In the next article, this organization will make sense with the implementation of other 2D objects to create.
0 Comments