Text3D

Text3D is a text label with a 3D location, orientation and size that is maintained when zooming in and out.

All properties for 2D text objects are applicable to 3D text objects. Additionally, use these properties to customise the look of your 3D text object.

Name Description
direction

Use this property to set the direction from the start of the first character to the end of the last character. This property is a three dimensional vector [X, Y, Z].

up_direction

Use this property to set the direction from the bottom of the text to the top

always_visible Use this boolean property to set the visibility of the 3D text when there are objects between the text and the view.
facing

Use this enum property to set where the text is facing. It can be set to the following values:

  • Text3D.Facing.CAMERA_FACING

  • Text3D.Facing.VIEWER_FACING

Topics:

Creating a Text3D Object

from mapteksdk.project import Project
from mapteksdk.data import Text3D
proj = Project() # Connect to default project

object_path = "scrapbook/text3d_example"

# Create Text
with proj.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 Text3D Properties

The following example will modify the colour, size, text, and position of the text object created in the last example.

from mapteksdk.project import Project
from mapteksdk.data import Text3D
proj = Project() # Connect to default project

object_path = "scrapbook/text3d_example"

# Create Text
with proj.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 will add Text3D at each point, with its height, in any selected object that has point primitives.

from mapteksdk.project import Project
from mapteksdk.data import Text3D, Surface
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))

proj = Project() # Connect to default project
selection = proj.get_selected()
for item in selection:
    with proj.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 proj.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

The following example will add Text3D at each point, with its index position in the points array in any selected object that has point primitives.

from mapteksdk.project import Project
from mapteksdk.data import Text3D
import numpy as np

proj = Project() # Connect to default project
selection = proj.get_selected()
for item in selection:
    with proj.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 proj.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 will add Text3D at the centre of each edge, with its index position in the edges array in any selected object that has edges primitives.

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)
    
proj = Project() # Connect to default project
selection = proj.get_selected()
for item in selection:
    with proj.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 proj.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 will add aText3Dobject at the centre of each facet, with its index position in the facets array in any selected Surface.

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)
    
proj = Project() # Connect to default project
selection = proj.get_selected()
for item in selection:
    if item.is_a(Surface):
        with proj.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]
            perimiters = triangle_perimeters(triangles)
            centroids = np.mean(triangles, axis=1)
            for i in range(triangles.shape[0]):
                with proj.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 = perimiters[i] / 15