Coverage for trimesh/path/util.py: 100%
22 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-24 04:40 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-24 04:40 +0000
1import numpy as np
3from ..util import is_ccw # NOQA
6def concatenate(paths, **kwargs):
7 """
8 Concatenate multiple paths into a single path.
10 Parameters
11 -------------
12 paths : (n,) Path
13 Path objects to concatenate
14 kwargs
15 Passed through to the path constructor
17 Returns
18 -------------
19 concat : Path, Path2D, or Path3D
20 Concatenated result
21 """
22 # if only one path object just return copy
23 if len(paths) == 1:
24 return paths[0].copy()
26 # upgrade to 3D if we have mixed 2D and 3D paths
27 dimensions = {i.vertices.shape[1] for i in paths}
28 if len(dimensions) > 1:
29 paths = [i.to_3D() if hasattr(i, "to_3D") else i for i in paths]
31 # length of vertex arrays
32 vert_len = np.array([len(i.vertices) for i in paths])
33 # how much to offset each paths vertex indices by
34 offsets = np.append(0.0, np.cumsum(vert_len))[:-1].astype(np.int64)
36 # resulting entities
37 entities = []
38 # resulting vertices
39 vertices = []
40 # resulting metadata
41 metadata = {}
42 for path, offset in zip(paths, offsets):
43 # update metadata
44 metadata.update(path.metadata)
45 # copy vertices, we will stack later
46 vertices.append(path.vertices.copy())
47 # copy entity then reindex points
48 for entity in path.entities:
49 # cleanly copy the entity into a new object
50 copied = entity.copy()
51 # offset the indexes
52 copied.points += offset
53 entities.append(copied)
54 # generate the single new concatenated path
55 # use input types so we don't have circular imports
56 concat = type(path)(
57 metadata=metadata, entities=entities, vertices=np.vstack(vertices), **kwargs
58 )
59 return concat