3D Text
3D text is a text label positioned at a specific location in 3D space with a defined orientation and size. Unlike 2D text, 3D text behaves like other 3D objects in the view; its orientation and size on the screen change when zooming or rotating. A single 3D text label is represented in the SDK with the Text3D class.
Text3D properties
All properties for 2D Text objects also apply to 3D text objects. In addition, you can use the following properties to customise the appearance of your 3D text object:
Set the direction of the label in space. The direction is defined as a vector from the start of the first character to the end of the last character. This property is represented by a 3D vector [X, Y, Z]. | |
Set the direction from the bottom of the text to the top. | |
Set this boolean property to control whether the label should be visible or not when there are other 3D objects positioned in front of it. | |
Set the direction the text should face, one of the following enum values: |
3D text examples
The following examples illustrate how to create and modify 3D text labels in a 3D environment. These examples cover creating a basic Text3D object, adjusting its properties such as text content, size, colour, and orientation, and using 3D text labels to annotate points, edges, and facets in a project.
Creating a Text3D object
The following example demonstrates how to create a 3D text object in a project, specifying its text, location, colour, and size properties.
from mapteksdk.project import Project from mapteksdk.data import Text3D project = Project() # Connect to default project object_path = "scrapbook/text3d_example" # Create Text with project.new(object_path, Text3D, overwrite=True) as text: text.text = 'hello world' text.location = [0, 0, 0] # Colours are R,G,B,A, where A is Alpha (255 = opaque) text.colour = [38, 128, 0, 255] # Light Green text.size = 100
Editing 3D text properties
The following example modifies the colour, size, text, and location of the Text3D object created in the last example.
from mapteksdk.project import Project project = Project() # Connect to default project object_path = "scrapbook/text3d_example" # Create Text with project.edit(object_path) as text: text.text = 'new text' text.location = [50, 50, 50] # Colours are R,G,B,A, where A is Alpha (255 = opaque) text.colour = [255, 50, 50, 255] text.size = 150
Labelling points at a particular height
The following example demonstrates how to create 3D text labels at the points of selected objects in a project, displaying their heights and colouring them based on their vertical position.
from mapteksdk.project import Project from mapteksdk.data import Text3D import numpy as np def colour_by_height(z_coordinates): # Sets a basic colour map over points based on height value within height range lowest, highest = np.min(z_coordinates), np.max(z_coordinates) ratio = 2 * (z_coordinates - lowest) / (highest - lowest) b = np.clip((255*(1-ratio)), 0, 255).astype(np.uint8) r = np.clip((255*(ratio-1)), 0, 255).astype(np.uint8) g = np.clip((255 - b - r), 0, 255).astype(np.uint8) a = np.full(z_coordinates.shape, 255, dtype=np.uint8) return np.column_stack((r,g,b,a)) project = Project() # Connect to default project selection = project.get_selected() for item in selection: with project.read(item) as obj: if hasattr(obj, 'points'): # Append _facet_index_labels/ to the surface path as the container to # store the text objects in parent_path = f"{obj.id.path}_point_heights" for i in range(obj.point_count): # For convenience, get z coordinates as an array z = obj.points[: ,2] # Create colours to assign to each value based on height in range colours = colour_by_height(z) with project.new_or_edit(f"{parent_path}/{i}", Text3D, overwrite=True) as label: # Position on the point label.location = obj.points[i] # Set label to point z coordinate label.text = str(f"{round(z[i],1)}m") label.size = 3 label.colour = colours[i]
Labelling point indices
This following example illustrates how to create 3D text labels at each point of selected objects in a project, displaying the index of each point.
from mapteksdk.project import Project from mapteksdk.data import Text3D project = Project() # Connect to default project selection = project.get_selected() for item in selection: with project.read(item) as obj: if hasattr(obj, 'points'): # Support anything with points # Append _edge_index_labels/ to the surface path as the container to # store the text objects in parent_path = f"{obj.id.path}_point_index_labels" for i in range(obj.point_count): with project.new_or_edit(f"{parent_path}/{i}", Text3D, overwrite=True) as label: # Position on the point label.location = obj.points[i] # Set label to point index label.text = str(i) label.size = 1 label.colour = [0, 255, 0, 255]
Labelling edge indices
The following example demonstrates how to create 3D text labels at the centre of each edge in selected objects, displaying the index of each edge with a size proportional to the length of the edge.
from mapteksdk.project import Project from mapteksdk.data import Text3D import numpy as np def edge_distances(edge_lines:np.ndarray) -> np.ndarray: # Calculate distance for each edge p1, p2 = edge_lines[:, 0, :], edge_lines[:, 1, :] line_lengths = np.sqrt((p2-p1)**2) return np.sum(line_lengths, axis=1) project = Project() # Connect to default project selection = project.get_selected() for item in selection: with project.read(item) as obj: if hasattr(obj, 'edges'): # Support lines or surfaces # Append _edge_index_labels/ to the surface path as the container to # store the text objects in parent_path = f"{obj.id.path}_edge_index_labels" edge_lines = obj.points[obj.edges] edge_lengths = edge_distances(edge_lines) edge_centres = np.mean(edge_lines, axis=1) for i in range(edge_lines.shape[0]): with project.new_or_edit(f"{parent_path}/{i}", Text3D, overwrite=True) as label: # Position in the centre of the edge label.location = edge_centres[i] # Set label to edge index label.text = str(i) # Variably size the text based on the length of the edge label.size = edge_lengths[i] / 10 label.colour = [255, 0, 0, 255]
Labelling facet indices
The following example demonstrates how to create 3D text labels at the centre of each facet in selected surface objects, displaying the index of each facet in the facets
array with a size proportional to its perimeter.
from mapteksdk.project import Project from mapteksdk.data import Text3D, Surface import numpy as np def triangle_perimeters(triangles:np.ndarray) -> np.ndarray: # Calculate perimeter for each triangle p1, p2, p3 = triangles[:, 0, :], triangles[:, 1, :], triangles[:, 2, :] line_lengths = np.sqrt((p2-p1)**2 + (p3-p2)**2 + (p3-p1)**2) return np.sum(line_lengths, axis=1) project = Project() # Connect to default project selection = project.get_selected() for item in selection: if item.is_a(Surface): with project.read(item) as surface: # Append _facet_index_labels/ to the surface path as the container to # store the text objects in parent_path = f"{surface.id.path}_facet_index_labels" triangles = surface.points[surface.facets] perimeters = triangle_perimeters(triangles) centroids = np.mean(triangles, axis=1) for i in range(triangles.shape[0]): with project.new_or_edit(f"{parent_path}/{i}", Text3D, overwrite=True) as label: # Position in the centre of the facet label.location = centroids[i] # Set label to facet index label.text = str(i) # Variably size the text based on the perimeter of the facet label.size = perimeters[i] / 15