forked from s_ranjbar/city_retrofit
added class Point and used in polygon.py
This commit is contained in:
parent
b319ae50dc
commit
6b7dac8123
32
city_model_structure/attributes/point.py
Normal file
32
city_model_structure/attributes/point.py
Normal 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
|
|
@ -9,6 +9,7 @@ from typing import List
|
|||
import sys
|
||||
import numpy as np
|
||||
import math
|
||||
from city_model_structure.attributes.point import Point
|
||||
|
||||
|
||||
class Polygon:
|
||||
|
@ -16,20 +17,59 @@ class Polygon:
|
|||
Polygon class
|
||||
"""
|
||||
|
||||
def __init__(self, points):
|
||||
# def __init__(self, points):
|
||||
def __init__(self, coordinates):
|
||||
|
||||
self._area = None
|
||||
self._points = points
|
||||
# self._points = points
|
||||
self._points = None
|
||||
self._points_list = 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
|
||||
def points(self) -> np.ndarray:
|
||||
def points(self) -> List[Point]:
|
||||
"""
|
||||
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
|
||||
|
||||
@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
|
||||
def points_list(self) -> np.ndarray:
|
||||
"""
|
||||
|
@ -37,10 +77,21 @@ class Polygon:
|
|||
:return: np.ndarray
|
||||
"""
|
||||
if self._points_list is None:
|
||||
s = self.points
|
||||
s = self.coordinates
|
||||
self._points_list = np.reshape(s, len(s) * 3)
|
||||
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
|
||||
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')
|
||||
return 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)):
|
||||
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)
|
||||
if alpha == 0:
|
||||
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:
|
||||
# Already horizontal
|
||||
for point in self.points:
|
||||
horizontal_points.append([point[0], point[1], 0])
|
||||
horizontal_points.append([point.coordinates[0], point.coordinates[1], 0])
|
||||
else:
|
||||
alpha = self._angle_between_vectors(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')
|
||||
else:
|
||||
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)
|
||||
return horizontal_points
|
||||
|
||||
|
@ -117,7 +168,7 @@ class Polygon:
|
|||
:return: np.ndarray
|
||||
"""
|
||||
if self._normal is None:
|
||||
points = self.points
|
||||
points = self.coordinates
|
||||
# todo: IF THE FIRST ONE IS 0, START WITH THE NEXT
|
||||
point_origin = points[len(points)-2]
|
||||
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])
|
||||
rest_points = []
|
||||
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):
|
||||
ears.append(ear)
|
||||
point_to_remove = concave_points[i]
|
||||
|
@ -357,19 +408,19 @@ class Polygon:
|
|||
area_points = 0
|
||||
point_is_not_vertex = True
|
||||
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
|
||||
break
|
||||
if point_is_not_vertex:
|
||||
for i in range(0, 3):
|
||||
if i != 2:
|
||||
new_points = ear.points[i][:]
|
||||
new_points = np.append(new_points, ear.points[i + 1][:])
|
||||
new_points = ear.coordinates[i][:]
|
||||
new_points = np.append(new_points, ear.coordinates[i + 1][:])
|
||||
new_points = np.append(new_points, point[:])
|
||||
else:
|
||||
new_points = ear.points[i][:]
|
||||
new_points = ear.coordinates[i][:]
|
||||
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
|
||||
new_points = new_points.reshape(rows, 3)
|
||||
new_triangle = Polygon(new_points)
|
||||
|
@ -460,3 +511,64 @@ class Polygon:
|
|||
cosine = -1
|
||||
alpha = math.acos(cosine)
|
||||
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
|
||||
|
|
|
@ -59,7 +59,7 @@ class Polyhedron:
|
|||
"""
|
||||
if self._vertices is None:
|
||||
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:
|
||||
found = False
|
||||
for vertex_2 in self._vertices:
|
||||
|
@ -88,14 +88,14 @@ class Polyhedron:
|
|||
for polygon in self._polygons:
|
||||
|
||||
face = []
|
||||
points = polygon.points
|
||||
points = polygon.coordinates
|
||||
if len(points) != 3:
|
||||
sub_polygons = polygon.triangulate()
|
||||
# todo: I modified this! To be checked @Guille
|
||||
if len(sub_polygons) >= 1:
|
||||
for sub_polygon in sub_polygons:
|
||||
face = []
|
||||
points = sub_polygon.points
|
||||
points = sub_polygon.coordinates
|
||||
for point in points:
|
||||
face.append(self._position_of(point, face))
|
||||
self._faces.append(face)
|
||||
|
@ -143,7 +143,7 @@ class Polyhedron:
|
|||
if self._max_z is None:
|
||||
self._max_z = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
self._max_z = max(self._max_z, point[2])
|
||||
return self._max_z
|
||||
|
||||
|
@ -156,7 +156,7 @@ class Polyhedron:
|
|||
if self._max_y is None:
|
||||
self._max_y = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
if self._max_y < point[1]:
|
||||
self._max_y = point[1]
|
||||
return self._max_y
|
||||
|
@ -170,7 +170,7 @@ class Polyhedron:
|
|||
if self._max_x is None:
|
||||
self._max_x = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
self._max_x = max(self._max_x, point[0])
|
||||
return self._max_x
|
||||
|
||||
|
@ -183,7 +183,7 @@ class Polyhedron:
|
|||
if self._min_z is None:
|
||||
self._min_z = self.max_z
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_z > point[2]:
|
||||
self._min_z = point[2]
|
||||
return self._min_z
|
||||
|
@ -197,7 +197,7 @@ class Polyhedron:
|
|||
if self._min_y is None:
|
||||
self._min_y = self.max_y
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_y > point[1]:
|
||||
self._min_y = point[1]
|
||||
return self._min_y
|
||||
|
@ -211,7 +211,7 @@ class Polyhedron:
|
|||
if self._min_x is None:
|
||||
self._min_x = self.max_x
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_x > point[0]:
|
||||
self._min_x = point[0]
|
||||
return self._min_x
|
||||
|
|
|
@ -88,7 +88,7 @@ class Surface:
|
|||
else:
|
||||
axis = 2
|
||||
max_coordinate = ''
|
||||
for point in self.perimeter_polygon.points:
|
||||
for point in self.perimeter_polygon.coordinates:
|
||||
if max_coordinate == '':
|
||||
max_coordinate = point[axis]
|
||||
elif max_coordinate < point[axis]:
|
||||
|
@ -103,7 +103,7 @@ class Surface:
|
|||
else:
|
||||
axis = 2
|
||||
min_coordinate = ''
|
||||
for point in self.perimeter_polygon.points:
|
||||
for point in self.perimeter_polygon.coordinates:
|
||||
if min_coordinate == '':
|
||||
min_coordinate = point[axis]
|
||||
elif min_coordinate > point[axis]:
|
||||
|
|
|
@ -58,7 +58,7 @@ class CityObject:
|
|||
City object volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
return self.detailed_polyhedron.volume
|
||||
return self.simplified_polyhedron.volume
|
||||
|
||||
@property
|
||||
def detailed_polyhedron(self) -> Polyhedron:
|
||||
|
|
|
@ -231,9 +231,9 @@ class EnergyAde:
|
|||
'@gml:id': f'PolyId{surface.name}_0',
|
||||
'gml:posList': {
|
||||
'@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))} '
|
||||
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:posList': {
|
||||
'@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))} '
|
||||
f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points[0]))}'
|
||||
f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.coordinates[0]))}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ class Idf:
|
|||
return points_list
|
||||
|
||||
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,
|
||||
num_stories=int(building.storeys_above_ground))
|
||||
self._add_heating_system(building)
|
||||
|
@ -162,7 +162,7 @@ class Idf:
|
|||
wall = self._idf.newidfobject(self._SURFACE, Name=f'{building.name}-{boundary.surface.name}',
|
||||
Surface_Type=idf_surface, Zone_Name=zone_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)
|
||||
index += 1
|
||||
self._add_heating_system(building)
|
||||
|
|
|
@ -48,7 +48,7 @@ class SimplifiedRadiosityAlgorithm:
|
|||
'@id': f'{surface.id}',
|
||||
'@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)
|
||||
surface_dict[f'V{point_index}'] = {
|
||||
'@x': f'{point[0]}',
|
||||
|
|
|
@ -77,9 +77,9 @@ class ConstructionHelper:
|
|||
nrcan_function_default_value = 'residential'
|
||||
nrcan_window_types = [cte.WINDOW]
|
||||
nrcan_construction_types = {
|
||||
cte.WALL: 'exterior wall',
|
||||
cte.GROUND_WALL: 'ground wall',
|
||||
cte.GROUND: 'exterior slab',
|
||||
cte.WALL: 'wall',
|
||||
cte.GROUND_WALL: 'basement_wall',
|
||||
cte.GROUND: 'floor',
|
||||
cte.ATTIC_FLOOR: 'attic floor',
|
||||
cte.INTERIOR_SLAB: 'interior slab',
|
||||
cte.ROOF: 'roof'
|
||||
|
|
Loading…
Reference in New Issue
Block a user