From e7e7bb39e21b6d3a89fe19a71ffae2b8f46c4412 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 21 Nov 2019 16:08:54 -0500 Subject: [PATCH 1/3] fix(package): Use to_array/ from_array in to_dict/from_dict --- ladybug_geometry/geometry2d/_1d.py | 8 +++---- ladybug_geometry/geometry2d/_2d.py | 2 +- ladybug_geometry/geometry2d/arc.py | 4 ++-- ladybug_geometry/geometry2d/mesh.py | 4 ++-- ladybug_geometry/geometry2d/pointvector.py | 20 +++++++++++++--- ladybug_geometry/geometry2d/polygon.py | 8 +++---- ladybug_geometry/geometry3d/_1d.py | 8 +++---- ladybug_geometry/geometry3d/_2d.py | 2 +- ladybug_geometry/geometry3d/face.py | 12 +++++----- ladybug_geometry/geometry3d/mesh.py | 4 ++-- ladybug_geometry/geometry3d/plane.py | 12 +++++----- ladybug_geometry/geometry3d/pointvector.py | 28 +++++++++++----------- ladybug_geometry/geometry3d/polyface.py | 8 +++---- 13 files changed, 67 insertions(+), 53 deletions(-) diff --git a/ladybug_geometry/geometry2d/_1d.py b/ladybug_geometry/geometry2d/_1d.py index 93837599..aa0b95a6 100644 --- a/ladybug_geometry/geometry2d/_1d.py +++ b/ladybug_geometry/geometry2d/_1d.py @@ -41,8 +41,8 @@ def from_dict(cls, data): "v": (10, 10) } """ - return cls(Point2D(data['p'][0], data['p'][1]), - Vector2D(data['v'][0], data['v'][1])) + return cls(Point2D.from_array(data['p']), + Vector2D.from_array(data['v'])) @property def p(self): @@ -95,8 +95,8 @@ def duplicate(self): def to_dict(self): """Get LineSegment2D/Ray2D as a dictionary.""" - return {'p': (self.p.x, self.p.y), - 'v': (self.v.x, self.v.y)} + return {'p': self.p.to_array(), + 'v': self.v.to_array()} def __copy__(self): return self.__class__(self.p, self.v) diff --git a/ladybug_geometry/geometry2d/_2d.py b/ladybug_geometry/geometry2d/_2d.py index e41fca7e..3a6c74b1 100644 --- a/ladybug_geometry/geometry2d/_2d.py +++ b/ladybug_geometry/geometry2d/_2d.py @@ -95,7 +95,7 @@ def __getitem__(self, key): def __iter__(self): return iter(self.vertices) - + def __copy__(self): return Base2DIn2D(self._vertices) diff --git a/ladybug_geometry/geometry2d/arc.py b/ladybug_geometry/geometry2d/arc.py index 300eb693..8458f690 100644 --- a/ladybug_geometry/geometry2d/arc.py +++ b/ladybug_geometry/geometry2d/arc.py @@ -67,7 +67,7 @@ def from_dict(cls, data): "a2": 3.14159 } """ - return cls(Point2D(data['c'][0], data['c'][1]), + return cls(Point2D.from_array(data['c']), data['r'], data['a1'], data['a2']) @classmethod @@ -374,7 +374,7 @@ def duplicate(self): def to_dict(self): """Get Arc2D as a dictionary.""" - return {'type': 'Arc2D', 'c': (self.c.x, self.c.y), + return {'type': 'Arc2D', 'c': self.c.to_array(), 'r': self.r, 'a1': self.a1, 'a2': self.a2} def _pt_in(self, point): diff --git a/ladybug_geometry/geometry2d/mesh.py b/ladybug_geometry/geometry2d/mesh.py index 71ef9560..83bd2b60 100644 --- a/ladybug_geometry/geometry2d/mesh.py +++ b/ladybug_geometry/geometry2d/mesh.py @@ -81,7 +81,7 @@ def from_dict(cls, data): raise ImportError('Colors are specified in input Mesh2D dictionary ' 'but failed to import ladybug.color') colors = tuple(Color.from_dict(col) for col in data['colors']) - return cls(tuple(Point2D(pt[0], pt[1]) for pt in data['vertices']), + return cls(tuple(Point2D.from_array(pt) for pt in data['vertices']), data['faces'], colors) @classmethod @@ -398,7 +398,7 @@ def to_dict(self): if self.colors is not None: colors = [col.to_dict() for col in self.colors] return {'type': 'Mesh2D', - 'vertices': [(pt.x, pt.y) for pt in self.vertices], + 'vertices': [pt.to_array() for pt in self.vertices], 'faces': self.faces, 'colors': colors} def _calculate_min_max(self): diff --git a/ladybug_geometry/geometry2d/pointvector.py b/ladybug_geometry/geometry2d/pointvector.py index ec931edf..119e4664 100644 --- a/ladybug_geometry/geometry2d/pointvector.py +++ b/ladybug_geometry/geometry2d/pointvector.py @@ -39,6 +39,16 @@ def from_dict(cls, data): """ return cls(data['x'], data['y']) + @classmethod + def from_array(cls, array): + """Initialize a Vector2D/Point2D from an array. + + Args: + array: A tuple or list with two numbers representing the x and y + values of the point. + """ + return cls(array[0], array[1]) + @property def x(self): """Get the X coordinate.""" @@ -58,15 +68,15 @@ def magnitude(self): def magnitude_squared(self): """Get the magnitude squared of the vector.""" return self.x ** 2 + self.y ** 2 - + def is_zero(self, tolerance=0): """Boolean to note whether the vector is within a given zero tolerance. - + Args: tolerance: The tolerance below which the vector is considered to be a zero vector. """ - return abs(self.x) <= tolerance and abs(self.y) <= tolerance + return abs(self.x) <= tolerance and abs(self.y) <= tolerance def normalize(self): """Get a copy of the vector that is a unit vector (magnitude=1).""" @@ -146,6 +156,10 @@ def to_dict(self): 'x': self.x, 'y': self.y} + def to_array(self): + """Get Vector2D/Point2D as a tuple of two numbers""" + return (self.x, self.y) + def _cast_to_float(self, value): """Ensure that an input coordinate value is a float.""" try: diff --git a/ladybug_geometry/geometry2d/polygon.py b/ladybug_geometry/geometry2d/polygon.py index 841f4638..6b94e6a2 100644 --- a/ladybug_geometry/geometry2d/polygon.py +++ b/ladybug_geometry/geometry2d/polygon.py @@ -65,7 +65,7 @@ def from_dict(cls, data): "vertices": [(0, 0), (10, 0), (0, 10)] } """ - return cls(tuple(Point2D(pt[0], pt[1]) for pt in data['vertices'])) + return cls(tuple(Point2D.from_array(pt) for pt in data['vertices'])) @classmethod def from_rectangle(cls, base_point, height_vector, base, height): @@ -644,7 +644,7 @@ def is_polygon_outside(self, polygon): def to_dict(self): """Get Polygon2D as a dictionary.""" return {'type': 'Polygon2D', - 'vertices': [(pt.x, pt.y) for pt in self.vertices]} + 'vertices': [pt.to_array() for pt in self.vertices]} @staticmethod def intersect_polygon_segments(polygon_list, tolerance): @@ -675,7 +675,7 @@ def intersect_polygon_segments(polygon_list, tolerance): Polygon2D.intersect_segments(polygon_list[i], polygon_list[j], tolerance) return polygon_list - + @staticmethod def intersect_segments(polygon1, polygon2, tolerance): """Intersect the line segments of two Polygon2Ds to ensure matching segments. @@ -729,7 +729,7 @@ def intersect_segments(polygon1, polygon2, tolerance): polygon2 = Polygon2D(poly_points) return polygon1, polygon2 - + @staticmethod def overlapping_bounding_rect(polygon1, polygon2, tolerance): """Check if the bounding rectangles of two polygons overlap within a tolerance. diff --git a/ladybug_geometry/geometry3d/_1d.py b/ladybug_geometry/geometry3d/_1d.py index f60a25ea..719d29b9 100644 --- a/ladybug_geometry/geometry3d/_1d.py +++ b/ladybug_geometry/geometry3d/_1d.py @@ -42,8 +42,8 @@ def from_dict(cls, data): "v": (10, 10, 0) } """ - return cls(Point3D(data['p'][0], data['p'][1], data['p'][2]), - Vector3D(data['v'][0], data['v'][1], data['v'][2])) + return cls(Point3D.from_array(data['p']), + Vector3D.from_array(data['v'])) @property def p(self): @@ -120,8 +120,8 @@ def duplicate(self): def to_dict(self): """Get LineSegment3D/Ray3D as a dictionary.""" - return {'p': (self.p.x, self.p.y, self.p.z), - 'v': (self.v.x, self.v.y, self.v.z)} + return {'p': self.p.to_array(), + 'v': self.v.to_array()} def __copy__(self): return self.__class__(self.p, self.v) diff --git a/ladybug_geometry/geometry3d/_2d.py b/ladybug_geometry/geometry3d/_2d.py index 8ac3ef5b..6ba4b893 100644 --- a/ladybug_geometry/geometry3d/_2d.py +++ b/ladybug_geometry/geometry3d/_2d.py @@ -100,7 +100,7 @@ def __getitem__(self, key): def __iter__(self): return iter(self.vertices) - + def __copy__(self): return Base2DIn3D(self._vertices) diff --git a/ladybug_geometry/geometry3d/face.py b/ladybug_geometry/geometry3d/face.py index bd630b4a..ebd8eda9 100644 --- a/ladybug_geometry/geometry3d/face.py +++ b/ladybug_geometry/geometry3d/face.py @@ -155,11 +155,11 @@ def from_dict(cls, data): holes = None if 'holes' in data and data['holes'] is not None: holes = tuple(tuple( - Point3D(pt[0], pt[1], pt[2]) for pt in hole) for hole in data['holes']) + Point3D.from_array(pt) for pt in hole) for hole in data['holes']) plane = None if 'plane' in data and data['plane'] is not None: plane = Plane.from_dict(data['plane']) - return cls(tuple(Point3D(pt[0], pt[1], pt[2]) for pt in data['boundary']), + return cls(tuple(Point3D.from_array(pt) for pt in data['boundary']), plane, holes) @classmethod @@ -1439,14 +1439,14 @@ def to_dict(self, include_plane=True, enforce_upper_left=False): """ base = {'type': 'Face3D'} if not enforce_upper_left: - base['boundary'] = [(pt.x, pt.y, pt.z) for pt in self.boundary] + base['boundary'] = [pt.to_array() for pt in self.boundary] else: - base['boundary'] = [(pt.x, pt.y, pt.z) for pt in + base['boundary'] = [pt.to_array() for pt in self.upper_left_counter_clockwise_boundary] if include_plane: base['plane'] = self.plane.to_dict() if self.has_holes: - base['holes'] = [[(pt.x, pt.y, pt.z) for pt in hole] + base['holes'] = [[pt.to_array() for pt in hole] for hole in self.holes] return base @@ -1578,7 +1578,7 @@ def _vertices_between_points(self, start_pt, end_pt, tolerance): if self[vert_ind].is_equivalent(end_pt, tolerance): found_other = True return new_verts - + def _diagonal_along_self(self, direction_vector, tolerance): """Get the diagonal oriented along this face and always starts on the left.""" tol_pt = Point3D(1.0e-7, 1.0e-7, 1.0e-7) # closer to Python tolerance than input diff --git a/ladybug_geometry/geometry3d/mesh.py b/ladybug_geometry/geometry3d/mesh.py index ddb29fc2..92268693 100644 --- a/ladybug_geometry/geometry3d/mesh.py +++ b/ladybug_geometry/geometry3d/mesh.py @@ -83,7 +83,7 @@ def from_dict(cls, data): raise ImportError('Colors are specified in input Mesh2D dictionary ' 'but failed to import ladybug.color') colors = tuple(Color.from_dict(col) for col in data['colors']) - return cls(tuple(Point3D(pt[0], pt[1], pt[2]) for pt in data['vertices']), + return cls(tuple(Point3D.from_array(pt) for pt in data['vertices']), data['faces'], colors) @classmethod @@ -347,7 +347,7 @@ def height_field_mesh(self, values, domain): def to_dict(self): """Get Mesh3D as a dictionary.""" base = {'type': 'Mesh3D', - 'vertices': [(pt.x, pt.y, pt.z) for pt in self.vertices], + 'vertices': [pt.to_array() for pt in self.vertices], 'faces': self.faces} if self.colors is not None: base['colors'] = [col.to_dict() for col in self.colors] diff --git a/ladybug_geometry/geometry3d/plane.py b/ladybug_geometry/geometry3d/plane.py index 5499c504..c8c5872d 100644 --- a/ladybug_geometry/geometry3d/plane.py +++ b/ladybug_geometry/geometry3d/plane.py @@ -74,9 +74,9 @@ def from_dict(cls, data): """ x = None if 'x' in data and data['x'] is not None: - x = Vector3D(data['x'][0], data['x'][1], data['x'][2]) - return cls(Vector3D(data['n'][0], data['n'][1], data['n'][2]), - Point3D(data['o'][0], data['o'][1], data['o'][2]), x) + x = Vector3D.from_array(data['x']) + return cls(Vector3D.from_array(data['n']), + Point3D.from_array(data['o']), x) @classmethod def from_three_points(cls, o, p2, p3): @@ -356,9 +356,9 @@ def duplicate(self): def to_dict(self): """Get Plane as a dictionary.""" return {'type': 'Plane', - 'n': (self.n.x, self.n.y, self.n.z), - 'o': (self.o.x, self.o.y, self.o.z), - 'x': (self.x.x, self.x.y, self.x.z)} + 'n': self.n.to_array(), + 'o': self.o.to_array(), + 'x': self.x.to_array()} def __copy__(self): return self.__class__(self.n, self.o) diff --git a/ladybug_geometry/geometry3d/pointvector.py b/ladybug_geometry/geometry3d/pointvector.py index 94e6ff15..b4c0bc97 100644 --- a/ladybug_geometry/geometry3d/pointvector.py +++ b/ladybug_geometry/geometry3d/pointvector.py @@ -44,6 +44,16 @@ def from_dict(cls, data): """ return cls(data['x'], data['y'], data['z']) + @classmethod + def from_array(cls, array): + """Initialize a Vector3D/Point3D from an array. + + Args: + array: A tuple or list with three numbers representing the x, y and z + values of the point. + """ + return cls(array[0], array[1], array[2]) + @property def x(self): """Get the X coordinate.""" @@ -152,6 +162,10 @@ def to_dict(self): 'y': self.y, 'z': self.z} + def to_array(self): + """Get Vector3D/Point3D as a tuple of three numbers""" + return (self.x, self.y, self.z) + def _cast_to_float(self, value): """Ensure that an input coordinate value is a float.""" try: @@ -322,20 +336,6 @@ class Point3D(Vector3D): """ __slots__ = () - @classmethod - def from_array(cls, array): - """Initialize a Point3D from an array. - - Args: - array: A tuple or list with three numbers representing the x, y and z - values of the point. - """ - return cls(array[0], array[1], array[2]) - - def to_array(self): - """Get Point3D as a tuple of three numbers""" - return (self.x, self.y, self.z) - def move(self, moving_vec): """Get a point that has been moved along a vector. diff --git a/ladybug_geometry/geometry3d/polyface.py b/ladybug_geometry/geometry3d/polyface.py index a4ef0ff0..70b04e38 100644 --- a/ladybug_geometry/geometry3d/polyface.py +++ b/ladybug_geometry/geometry3d/polyface.py @@ -135,7 +135,7 @@ def from_dict(cls, data): else: edge_information = None - return cls(tuple(Point3D(pt[0], pt[1], pt[2]) for pt in data['vertices']), + return cls(tuple(Point3D.from_array(pt) for pt in data['vertices']), data['face_indices'], edge_information) @classmethod @@ -155,7 +155,7 @@ def from_faces(cls, faces, tolerance=0): face_indices = [] # collection of face indices for f in faces: ind = [] - loops = (f.boundary,) if not f.has_holes else (f.boundary,) + f.holes + loops = [f.boundary] if not f.has_holes else [f.boundary] + f.holes for j, loop in enumerate(loops): ind.append([]) for v in loop: @@ -770,10 +770,10 @@ def to_dict(self, include_edge_information=True): it is de-serialized. Default True. """ base = {'type': 'Polyface3D', - 'vertices': [(v.x, v.y, v.z) for v in self.vertices], + 'vertices': [v.to_array() for v in self.vertices], 'face_indices': self.face_indices} if include_edge_information: - base['edge_information'] = self.edge_information + base['edge_information'] = self.edge_information return base def _get_edge_type(self, edge_type): From 566e7b5b674818497b93e590db917d29ca1e13af Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 21 Nov 2019 10:44:12 -0500 Subject: [PATCH 2/3] Revert "fix(package): Use from_array()/ to_array() in dict functions" This reverts commit 2ae3adb197be10422205cc6d877d754d0dd5f5e7. From a1c6a5c0f017fb5cd626ffc8ade18bd977b29238 Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 21 Nov 2019 16:53:17 -0500 Subject: [PATCH 3/3] fix(polyface): Fix from_faces bug --- ladybug_geometry/geometry3d/polyface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ladybug_geometry/geometry3d/polyface.py b/ladybug_geometry/geometry3d/polyface.py index 70b04e38..1ccaa57a 100644 --- a/ladybug_geometry/geometry3d/polyface.py +++ b/ladybug_geometry/geometry3d/polyface.py @@ -155,7 +155,7 @@ def from_faces(cls, faces, tolerance=0): face_indices = [] # collection of face indices for f in faces: ind = [] - loops = [f.boundary] if not f.has_holes else [f.boundary] + f.holes + loops = (f.boundary,) if not f.has_holes else (f.boundary,) + f.holes for j, loop in enumerate(loops): ind.append([]) for v in loop: