# Path: trimesh/constants.py
# class NumericalToleranceMesh(object):
# class NumericalResolutionMesh(object):
# class NumericalTolerancePath(object):
# class NumericalResolutionPath(object):
# class MeshError(Exception):
# class TransformError(Exception):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
# def _log_time(method):
#     def timed(*args, **kwargs):
# 
# Path: trimesh/constants.py
# class NumericalToleranceMesh(object):
# class NumericalResolutionMesh(object):
# class NumericalTolerancePath(object):
# class NumericalResolutionPath(object):
# class MeshError(Exception):
# class TransformError(Exception):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
# def _log_time(method):
#     def timed(*args, **kwargs):
# 
# Path: trimesh/path/entities.py
# class Line(Entity):
#     '''
#     A line or poly-line entity
#     '''
# 
#     def discrete(self, vertices, scale=1.0):
#         return vertices[self.points]
# 
#     @property
#     def is_valid(self):
#         valid = np.any((self.points - self.points[0]) != 0)
#         return valid
# 
#     def explode(self):
#         points = np.column_stack((self.points,
#                                   self.points)).ravel()[1:-1].reshape((-1, 2))
#         return [Line(i) for i in points]
# 
# class Arc(Entity):
# 
#     @property
#     def closed(self):
#         if hasattr(self, '_closed'):
#             return self._closed
#         return False
# 
#     @closed.setter
#     def closed(self, value):
#         self._closed = bool(value)
# 
#     def discrete(self, vertices, scale=1.0):
#         return discretize_arc(vertices[self.points],
#                               close=self.closed,
#                               scale=scale)
# 
#     def center(self, vertices):
#         return arc_center(vertices[self.points])
# 
# class BSpline(Curve):
# 
#     def __init__(self, points, knots, closed=None):
#         self.points = points
#         self.knots = knots
# 
#     def discrete(self, vertices, count=None, scale=1.0):
#         result = discretize_bspline(control=vertices[self.points],
#                                     knots=self.knots,
#                                     count=count,
#                                     scale=scale)
#         return result
# 
#     def to_dict(self):
#         '''
#         Returns a dictionary with all of the information about the entity.
#         '''
#         return {'type': self.__class__.__name__,
#                 'points': self.points.tolist(),
#                 'knots': self.knots.tolist(),
#                 'closed': self.closed}
# 
# Path: trimesh/path/util.py
# def angles_to_threepoint(angles, center, radius, normal=[0, 0, 1]):
#     if angles[1] < angles[0]:
#         angles[1] += np.pi * 2
#     angles = [angles[0], np.mean(angles), angles[1]]
#     planar = np.column_stack((np.cos(angles), np.sin(angles))) * radius
#     points = planar + center
#     return points
# 
# def is_ccw(points):
#     '''
#     Given an (n,2) set of points, return True if they are counterclockwise
#     '''
#     xd = np.diff(points[:, 0])
#     yd = np.sum(np.column_stack((points[:, 1],
#                                  points[:, 1])).reshape(-1)[1:-1].reshape((-1, 2)), axis=1)
#     area = np.sum(xd * yd) * .5
#     ccw = area < 0
# 
#     return ccw
# 
# Path: trimesh/util.py
# def is_binary_file(file_obj):
#     '''
#     Returns True if file has non-ASCII characters (> 0x7F, or 127)
#     Should work in both Python 2 and 3
#     '''
#     start = file_obj.tell()
#     fbytes = file_obj.read(1024)
#     file_obj.seek(start)
#     is_str = isinstance(fbytes, str)
#     for fbyte in fbytes:
#         if is_str:
#             code = ord(fbyte)
#         else:
#             code = fbyte
#         if code > 127:
#             return True
#     return False
# 
# def multi_dict(pairs):
#     '''
#     Given a set of key value pairs, create a dictionary.
#     If a key occurs multiple times, stack the values into an array.
# 
#     Can be called like the regular dict(pairs) constructor
# 
#     Arguments
#     ----------
#     pairs: (n,2) array of key, value pairs
# 
#     Returns
#     ----------
#     result: dict, with all values stored (rather than last with regular dict)
# 
#     '''
#     result = collections.defaultdict(list)
#     for k, v in pairs:
#         result[k].append(v)
#     return result
# 
# def make_sequence(obj):
#     '''
#     Given an object, if it is a sequence return, otherwise
#     add it to a length 1 sequence and return.
# 
#     Useful for wrapping functions which sometimes return single
#     objects and other times return lists of objects.
#     '''
#     if is_sequence(obj):
#         return np.array(list(obj))
#     else:
#         return np.array([obj])


import numpy as np
import collections
from ...constants import log
from ...constants import tol_path as tol
from ..entities import Line, Arc, BSpline
from ..util import angles_to_threepoint, is_ccw
from ...util import is_binary_file, multi_dict, make_sequence


# unit codes
_DXF_UNITS = {1: 'inches',
              2: 'feet',
              3: 'miles',
              4: 'millimeters',
              5: 'centimeters',
              6: 'meters',
              7: 'kilometers',
              8: 'microinches',
              9: 'mils',
              10: 'yards',
              11: 'angstroms',
              12: 'nanometers',

# Path: trimesh/constants.py
# class NumericalToleranceMesh(object):
# class NumericalResolutionMesh(object):
# class NumericalTolerancePath(object):
# class NumericalResolutionPath(object):
# class MeshError(Exception):
# class TransformError(Exception):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
# def _log_time(method):
#     def timed(*args, **kwargs):
# 
# Path: trimesh/constants.py
# class NumericalToleranceMesh(object):
# class NumericalResolutionMesh(object):
# class NumericalTolerancePath(object):
# class NumericalResolutionPath(object):
# class MeshError(Exception):
# class TransformError(Exception):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
#     def __init__(self, **kwargs):
# def _log_time(method):
#     def timed(*args, **kwargs):
# 
# Path: trimesh/path/entities.py
# class Line(Entity):
#     '''
#     A line or poly-line entity
#     '''
# 
#     def discrete(self, vertices, scale=1.0):
#         return vertices[self.points]
# 
#     @property
#     def is_valid(self):
#         valid = np.any((self.points - self.points[0]) != 0)
#         return valid
# 
#     def explode(self):
#         points = np.column_stack((self.points,
#                                   self.points)).ravel()[1:-1].reshape((-1, 2))
#         return [Line(i) for i in points]
# 
# class Arc(Entity):
# 
#     @property
#     def closed(self):
#         if hasattr(self, '_closed'):
#             return self._closed
#         return False
# 
#     @closed.setter
#     def closed(self, value):
#         self._closed = bool(value)
# 
#     def discrete(self, vertices, scale=1.0):
#         return discretize_arc(vertices[self.points],
#                               close=self.closed,
#                               scale=scale)
# 
#     def center(self, vertices):
#         return arc_center(vertices[self.points])
# 
# class BSpline(Curve):
# 
#     def __init__(self, points, knots, closed=None):
#         self.points = points
#         self.knots = knots
# 
#     def discrete(self, vertices, count=None, scale=1.0):
#         result = discretize_bspline(control=vertices[self.points],
#                                     knots=self.knots,
#                                     count=count,
#                                     scale=scale)
#         return result
# 
#     def to_dict(self):
#         '''
#         Returns a dictionary with all of the information about the entity.
#         '''
#         return {'type': self.__class__.__name__,
#                 'points': self.points.tolist(),
#                 'knots': self.knots.tolist(),
#                 'closed': self.closed}
# 
# Path: trimesh/path/util.py
# def angles_to_threepoint(angles, center, radius, normal=[0, 0, 1]):
#     if angles[1] < angles[0]:
#         angles[1] += np.pi * 2
#     angles = [angles[0], np.mean(angles), angles[1]]
#     planar = np.column_stack((np.cos(angles), np.sin(angles))) * radius
#     points = planar + center
#     return points
# 
# def is_ccw(points):
#     '''
#     Given an (n,2) set of points, return True if they are counterclockwise
#     '''
#     xd = np.diff(points[:, 0])
#     yd = np.sum(np.column_stack((points[:, 1],
#                                  points[:, 1])).reshape(-1)[1:-1].reshape((-1, 2)), axis=1)
#     area = np.sum(xd * yd) * .5
#     ccw = area < 0
# 
#     return ccw
# 
# Path: trimesh/util.py
# def is_binary_file(file_obj):
#     '''
#     Returns True if file has non-ASCII characters (> 0x7F, or 127)
#     Should work in both Python 2 and 3
#     '''
#     start = file_obj.tell()
#     fbytes = file_obj.read(1024)
#     file_obj.seek(start)
#     is_str = isinstance(fbytes, str)
#     for fbyte in fbytes:
#         if is_str:
#             code = ord(fbyte)
#         else:
#             code = fbyte
#         if code > 127:
#             return True
#     return False
# 
# def multi_dict(pairs):
#     '''
#     Given a set of key value pairs, create a dictionary.
#     If a key occurs multiple times, stack the values into an array.
# 
#     Can be called like the regular dict(pairs) constructor
# 
#     Arguments
#     ----------
#     pairs: (n,2) array of key, value pairs
# 
#     Returns
#     ----------
#     result: dict, with all values stored (rather than last with regular dict)
# 
#     '''
#     result = collections.defaultdict(list)
#     for k, v in pairs:
#         result[k].append(v)
#     return result
# 
# def make_sequence(obj):
#     '''
#     Given an object, if it is a sequence return, otherwise
#     add it to a length 1 sequence and return.
# 
#     Useful for wrapping functions which sometimes return single
#     objects and other times return lists of objects.
#     '''
#     if is_sequence(obj):
#         return np.array(list(obj))
#     else:
#         return np.array([obj])


# Path: trimesh/path/io/dxf_load.py
import numpy as np
import collections
from ...constants import log
from ...constants import tol_path as tol
from ..entities import Line, Arc, BSpline
from ..util import angles_to_threepoint, is_ccw
from ...util import is_binary_file, multi_dict, make_sequence



# unit codes
_DXF_UNITS = {1: 'inches',
              2: 'feet',
              3: 'miles',
              4: 'millimeters',
              5: 'centimeters',
              6: 'meters',
              7: 'kilometers',
              8: 'microinches',
              9: 'mils',
              10: 'yards',
              11: 'angstroms',
              12: 'nanometers',

              13: 'microns',