Running a Script
Running scripts from context menus
The mapteksdk.context_menu package contains functionality designed for scripts run from context menus in the Workbench. It allows for querying the object right clicked on to open the context menu and the location on that object the mouse was over when the context menu was opened.
Getting the object right clicked on
There are two ways to get the object right clicked on to open the context menu: context_object_path() and context_object_id().
The context_object_path() function:
-
Returns the path to the object right clicked on to open the context menu. This can be used to open the right clicked object, but nothing else.
-
It will not raise an error if not connected to an application.
-
Without an application it won’t be useful unless you pass it to another script or program that will or is connected to an application.
-
-
It will raise an error if the script was not run from a context menu or if there was no object under the mouse when the context menu was opened.
The context_object_id() function:
-
Returns the object ID of the object right clicked to open the context menu. This can be used to query metadata about the object (e.g. its type) and to open the right clicked object.
-
This will raise an error if called before the script connects to an application.
-
It will raise an error if the script was not run from a context menu or if there was no object under the mouse when the context menu was opened.
The following example script uses this to colour the object right clicked on purple.
from mapteksdk.project import Project from mapteksdk.context_menu import context_object_path PURPLE = [221, 160, 221, 255] if __name__ == "__main__": # Call context_object_path() before Project() so that if the script is not # called from a context menu, it will encounter an error before it # wastes any time attempting to connect to an application. path = context_object_path() with Project() as project: with project.edit(path) as context_object: try: context_object.point_colours[:] = PURPLE except AttributeError: pass try: context_object.facet_colours[:] = PURPLE except AttributeError: pass try: context_object.block_colours[:] = PURPLE except AttributeError: pass
The following animation demonstrates this script:
![](../../images/key-concepts/output/context-menu-object.gif)
Getting the location of the object that was right-clicked on
The context_location function returns the location the point the mouse was over when the context menu was opened.
-
The context_location() function will raise an error if the script was not called from a context menu, or if there was no object under the mouse when the context menu was opened.
-
The context_location() function will not raise an error if it is called before connecting to an application.
The following example script creates a label where the mouse was when the context menu was opened:
from __future__ import annotations from mapteksdk.project import Project from mapteksdk.data import Text2D from mapteksdk.context_menu import context_object_id, context_location from mapteksdk.operations import active_view def next_label_name(project: Project, template: str) -> tuple[int, str]: """Get the next unused number and path for the next label to create. Parameters ---------- project Project to use to check for objects in. template A string containing a single "%i". The %i will be replaced with an integer until it is a path which does not exist in a project. Returns ------- tuple A tuple where the first element is the number inserted into the template string which resulted in an object which did not exist. The second element is the path for the next label. Warnings -------- This function is not thread safe. """ i = 1 while True: result_path = template % i if not project.find_object(result_path): return i, result_path i += 1 if __name__ == "__main__": with Project() as project: oid = context_object_id() template = f"{oid.path}_labels/%i" i, path = next_label_name(project, template) with project.new(path, Text2D) as label: label.text = str(i) label.location = context_location() view = active_view() view.add_objects([label.id])
The following animation shows this script in action:
![](../../images/key-concepts/output/content-menu-location.gif)
Advanced - Using context object and location
The context menu functions are not mutually exclusive and can be used together, as demonstrated in the following example. This example colours the right clicked object by distance from the mouse cursor when the context menu was opened (Red for close, transitioning to orange and then blue for points far away from the cursor):
from mapteksdk.project import Project from mapteksdk.data import PointSet, NumericColourMap, ObjectID from mapteksdk.context_menu import context_location, context_object_id import numpy as np DISTANCE_FROM_CLICK = "distance_from_click" def calculate_distance_from_point( points: np.ndarray, target_point: np.ndarray) -> np.ndarray: """Calculate the distance of many points from the target point. Parameters ---------- points The points to calculate their distance from the target point. This should be a numpy array of shape (N, 3) where N is the point count. target_point The target point. This should be a numpy array of shape (3,) Returns ------- ndarray The distance of each point in points from the target point. This is a numpy array of shape (N,) where N is the number of points in points. """ return np.linalg.norm(points - target_point, axis=1) def generate_colour_map( project: Project, minimum: float, middle: float, maximum: float ) -> ObjectID[NumericColourMap]: """Generate a colour map. The colour map is red at the minimum, orange at the middle and blue at the maximum. Parameters ---------- project The Project to use to create the colour map. minimum The minimum value in the colour map. This will be red in the colour map. middle The midpoint of the colour map. This should be greater than minimum and less than middle. It does not need to be the exact midpoint. This will be orange in the colour map. maximum The maximum value in the colour map. This will be blue in the colour map. Returns ------- ObjectID[ColourMap] The object ID of the colour map. """ with project.new(None, NumericColourMap) as colour_map: colour_map.ranges = [minimum, middle, maximum] colour_map.colours = [ [255, 0, 0, 255], [255, 165, 0, 255], [0, 0, 255, 255] ] return colour_map.id if __name__ == "__main__": with Project() as project: with project.edit(context_object_id()) as data_object: data_object: PointSet # Calculate the distance of every point in the object from the # picked point. try: distance_from_click = calculate_distance_from_point( data_object.points, context_location()) data_object.point_attributes[DISTANCE_FROM_CLICK] = distance_from_click except AttributeError as error: raise RuntimeError("This operation only supports objects with points." ) from error minimum = np.min(distance_from_click) maximum = np.max(distance_from_click) middle = (minimum + maximum) / 2 # Colour the object by distance from the picked point. colour_map_id = generate_colour_map(project, minimum, middle, maximum) data_object.point_attributes.set_colour_map( DISTANCE_FROM_CLICK, colour_map_id)
The following animation shows this script in action:
![](../../images/key-concepts/output/context-menu-object-and-location.gif)