.. _services_Objectsservice: .. role:: python(code) :language: python Objects Service =============== The WindPro ObjectsService provides access to functionality related to objects in windPRO. The ObjectService allows for manipulating general properties of objects as well as object layers. Each object has an object type in windPRO scripting that allows to e.g. generate an object of this type or get a list of all objects of that type present in the project. Some objects have additional scripting services that allow access to more specialized functionality and properties of these objects. The table below gives a list of all object types in windPRO scripting and a link to the dedicated service if available. .. list-table:: Objects available in scripting :widths: 25 75 75 :header-rows: 1 * - Object type - Description - Scripting Service * - AreaObj - Area object - :ref:`ObjAreaService ` * - BusBar - - not available * - Camera - - not available * - CtrlPoint - Control point - :ref:`ObjCtrlPointService ` * - EGrid - EGrid object - not available * - ELoad - - not available * - ExtGrid - - not available * - ExistWTG - Existing ETG - :ref:`ObjWtgService ` * - HCData - Line data - :ref:`ObjLineService ` * - HCGridObj - Height contour grid - :ref:`ObjElevationGridService ` * - MeteoObjectData - Meteo object - :ref:`ObjMeteoService ` * - NewWTG - New WTG - :ref:`ObjWtgService ` * - NSA - Noise Receptor or area - :ref:`ObjNSAService ` * - Obj3DData - - not available * - Obstacle - Obstacle object - :ref:`ObjObstacleService ` * - Polygons - - not available * - Profile - - not available * - RadarObject - Radar - :ref:`ObjRadarService ` * - RoadObject - Road object - not available * - ResultLayerObject - Result Layers - not available * - Ruler - Ruler for measuring - :ref:`ObjRulerService ` * - Shadow - Shadow receptor - :ref:`ObjShadowService ` * - SolarPvObject - Solar PV object - not available * - Shape - Shape - not available * - SiteCenter - Site center - not available * - SiteData - Site data object - :ref:`ObjSiteDataService ` * - Transformer - - not available * - Unknown - Not known type - not available * - UsrTextData - Text box - :ref:`ObjTextService ` * - VR - - not available * - VRCamera - - not available * - WTGareas - WTG area - :ref:`ObjWtgAreasService ` * - WTGnet - - not available In the following a few examples are given on how to use the the ObjectsService To use, create, and edit objects and layers in windPRO with a python script you need to make an instance of the service for objects. It is done with ``windproapi.get_service()``, which takes in the type of service as a parameter. The code below is an example of the setup needed to use the windproapi. .. code-block:: python import os from windproapi.utils import get_windpro_sample_path from windproapi import WindProApi _windproapi = WindProApi() _windproapi.start_windpro_random_port() objects_service = _windproapi.get_service('ObjectsService') Manipulate Objects ****************** With ``GetObjectTypes`` you get a list of all the object types in windPRO, and with ``GetObjectCount`` you get the number of objects in your project. The code below shows an example of the method. .. code-block:: python project_service = _windproapi.get_service('ProjectService') working_dir = os.path.join(get_windpro_sample_path("4.0"), 'New Salem\\4.0') project_path = os.path.join(working_dir, 'New Salem.w40p') project_service.LoadFromFile(project_path) # objTypes stores a list of object types objTypes = objects_service.GetObjectTypes() # objCount stores the number of objects objCount = objects_service.GetObjectCount() ``GetObject`` returns an object as a dictionary with it's properties, it takes the index of the object as a parameter. Like ``GetObject``, ``GetObjectFromHandle`` also returns an object a dictionary but takes in the handle of the object as a parameter. Getting objects by handle is recommended, as the handle will not change if objects are added or deleted. You can assign properties directly using "." and then you can apply the changes with ``SetObjectPropsFromHandle``, where you overwrite the object. The code below shows an example on these methods as well as an example of a windPRO object in python. .. code-block:: python # GetObject() stores information about and object as a dictionary obj = objects_service.GetObject(1) # result of obj """ { 'Handle': 390762937, 'TypeId': 'NewWTG', 'ObjType': 0, 'ApiObjType': 'NewWTG', 'Lng': -101.406510917218, 'Lat': 46.7555215047512, 'Z': 700.0, 'Count': 1, 'Angle': 0.0, 'UserDescription': 'T24', 'AutoLevel': True, 'OffsetZ': 0.0, 'UserLabel': 'T24', 'SymbolVisible': True } """ # GetObjectFromHandle() stores information about and object as a dictionary objFromHandle = objects_service.GetObjectFromHandle(Handle) # Make some changes to the object before applying them with SetObjectPropsFromHandle() obj.Lng = -101.40 obj.Lat = 46.75 # SetObjectPropsFromHandle() set the properties in the object given as a parameter and returns it with the new information. obj = objects_service.SetObjectPropsFromHandle(obj) # GetObjects() returns all objects of a specific type objects_service.GetObjects('NewWTG') Often it is needed to get objects of a specific type. You can also get a list of all objects of a specific type with ``GetObjects`` which takes the object type as a parameter. All objects types are available from ``GetObjectTypes``. .. code-block:: python # objTypes stores a list of object types objTypes = objects_service.GetObjectTypes() print(objTypes) # Getting all turbines that are in the project. NewWTG in contrast to ExistWTG new_wtgs_objs = objects_service.GetObjects("NewWTG") Interaction with windPRO scripting are kept to a relatively basic level for getting object. Getting objects by index can be useful if it is necessary to loop through all objects in the project. Getting objects by handle ensures that this is the exact object that was intended. Often it is necessary to find a specific object from this list of objects, e.g, from its *Description* in windPRO. With scripting functionality like this can be easily made within the scripting language. .. code-block:: python # Getting all turbines that are in the project. NewWTG in contrast to ExistWTG new_wtgs_objs = objects_service.GetObjects("NewWTG") # Defining function that loops through a def get_obj_from_list_by_user_description(objs, user_description): l_obj = [] for o in objs: if o["UserDescription"] == user_description: l_obj.append(o) if len(l_obj) == 1: return l_obj[0] elif len(l_obj) == 0: raise ValueError(f"Could not find {user_description} in any UserDescription.") else: raise ValueError(f"More than one variable UserDescription {user_description}.") obj_T24 = get_obj_from_list_by_user_description(new_wtgs_objs, "T24") You can add, save, load, delete, and clone an object using the methods shown below. With ``AddObject`` you need to give a type, latitude, longitude, and a name of the object. ``SaveObject`` needs the handle of the object you want to save and the path where you want to save it. ``LoadObject`` need the path of the file you want to load. ``DeleteObject`` and ``CloneObject`` need the handle of the object you want to alter. The code below is an example of these methods. .. code-block:: python # AddObject(type, lat, lon, name) adds a new object of a specific type with a name and placed on parsed coordinates. objects_service.AddObject('NewWTG', 46.75, -101.40, 'New WTG obj') # CloneObject(handle) copies an object and returns the properties as a dictionary cloneObj = objects_service.CloneObject(Handle) # SaveObject(int handle, string path) saves an object to a file and returns true on succes saveObj = objects_service.SaveObject(Handle, filePath) # DeleteObject(int handle) deletes an object objects_service.DeleteObject(Handle) # LoadObject() loads an object from a file and returns true on succes loadObj = objects_service.LoadObject(filePath) Manipulate layers ***************** You can get basic information about layers from the ObjectService. It is possible to get the number of layers and the handle of that layer by index. The name of the layer is connected via the layer handle. .. code-block:: python # return the count of all layers layerCount = objects_service.GetLayerCount() # returns the handle of the layer with the count given layerHandle = objects_service.GetLayerHandle(1) # returns the name of the layer by handle layerName = objects_service.GetLayerName(layerHandle) You can add, rename, and delete layers simple by following the example shown below. AddLayer returns a handle that can be used to modify this layer. Adding layers requires the handle of the parent folder. If the layer is not supposed to be in a sub folder you need to indicate this by using a 0. .. code-block:: python # Adds a layer with a given name and returns the handle layer = objects_service.AddLayer('newlayer', 0) # Renames a layer with the handle stored in the layer variable objects_service.RenameLayer(layer, 'RenamedLayer') # Deletes layer from handle objects_service.DeleteLayer(layer) You can get the current layer in editmode and change it to another layer with the example shown below. .. code-block:: python # returns the current edit layer editLayer = objects_service.GetEditLayer() # set a layer to edit layer with a handle objects_service.SetEditLayer(layerHandle) Layers are like a folder structure but the output from windPRO is a flat list where layers are linked to their parent folder by handle. Transforming the existing layer structure into a dictionary in python is possible with the function *get_layer_dict* provided in the python package. Be aware that layer folder names need to be unique for this function to work properly. A full running example showing the presented features is given below. You need the sample project New Salem to execute the script. Result Layers ************* Result layers are also handles as objects in windPRO. They have a location, even though they are not shown on the windPRO GUI. A good way is to choose the location of the site center for all result layers. Manually adding result layers is necessary for some calculations to display the result in windPRO. .. literalinclude:: ../../python/examples/fromDocs/object_service.py