diff --git a/city_model_structure/attributes/surface.py b/city_model_structure/attributes/surface.py index ac3c5dd5..eab0d10f 100644 --- a/city_model_structure/attributes/surface.py +++ b/city_model_structure/attributes/surface.py @@ -16,17 +16,17 @@ class Surface: """ Surface class """ - def __init__(self, coordinates, holes_coordinates=None, surface_type=None, name=None, swr='0.2', remove_last=True): + def __init__(self, coordinates, holes_coordinates=None, surface_type=None, name=None, swr='0.2'): self._coordinates = coordinates self._holes_coordinates = holes_coordinates self._type = surface_type self._name = name self._swr = swr - self._remove_last = remove_last self._points = None self._points_list = None self._holes_points = None self._holes_points_list = None + self._perimeter_points = None self._azimuth = None self._inclination = None self._area_above_ground = None @@ -40,7 +40,6 @@ class Surface: self._perimeter_surface = None self._hole_surfaces = None self._solid_surface = None - self._perimeter_vertices = None def parent(self, parent, surface_id): """ @@ -82,32 +81,32 @@ class Surface: @property def points(self) -> np.ndarray: """ - Surface point coordinates list [x, y, z, x, y, z,...] + Solid surface point matrix [[x, y, z],[x, y, z],...] :return: np.ndarray """ if self._points is None: self._points = np.fromstring(self._coordinates, dtype=float, sep=' ') - self._points = gh.to_points_matrix(self._points, self._remove_last) + self._points = gh.to_points_matrix(self._points) return self._points @property def holes_points(self) -> [np.ndarray]: """ - Surface point coordinates list [x, y, z, x, y, z,...] + Holes surfaces point matrices [[[x, y, z],[x, y, z],...]] :return: np.ndarray """ if self._holes_coordinates is not None: self._holes_points = [] for hole_coordinates in self._holes_coordinates: hole_points = np.fromstring(hole_coordinates, dtype=float, sep=' ') - hole_points = gh.to_points_matrix(hole_points, self._remove_last) + hole_points = gh.to_points_matrix(hole_points) self._holes_points.append(hole_points) return self._holes_points @property def points_list(self) -> np.ndarray: """ - Surface point matrix [[x, y, z],[x, y, z],...] + Solid surface point coordinates list [x, y, z, x, y, z,...] :return: np.ndarray """ if self._points_list is None: @@ -118,7 +117,7 @@ class Surface: @property def holes_points_list(self) -> np.ndarray: """ - Surface point matrix [[x, y, z],[x, y, z],...] + Holes surfaces point coordinates list [x, y, z, x, y, z,...] :return: np.ndarray """ if self._holes_coordinates is not None: @@ -274,7 +273,7 @@ class Surface: :return: Polygon """ if self._perimeter_surface is None: - self._perimeter_surface = Polygon(self.perimeter_vertices) + self._perimeter_surface = Polygon(self.perimeter_points) return self._perimeter_surface @property @@ -301,43 +300,37 @@ class Surface: self._hole_surfaces = None else: self._hole_surfaces = [] - for hole_vertices in self.holes_points: - self._hole_surfaces.append(Polygon(hole_vertices)) + for hole_points in self.holes_points: + self._hole_surfaces.append(Polygon(hole_points)) return self._hole_surfaces @property - def perimeter_vertices(self) -> np.ndarray: + def perimeter_points(self) -> np.ndarray: """ - vertices of the perimeter organized in the same order as in coordinates - :return: + Matrix of points of the perimeter in the same order as in coordinates [[x, y, z],[x, y, z],...] + :return: np.ndarray """ - if self._perimeter_vertices is None: + if self._perimeter_points is None: if self.holes_points is None: - self._perimeter_vertices = self.points + self._perimeter_points = self.points else: - first_point = True - for point in self.points: - point_of_hole = False - for hole_points in self.holes_points: - for hole_point in hole_points: - if gh().almost_equal(0.0, point, hole_point): - point_of_hole = True - if not point_of_hole: - if first_point: - self._perimeter_vertices = np.array([point]) - first_point = False - else: - self._perimeter_vertices = np.append(self._perimeter_vertices, [point], axis=0) + _perimeter_coordinates = self._coordinates + for hole_points in self.holes_points: + _hole = np.append(hole_points, hole_points[0]) + _closed_hole = ' '.join(str(e) for e in [*_hole[:]]) + # add a mark 'M' to ensure that the recombination of points does not provoke errors in finding holes + _perimeter_coordinates = _perimeter_coordinates.replace(_closed_hole, 'M') + _perimeter_coordinates = _perimeter_coordinates.replace('M', '') + self._perimeter_points = np.fromstring(_perimeter_coordinates, dtype=float, sep=' ') + self._perimeter_points = gh.to_points_matrix(self._perimeter_points) # remove duplicated points - pv = np.array([self._perimeter_vertices[0]]) - for point in self._perimeter_vertices: + pv = np.array([self._perimeter_points[0]]) + for point in self._perimeter_points: duplicated_point = False for p in pv: if gh().almost_equal(0.0, p, point): duplicated_point = True if not duplicated_point: pv = np.append(pv, [point], axis=0) - self._perimeter_vertices = pv - if not self._remove_last: - self._perimeter_vertices = np.append(self._perimeter_vertices, [self._perimeter_vertices[0]], axis=0) - return self._perimeter_vertices + self._perimeter_points = pv + return self._perimeter_points diff --git a/helpers/geometry_helper.py b/helpers/geometry_helper.py index 3f0e62f2..0029a16a 100644 --- a/helpers/geometry_helper.py +++ b/helpers/geometry_helper.py @@ -2,7 +2,7 @@ Geometry helper SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca -Contributors Pilar Monsalvete pilar_monsalvete@yahoo.es +Contributors Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca """ import sys import math @@ -99,17 +99,14 @@ class GeometryHelper: return True @staticmethod - def to_points_matrix(points, remove_last=False): + def to_points_matrix(points): """ Transform a point vector into a point matrix :param points: [x, y, z, x, y, z ...] - :param remove_last: Boolean :return: [[x,y,z],[x,y,z]...] """ rows = points.size // 3 points = points.reshape(rows, 3) - if remove_last: - points = np.delete(points, rows - 1, 0) return points @staticmethod diff --git a/tests/test_geometry_factory.py b/tests/test_geometry_factory.py index 3a31ccb8..935e6a5e 100644 --- a/tests/test_geometry_factory.py +++ b/tests/test_geometry_factory.py @@ -249,16 +249,18 @@ class TestGeometryFactory(TestCase): def test_surface(self): coordinates = '0.0 0.0 0.0 0.0 4.0 0.0 4.0 4.0 0.0 4.0 0.0 0.0 0.0 0.0 0.0 ' \ '1.0 1.0 0.0 2.0 1.0 0.0 2.0 2.0 0.0 1.0 2.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 ' \ - '2.0 2.0 0.0 3.0 2.0 0.0 3.0 3.0 0.0 2.0 3.0 0.0 2.0 2.0 0.0 0.0 0.0 0.0' - holes_coordinates = ['1.0 1.0 0.0 2.0 1.0 0.0 2.0 2.0 0.0 1.0 2.0 0.0 1.0 1.0 0.0', - '2.0 2.0 0.0 3.0 2.0 0.0 3.0 3.0 0.0 2.0 3.0 0.0 2.0 2.0 0.0'] - surface = Surface(coordinates, holes_coordinates=holes_coordinates, remove_last=True) - print(surface.points) + '2.0 2.0 0.0 3.0 2.0 0.0 3.0 3.0 0.0 2.0 3.0 0.0 2.0 2.0 0.0' + holes_coordinates = ['1.0 1.0 0.0 2.0 1.0 0.0 2.0 2.0 0.0 1.0 2.0 0.0', + '2.0 2.0 0.0 3.0 2.0 0.0 3.0 3.0 0.0 2.0 3.0 0.0'] + surface = Surface(coordinates, holes_coordinates=holes_coordinates) + print('solid:', surface.points) print(surface.holes_points) - print(surface.perimeter_vertices) - print(surface.hole_surfaces[1].area) - print(surface.perimeter_surface.area) - print(surface.solid_surface.area) - print(surface.hole_surfaces[1].normal) - print(surface.perimeter_surface.normal) - print(surface.solid_surface.normal) + print('perimeter:', surface.perimeter_points) + for i in range(0, len(holes_coordinates)): + print(surface.hole_surfaces[i].area) + print('perimeter:', surface.perimeter_surface.area) + print('solid:', surface.solid_surface.area) + for i in range(0, len(holes_coordinates)): + print(surface.hole_surfaces[i].normal) + print('perimeter:', surface.perimeter_surface.normal) + print('solid:', surface.solid_surface.normal)