1import numpy as np
2import os
3
4from .dxf import _dxf_loaders
5from .svg_io import svg_to_path
6from ..path import Path, Path2D, Path3D
7
8from . import misc
9from ... import util
10
11
12def load_path(obj, file_type=None, **kwargs):
13    """
14    Load a file to a Path object.
15
16    Parameters
17    -----------
18    obj : One of the following:
19         - Path, Path2D, or Path3D objects
20         - open file object (dxf or svg)
21         - file name (dxf or svg)
22         - shapely.geometry.Polygon
23         - shapely.geometry.MultiLineString
24         - dict with kwargs for Path constructor
25         - (n,2,(2|3)) float, line segments
26    file_type : str
27        Type of file is required if file
28        object passed.
29
30    Returns
31    ---------
32    path : Path, Path2D, Path3D object
33        Data as a native trimesh Path object
34    """
35
36    if isinstance(obj, Path):
37        # we have been passed a Path object so
38        # do nothing and return the passed object
39        return obj
40    elif util.is_file(obj):
41        # for open file objects use loaders
42        loaded = path_loaders[file_type](obj,
43                                         file_type=file_type)
44        obj.close()
45    elif util.is_string(obj):
46        # strings passed are evaluated as file objects
47        with open(obj, 'rb') as file_obj:
48            # get the file type from the extension
49            file_type = os.path.splitext(obj)[-1][1:].lower()
50            # call the loader
51            loaded = path_loaders[file_type](file_obj,
52                                             file_type=file_type)
53    elif util.is_instance_named(obj, 'Polygon'):
54        # convert from shapely polygons to Path2D
55        loaded = misc.polygon_to_path(obj)
56    elif util.is_instance_named(obj, 'MultiLineString'):
57        # convert from shapely LineStrings to Path2D
58        loaded = misc.linestrings_to_path(obj)
59    elif util.is_instance_named(obj, 'dict'):
60        # load as kwargs
61        loaded = misc.dict_to_path(obj)
62    elif util.is_sequence(obj):
63        # load as lines in space
64        loaded = misc.lines_to_path(obj)
65    else:
66        raise ValueError('Not a supported object type!')
67
68    # pass kwargs through to path loader
69    kwargs.update(loaded)
70    # convert the kwargs to a Path2D or Path3D object
71    path = _create_path(**kwargs)
72
73    return path
74
75
76def _create_path(entities,
77                 vertices,
78                 metadata=None,
79                 **kwargs):
80    """
81    Turn entities and vertices into a Path2D or a Path3D
82    object depending on dimension of vertices.
83
84    Parameters
85    -----------
86    entities : list
87        Entity objects that reference vertex indices
88    vertices : (n, 2) or (n, 3) float
89        Vertices in space
90    metadata : dict
91        Any metadata about the path object
92
93    Returns
94    -----------
95    as_path : Path2D or Path3D object
96        Args in native trimesh object form
97
98    """
99    # make sure vertices are numpy array
100    vertices = np.asanyarray(vertices, dtype=np.float64)
101
102    # check dimension of vertices to decide on object type
103    if vertices.shape[1] == 2:
104        path_type = Path2D
105    elif vertices.shape[1] == 3:
106        path_type = Path3D
107    else:
108        # weird or empty vertices, just use default Path object
109        path_type = Path
110
111    # create the object
112    as_path = path_type(entities=entities,
113                        vertices=vertices,
114                        metadata=metadata,
115                        **kwargs)
116    return as_path
117
118
119def path_formats():
120    """
121    Get a list of supported path formats.
122
123    Returns
124    ------------
125    loaders : list of str
126        Extensions of loadable formats, ie:
127        ['svg', 'dxf']
128    """
129    return list(path_loaders.keys())
130
131
132path_loaders = {'svg': svg_to_path}
133path_loaders.update(_dxf_loaders)
134