# Path: openmodes/helpers.py
# class Identified(object):
#     """An object which can be uniquely identified by an id number. It is
#     assumed that any object which subclasses Identified is immutable, so that
#     its id can be used for caching complex results which depend on this object.
#     """
# 
#     def __init__(self):
#         self.id = uuid.uuid4()
# 
#     def __hash__(self):
#         return self.id.__hash__()
# 
#     def __eq__(self, other):
#         return hasattr(other, 'id') and (self.id == other.id)
# 
#     def __repr__(self):
#         "Represent the object by its id, in addition to its memory address"
#         return ("<%s at 0x%08x with id %s>" % (str(self.__class__)[8:-2],
#                                                id(self),
#                                                str(self.id)))
# 
# class cached_property(object):
#     """
#     A property that is only computed once per instance and then replaces itself
#     with an ordinary attribute. Deleting the attribute resets the property.
# 
#     Taken from https://github.com/pydanny/cached-property/blob/master/cached_property.py
#     Original source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
#     Copyright under MIT License
#     """
# 
#     def __init__(self, func):
#         self.__doc__ = getattr(func, '__doc__')
#         self.func = func
# 
#     def __get__(self, obj, cls):
#         if obj is None:
#             return self
#         value = obj.__dict__[self.func.__name__] = self.func(obj)
#         return value


import logging
import numpy as np
from openmodes.helpers import Identified, cached_property
from openmodes.external.ordered_set import OrderedSet
from collections import OrderedDict
    @property
    def shortest_edge(self):
        """The shortest edge in the mesh"""
        return self.edge_lens.min()

    @property
    def max_distance(self):
        """The furthest distance between any two nodes in this mesh"""
        return np.sqrt(np.sum((self.nodes[:, None, :] -
                       self.nodes[None, :, :])**2, axis=2)).max()

    def fast_size(self):
        """A fast estimate of the size of the mesh, based on the maximum
        distance along any of the three cartesian axes"""
        return max(np.max(self.nodes, axis=0)-np.min(self.nodes, axis=0))

    @property
    def polygon_areas(self):
        """The area of each triangle in the mesh"""
        areas = np.empty(len(self.polygons), np.float64)

        # calculate all the edges in the mesh
        for count, t_nodes in enumerate(self.polygons):
            # calculate the area of each triangle
            vec1 = self.nodes[t_nodes[1]]-self.nodes[t_nodes[0]]
            vec2 = self.nodes[t_nodes[2]]-self.nodes[t_nodes[0]]
            areas[count] = 0.5*np.sqrt(sum(np.cross(vec1, vec2)**2))

        return areas


# Path: openmodes/helpers.py
# class Identified(object):
#     """An object which can be uniquely identified by an id number. It is
#     assumed that any object which subclasses Identified is immutable, so that
#     its id can be used for caching complex results which depend on this object.
#     """
# 
#     def __init__(self):
#         self.id = uuid.uuid4()
# 
#     def __hash__(self):
#         return self.id.__hash__()
# 
#     def __eq__(self, other):
#         return hasattr(other, 'id') and (self.id == other.id)
# 
#     def __repr__(self):
#         "Represent the object by its id, in addition to its memory address"
#         return ("<%s at 0x%08x with id %s>" % (str(self.__class__)[8:-2],
#                                                id(self),
#                                                str(self.id)))
# 
# class cached_property(object):
#     """
#     A property that is only computed once per instance and then replaces itself
#     with an ordinary attribute. Deleting the attribute resets the property.
# 
#     Taken from https://github.com/pydanny/cached-property/blob/master/cached_property.py
#     Original source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
#     Copyright under MIT License
#     """
# 
#     def __init__(self, func):
#         self.__doc__ = getattr(func, '__doc__')
#         self.func = func
# 
#     def __get__(self, obj, cls):
#         if obj is None:
#             return self
#         value = obj.__dict__[self.func.__name__] = self.func(obj)
#         return value


# Path: openmodes/mesh/mesh.py
import logging
import numpy as np
from openmodes.helpers import Identified, cached_property
from openmodes.external.ordered_set import OrderedSet
from collections import OrderedDict

    @property
    def shortest_edge(self):
        """The shortest edge in the mesh"""
        return self.edge_lens.min()

    @property
    def max_distance(self):
        """The furthest distance between any two nodes in this mesh"""
        return np.sqrt(np.sum((self.nodes[:, None, :] -
                       self.nodes[None, :, :])**2, axis=2)).max()

    def fast_size(self):
        """A fast estimate of the size of the mesh, based on the maximum
        distance along any of the three cartesian axes"""
        return max(np.max(self.nodes, axis=0)-np.min(self.nodes, axis=0))

    @property
    def polygon_areas(self):
        """The area of each triangle in the mesh"""
        areas = np.empty(len(self.polygons), np.float64)

        # calculate all the edges in the mesh
        for count, t_nodes in enumerate(self.polygons):
            # calculate the area of each triangle
            vec1 = self.nodes[t_nodes[1]]-self.nodes[t_nodes[0]]
            vec2 = self.nodes[t_nodes[2]]-self.nodes[t_nodes[0]]
            areas[count] = 0.5*np.sqrt(sum(np.cross(vec1, vec2)**2))

        return areas


    @cached_property