added class Point and used in polygon.py

This commit is contained in:
Pilar 2021-06-22 13:16:17 -04:00
parent b319ae50dc
commit 6b7dac8123
9 changed files with 182 additions and 38 deletions

View File

@ -0,0 +1,32 @@
"""
Point module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import math
class Point:
"""
Point class
"""
def __init__(self, coordinates):
self._coordinates = coordinates
@property
def coordinates(self):
return self._coordinates
def distance_to_point(self, other_point):
"""
distance between points in an n-D Euclidean space
:param other_point: point or vertex
:return: float
"""
power = 0
for dimension in range(0, len(self.coordinates)):
power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2)
distance = math.sqrt(power)
return distance

View File

@ -9,6 +9,7 @@ from typing import List
import sys import sys
import numpy as np import numpy as np
import math import math
from city_model_structure.attributes.point import Point
class Polygon: class Polygon:
@ -16,20 +17,59 @@ class Polygon:
Polygon class Polygon class
""" """
def __init__(self, points): # def __init__(self, points):
def __init__(self, coordinates):
self._area = None self._area = None
self._points = points # self._points = points
self._points = None
self._points_list = None self._points_list = None
self._normal = None self._normal = None
self._inverse = None
self._edges = None
# self._coordinates = None
self._coordinates = coordinates
# @property
# def points(self) -> List[Point]:
# """
# List of points belonging to the polygon [[x, y, z],...]
# :return: List[Point]
# """
# return self._points
#
# @property
# def coordinates(self) -> List[np.ndarray]:
# """
# List of points in the shape of its coordinates belonging to the polygon [[x, y, z],...]
# :return: np.array
# """
# if self._coordinates is None:
# self._coordinates = []
# for point in self.points:
# self._coordinates.append(np.array(point.coordinates))
# return self._coordinates
#
@property @property
def points(self) -> np.ndarray: def points(self) -> List[Point]:
""" """
List of points belonging to the polygon [[x, y, z],...] List of points belonging to the polygon [[x, y, z],...]
:return: ndarray[coordinates] :return: List[Point]
""" """
if self._points is None:
self._points = []
for coordinate in self.coordinates:
self._points.append(Point(coordinate))
return self._points return self._points
@property
def coordinates(self) -> List[np.ndarray]:
"""
List of points in the shape of its coordinates belonging to the polygon [[x, y, z],...]
:return: np.array
"""
return self._coordinates
@property @property
def points_list(self) -> np.ndarray: def points_list(self) -> np.ndarray:
""" """
@ -37,10 +77,21 @@ class Polygon:
:return: np.ndarray :return: np.ndarray
""" """
if self._points_list is None: if self._points_list is None:
s = self.points s = self.coordinates
self._points_list = np.reshape(s, len(s) * 3) self._points_list = np.reshape(s, len(s) * 3)
return self._points_list return self._points_list
@property
def edges(self):
if self._edges is None:
self._edges = []
for i in range(0, len(self.points)-1):
point_1 = self.points[i]
point_2 = self.points[i+1]
self._edges.append([point_1, point_2])
self._edges.append([self.points[len(self.points)-1], self.points[0]])
return self._edges
@property @property
def area(self): def area(self):
""" """
@ -53,9 +104,9 @@ class Polygon:
sys.stderr.write('Warning: the area of a line or point cannot be calculated 1. Area = 0\n') sys.stderr.write('Warning: the area of a line or point cannot be calculated 1. Area = 0\n')
return 0 return 0
alpha = 0 alpha = 0
vec_1 = self.points[1] - self.points[0] vec_1 = self.points[1].coordinates - self.points[0].coordinates
for i in range(2, len(self.points)): for i in range(2, len(self.points)):
vec_2 = self.points[i] - self.points[0] vec_2 = self.points[i].coordinates - self.points[0].coordinates
alpha += self._angle_between_vectors(vec_1, vec_2) alpha += self._angle_between_vectors(vec_1, vec_2)
if alpha == 0: if alpha == 0:
sys.stderr.write('Warning: the area of a line or point cannot be calculated 2. Area = 0\n') sys.stderr.write('Warning: the area of a line or point cannot be calculated 2. Area = 0\n')
@ -87,7 +138,7 @@ class Polygon:
if x == 0 and y == 0: if x == 0 and y == 0:
# Already horizontal # Already horizontal
for point in self.points: for point in self.points:
horizontal_points.append([point[0], point[1], 0]) horizontal_points.append([point.coordinates[0], point.coordinates[1], 0])
else: else:
alpha = self._angle_between_vectors(normal_vector, z_vector) alpha = self._angle_between_vectors(normal_vector, z_vector)
rotation_line = np.cross(normal_vector, z_vector) rotation_line = np.cross(normal_vector, z_vector)
@ -106,7 +157,7 @@ class Polygon:
sys.stderr.write('Warning: rotation base matrix returned None\n') sys.stderr.write('Warning: rotation base matrix returned None\n')
else: else:
for point in self.points: for point in self.points:
new_point = np.matmul(rotation_base_matrix, point) new_point = np.matmul(rotation_base_matrix, point.coordinates)
horizontal_points.append(new_point) horizontal_points.append(new_point)
return horizontal_points return horizontal_points
@ -117,7 +168,7 @@ class Polygon:
:return: np.ndarray :return: np.ndarray
""" """
if self._normal is None: if self._normal is None:
points = self.points points = self.coordinates
# todo: IF THE FIRST ONE IS 0, START WITH THE NEXT # todo: IF THE FIRST ONE IS 0, START WITH THE NEXT
point_origin = points[len(points)-2] point_origin = points[len(points)-2]
vector_1 = points[len(points)-1] - point_origin vector_1 = points[len(points)-1] - point_origin
@ -200,7 +251,7 @@ class Polygon:
ear = self._triangle(points_list, total_points_list, concave_points[i]) ear = self._triangle(points_list, total_points_list, concave_points[i])
rest_points = [] rest_points = []
for p in total_points_list: for p in total_points_list:
rest_points.append(list(self.points[p])) rest_points.append(list(self.coordinates[p]))
if self._is_ear(ear, rest_points): if self._is_ear(ear, rest_points):
ears.append(ear) ears.append(ear)
point_to_remove = concave_points[i] point_to_remove = concave_points[i]
@ -357,19 +408,19 @@ class Polygon:
area_points = 0 area_points = 0
point_is_not_vertex = True point_is_not_vertex = True
for i in range(0, 3): for i in range(0, 3):
if abs(np.linalg.norm(point) - np.linalg.norm(ear.points[i])) < 0.0001: if abs(np.linalg.norm(point) - np.linalg.norm(ear.coordinates[i])) < 0.0001:
point_is_not_vertex = False point_is_not_vertex = False
break break
if point_is_not_vertex: if point_is_not_vertex:
for i in range(0, 3): for i in range(0, 3):
if i != 2: if i != 2:
new_points = ear.points[i][:] new_points = ear.coordinates[i][:]
new_points = np.append(new_points, ear.points[i + 1][:]) new_points = np.append(new_points, ear.coordinates[i + 1][:])
new_points = np.append(new_points, point[:]) new_points = np.append(new_points, point[:])
else: else:
new_points = ear.points[i][:] new_points = ear.coordinates[i][:]
new_points = np.append(new_points, point[:]) new_points = np.append(new_points, point[:])
new_points = np.append(new_points, ear.points[0][:]) new_points = np.append(new_points, ear.coordinates[0][:])
rows = new_points.size // 3 rows = new_points.size // 3
new_points = new_points.reshape(rows, 3) new_points = new_points.reshape(rows, 3)
new_triangle = Polygon(new_points) new_triangle = Polygon(new_points)
@ -460,3 +511,64 @@ class Polygon:
cosine = -1 cosine = -1
alpha = math.acos(cosine) alpha = math.acos(cosine)
return alpha return alpha
@property
def inverse(self):
if self._inverse is None:
self._inverse = self.points[::-1]
return self._inverse
# def divide(self, polygon):
# return polygon_1, polygon_2, intersection
def reshape(self, triangles) -> Polygon:
edges_list = []
for i in range(0, len(triangles)):
for edge in triangles[i].edges:
print('edge')
print(edge[0].coordinates, edge[1].coordinates)
if not self._edge_in_edges_list(edge, edges_list):
edges_list.append(edge)
print('list')
for e in edges_list:
print(e[0].coordinates, e[1].coordinates)
else:
print('remove')
edges_list = self._remove_from_list(edge, edges_list)
for e in edges_list:
print(e[0].coordinates, e[1].coordinates)
points = self._order_points(edges_list)
return Polygon(points)
@staticmethod
def _edge_in_edges_list(edge, edges_list):
for ed in edges_list:
if (ed[0].distance_to_point(edge[0]) == 0 and ed[1].distance_to_point(edge[1]) == 0) or\
(ed[1].distance_to_point(edge[0]) == 0 and ed[0].distance_to_point(edge[1]) == 0):
return True
return False
@staticmethod
def _order_points(edges_list):
points = edges_list[0]
for i in range(1, len(edges_list)):
point_1 = edges_list[i][0]
point_2 = points[len(points)-1]
if point_1.distance_to_point(point_2) == 0:
points.append(edges_list[i][1])
points.remove(points[len(points)-1])
array_points = []
for point in points:
print(point.coordinates)
array_points.append(point.coordinates)
return np.array(array_points)
@staticmethod
def _remove_from_list(edge, edges_list):
new_list = []
for ed in edges_list:
if not((ed[0].distance_to_point(edge[0]) == 0 and ed[1].distance_to_point(edge[1]) == 0) or
(ed[1].distance_to_point(edge[0]) == 0 and ed[0].distance_to_point(edge[1]) == 0)):
new_list.append(ed)
return new_list

View File

@ -59,7 +59,7 @@ class Polyhedron:
""" """
if self._vertices is None: if self._vertices is None:
vertices, self._vertices = [], [] vertices, self._vertices = [], []
_ = [vertices.extend(s.points) for s in self._polygons] _ = [vertices.extend(s.coordinates) for s in self._polygons]
for vertex_1 in vertices: for vertex_1 in vertices:
found = False found = False
for vertex_2 in self._vertices: for vertex_2 in self._vertices:
@ -88,14 +88,14 @@ class Polyhedron:
for polygon in self._polygons: for polygon in self._polygons:
face = [] face = []
points = polygon.points points = polygon.coordinates
if len(points) != 3: if len(points) != 3:
sub_polygons = polygon.triangulate() sub_polygons = polygon.triangulate()
# todo: I modified this! To be checked @Guille # todo: I modified this! To be checked @Guille
if len(sub_polygons) >= 1: if len(sub_polygons) >= 1:
for sub_polygon in sub_polygons: for sub_polygon in sub_polygons:
face = [] face = []
points = sub_polygon.points points = sub_polygon.coordinates
for point in points: for point in points:
face.append(self._position_of(point, face)) face.append(self._position_of(point, face))
self._faces.append(face) self._faces.append(face)
@ -143,7 +143,7 @@ class Polyhedron:
if self._max_z is None: if self._max_z is None:
self._max_z = ConfigurationHelper().min_coordinate self._max_z = ConfigurationHelper().min_coordinate
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
self._max_z = max(self._max_z, point[2]) self._max_z = max(self._max_z, point[2])
return self._max_z return self._max_z
@ -156,7 +156,7 @@ class Polyhedron:
if self._max_y is None: if self._max_y is None:
self._max_y = ConfigurationHelper().min_coordinate self._max_y = ConfigurationHelper().min_coordinate
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
if self._max_y < point[1]: if self._max_y < point[1]:
self._max_y = point[1] self._max_y = point[1]
return self._max_y return self._max_y
@ -170,7 +170,7 @@ class Polyhedron:
if self._max_x is None: if self._max_x is None:
self._max_x = ConfigurationHelper().min_coordinate self._max_x = ConfigurationHelper().min_coordinate
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
self._max_x = max(self._max_x, point[0]) self._max_x = max(self._max_x, point[0])
return self._max_x return self._max_x
@ -183,7 +183,7 @@ class Polyhedron:
if self._min_z is None: if self._min_z is None:
self._min_z = self.max_z self._min_z = self.max_z
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
if self._min_z > point[2]: if self._min_z > point[2]:
self._min_z = point[2] self._min_z = point[2]
return self._min_z return self._min_z
@ -197,7 +197,7 @@ class Polyhedron:
if self._min_y is None: if self._min_y is None:
self._min_y = self.max_y self._min_y = self.max_y
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
if self._min_y > point[1]: if self._min_y > point[1]:
self._min_y = point[1] self._min_y = point[1]
return self._min_y return self._min_y
@ -211,7 +211,7 @@ class Polyhedron:
if self._min_x is None: if self._min_x is None:
self._min_x = self.max_x self._min_x = self.max_x
for polygon in self._polygons: for polygon in self._polygons:
for point in polygon.points: for point in polygon.coordinates:
if self._min_x > point[0]: if self._min_x > point[0]:
self._min_x = point[0] self._min_x = point[0]
return self._min_x return self._min_x

View File

@ -88,7 +88,7 @@ class Surface:
else: else:
axis = 2 axis = 2
max_coordinate = '' max_coordinate = ''
for point in self.perimeter_polygon.points: for point in self.perimeter_polygon.coordinates:
if max_coordinate == '': if max_coordinate == '':
max_coordinate = point[axis] max_coordinate = point[axis]
elif max_coordinate < point[axis]: elif max_coordinate < point[axis]:
@ -103,7 +103,7 @@ class Surface:
else: else:
axis = 2 axis = 2
min_coordinate = '' min_coordinate = ''
for point in self.perimeter_polygon.points: for point in self.perimeter_polygon.coordinates:
if min_coordinate == '': if min_coordinate == '':
min_coordinate = point[axis] min_coordinate = point[axis]
elif min_coordinate > point[axis]: elif min_coordinate > point[axis]:

View File

@ -58,7 +58,7 @@ class CityObject:
City object volume in cubic meters City object volume in cubic meters
:return: float :return: float
""" """
return self.detailed_polyhedron.volume return self.simplified_polyhedron.volume
@property @property
def detailed_polyhedron(self) -> Polyhedron: def detailed_polyhedron(self) -> Polyhedron:

View File

@ -231,9 +231,9 @@ class EnergyAde:
'@gml:id': f'PolyId{surface.name}_0', '@gml:id': f'PolyId{surface.name}_0',
'gml:posList': { 'gml:posList': {
'@srsDimension': '3', '@srsDimension': '3',
'@count': len(surface.solid_polygon.points) + 1, '@count': len(surface.solid_polygon.coordinates) + 1,
'#text': f'{" ".join(map(str, surface.solid_polygon.points_list))} ' '#text': f'{" ".join(map(str, surface.solid_polygon.points_list))} '
f'{" ".join(map(str, surface.solid_polygon.points[0]))}' f'{" ".join(map(str, surface.solid_polygon.coordinates[0]))}'
} }
} }
} }
@ -343,9 +343,9 @@ class EnergyAde:
'@gml:id': f'GML_{uuid.uuid4()}', '@gml:id': f'GML_{uuid.uuid4()}',
'gml:posList': { 'gml:posList': {
'@srsDimension': '3', '@srsDimension': '3',
'@count': len(thermal_boundary.surface.solid_polygon.points) + 1, '@count': len(thermal_boundary.surface.solid_polygon.coordinates) + 1,
'#text': f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points_list))} ' '#text': f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points_list))} '
f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points[0]))}' f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.coordinates[0]))}'
} }
} }
} }

View File

@ -145,7 +145,7 @@ class Idf:
return points_list return points_list
def add_block(self, building): def add_block(self, building):
_points = IdfHelper._matrix_to_2d_list(building.foot_print.points) _points = IdfHelper._matrix_to_2d_list(building.foot_print.coordinates)
self._idf.add_block(name=building.name, coordinates=_points, height=building.max_height, self._idf.add_block(name=building.name, coordinates=_points, height=building.max_height,
num_stories=int(building.storeys_above_ground)) num_stories=int(building.storeys_above_ground))
self._add_heating_system(building) self._add_heating_system(building)
@ -162,7 +162,7 @@ class Idf:
wall = self._idf.newidfobject(self._SURFACE, Name=f'{building.name}-{boundary.surface.name}', wall = self._idf.newidfobject(self._SURFACE, Name=f'{building.name}-{boundary.surface.name}',
Surface_Type=idf_surface, Zone_Name=zone_name, Surface_Type=idf_surface, Zone_Name=zone_name,
Construction_Name=boundary.construction_name) Construction_Name=boundary.construction_name)
coordinates = IdfHelper._matrix_to_list(boundary.surface.points) coordinates = IdfHelper._matrix_to_list(boundary.surface.coordinates)
wall.setcoords(coordinates) wall.setcoords(coordinates)
index += 1 index += 1
self._add_heating_system(building) self._add_heating_system(building)

View File

@ -48,7 +48,7 @@ class SimplifiedRadiosityAlgorithm:
'@id': f'{surface.id}', '@id': f'{surface.id}',
'@ShortWaveReflectance': f'{surface.swr}' '@ShortWaveReflectance': f'{surface.swr}'
} }
for point_index, point in enumerate(surface.perimeter_polygon.points): for point_index, point in enumerate(surface.perimeter_polygon.coordinates):
point = self._correct_point(point) point = self._correct_point(point)
surface_dict[f'V{point_index}'] = { surface_dict[f'V{point_index}'] = {
'@x': f'{point[0]}', '@x': f'{point[0]}',

View File

@ -77,9 +77,9 @@ class ConstructionHelper:
nrcan_function_default_value = 'residential' nrcan_function_default_value = 'residential'
nrcan_window_types = [cte.WINDOW] nrcan_window_types = [cte.WINDOW]
nrcan_construction_types = { nrcan_construction_types = {
cte.WALL: 'exterior wall', cte.WALL: 'wall',
cte.GROUND_WALL: 'ground wall', cte.GROUND_WALL: 'basement_wall',
cte.GROUND: 'exterior slab', cte.GROUND: 'floor',
cte.ATTIC_FLOOR: 'attic floor', cte.ATTIC_FLOOR: 'attic floor',
cte.INTERIOR_SLAB: 'interior slab', cte.INTERIOR_SLAB: 'interior slab',
cte.ROOF: 'roof' cte.ROOF: 'roof'