replace geometry helper with package
This commit is contained in:
parent
360b2e3636
commit
79e79f48c4
|
@ -1,80 +0,0 @@
|
|||
"""
|
||||
Plane module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import TypeVar
|
||||
import numpy as np
|
||||
|
||||
Point = TypeVar('Point')
|
||||
|
||||
|
||||
class Plane:
|
||||
"""
|
||||
Plane class
|
||||
"""
|
||||
|
||||
def __init__(self, origin, normal):
|
||||
self._origin = origin
|
||||
self._normal = normal
|
||||
self._equation = None
|
||||
self._opposite_normal = None
|
||||
|
||||
@property
|
||||
def origin(self) -> Point:
|
||||
"""
|
||||
Get plane origin point
|
||||
:return: Point
|
||||
"""
|
||||
return self._origin
|
||||
|
||||
@property
|
||||
def normal(self):
|
||||
"""
|
||||
Get plane normal [x, y, z]
|
||||
:return: np.ndarray
|
||||
"""
|
||||
return self._normal
|
||||
|
||||
@property
|
||||
def equation(self) -> (float, float, float, float):
|
||||
"""
|
||||
Get the plane equation components Ax + By + Cz + D = 0
|
||||
:return: (A, B, C, D)
|
||||
"""
|
||||
if self._equation is None:
|
||||
|
||||
a = self.normal[0]
|
||||
b = self.normal[1]
|
||||
c = self.normal[2]
|
||||
d = ((-1 * self.origin.coordinates[0]) * self.normal[0])
|
||||
d += ((-1 * self.origin.coordinates[1]) * self.normal[1])
|
||||
d += ((-1 * self.origin.coordinates[2]) * self.normal[2])
|
||||
self._equation = (a, b, c, d)
|
||||
return self._equation
|
||||
|
||||
def distance_to_point(self, point):
|
||||
"""
|
||||
Distance between the given point and the plane
|
||||
:return: float
|
||||
"""
|
||||
p = point
|
||||
e = self.equation
|
||||
denominator = np.abs((p[0] * e[0]) + (p[1] * e[1]) + (p[2] * e[2]) + e[3])
|
||||
numerator = np.sqrt((e[0]**2) + (e[1]**2) + (e[2]**2))
|
||||
return float(denominator / numerator)
|
||||
|
||||
@property
|
||||
def opposite_normal(self):
|
||||
"""
|
||||
get plane normal in the opposite direction [x, y, z]
|
||||
:return: np.ndarray
|
||||
"""
|
||||
if self._opposite_normal is None:
|
||||
coordinates = []
|
||||
for coordinate in self.normal:
|
||||
coordinates.append(-coordinate)
|
||||
self._opposite_normal = np.array(coordinates)
|
||||
return self._opposite_normal
|
|
@ -1,37 +0,0 @@
|
|||
"""
|
||||
Point module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder 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):
|
||||
"""
|
||||
Get point coordinates
|
||||
:return: [ndarray]
|
||||
"""
|
||||
return self._coordinates
|
||||
|
||||
def distance_to_point(self, other_point):
|
||||
"""
|
||||
Calculates 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
|
|
@ -1,452 +0,0 @@
|
|||
"""
|
||||
Polygon module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import math
|
||||
import sys
|
||||
from typing import List
|
||||
from hub.hub_logger import logger
|
||||
import numpy as np
|
||||
from trimesh import Trimesh
|
||||
import trimesh.intersections
|
||||
import trimesh.creation
|
||||
import trimesh.geometry
|
||||
from shapely.geometry.polygon import Polygon as shapley_polygon
|
||||
|
||||
from hub.city_model_structure.attributes.plane import Plane
|
||||
from hub.city_model_structure.attributes.point import Point
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class Polygon:
|
||||
"""
|
||||
Polygon class
|
||||
"""
|
||||
def __init__(self, coordinates):
|
||||
self._area = None
|
||||
self._points = None
|
||||
self._points_list = None
|
||||
self._normal = None
|
||||
self._inverse = None
|
||||
self._edges = None
|
||||
self._coordinates = coordinates
|
||||
self._triangles = None
|
||||
self._vertices = None
|
||||
self._faces = None
|
||||
self._plane = None
|
||||
|
||||
@property
|
||||
def points(self) -> List[Point]:
|
||||
"""
|
||||
Get the points belonging to the polygon [[x, y, z],...]
|
||||
:return: [Point]
|
||||
"""
|
||||
if self._points is None:
|
||||
self._points = []
|
||||
for coordinate in self.coordinates:
|
||||
self._points.append(Point(coordinate))
|
||||
return self._points
|
||||
|
||||
@property
|
||||
def plane(self) -> Plane:
|
||||
"""
|
||||
Get the polygon plane
|
||||
:return: Plane
|
||||
"""
|
||||
if self._plane is None:
|
||||
self._plane = Plane(normal=self.normal, origin=self.points[0])
|
||||
return self._plane
|
||||
|
||||
@property
|
||||
def coordinates(self) -> List[np.ndarray]:
|
||||
"""
|
||||
Get the points in the shape of its coordinates belonging to the polygon [[x, y, z],...]
|
||||
:return: [np.ndarray]
|
||||
"""
|
||||
return self._coordinates
|
||||
|
||||
def contains_point(self, point):
|
||||
"""
|
||||
Determines if the given point is contained by the current polygon
|
||||
:return: boolean
|
||||
"""
|
||||
# fixme: This method doesn't seems to work.
|
||||
n = len(self.vertices)
|
||||
angle_sum = 0
|
||||
for i in range(0, n):
|
||||
vector_0 = self.vertices[i]
|
||||
vector_1 = self.vertices[(i+1) % n]
|
||||
# set to origin
|
||||
vector_0[0] = vector_0[0] - point.coordinates[0]
|
||||
vector_0[1] = vector_0[1] - point.coordinates[1]
|
||||
vector_0[2] = vector_0[2] - point.coordinates[2]
|
||||
vector_1[0] = vector_1[0] - point.coordinates[0]
|
||||
vector_1[1] = vector_1[1] - point.coordinates[1]
|
||||
vector_1[2] = vector_1[2] - point.coordinates[2]
|
||||
module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
|
||||
|
||||
scalar_product = np.dot(vector_0, vector_1)
|
||||
angle = np.pi/2
|
||||
if module != 0:
|
||||
angle = abs(np.arcsin(scalar_product / module))
|
||||
angle_sum += angle
|
||||
return abs(angle_sum - math.pi*2) < cte.EPSILON
|
||||
|
||||
def contains_polygon(self, polygon):
|
||||
"""
|
||||
Determines if the given polygon is contained by the current polygon
|
||||
:return: boolean
|
||||
"""
|
||||
|
||||
for point in polygon.points:
|
||||
if not self.contains_point(point):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def points_list(self) -> np.ndarray:
|
||||
"""
|
||||
Get the solid surface point coordinates list [x, y, z, x, y, z,...]
|
||||
:return: np.ndarray
|
||||
"""
|
||||
if self._points_list is None:
|
||||
s = self.coordinates
|
||||
self._points_list = np.reshape(s, len(s) * 3)
|
||||
return self._points_list
|
||||
|
||||
@property
|
||||
def edges(self) -> List[List[Point]]:
|
||||
"""
|
||||
Get polygon edges list
|
||||
:return: [[Point]]
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Get surface area in square meters
|
||||
:return: float
|
||||
"""
|
||||
if self._area is None:
|
||||
self._area = 0
|
||||
for triangle in self.triangles:
|
||||
ab = np.zeros(3)
|
||||
ac = np.zeros(3)
|
||||
for i in range(0, 3):
|
||||
ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
|
||||
ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
|
||||
self._area += np.linalg.norm(np.cross(ab, ac)) / 2
|
||||
return self._area
|
||||
|
||||
@area.setter
|
||||
def area(self, value):
|
||||
self._area = value
|
||||
|
||||
@property
|
||||
def normal(self) -> np.ndarray:
|
||||
"""
|
||||
Get surface normal vector
|
||||
:return: np.ndarray
|
||||
"""
|
||||
if self._normal is None:
|
||||
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
|
||||
vector_2 = points[0] - point_origin
|
||||
vector_3 = points[1] - point_origin
|
||||
cross_product = np.cross(vector_1, vector_2)
|
||||
if np.linalg.norm(cross_product) != 0:
|
||||
cross_product = cross_product / np.linalg.norm(cross_product)
|
||||
alpha = self._angle_between_vectors(vector_1, vector_2)
|
||||
else:
|
||||
cross_product = [0, 0, 0]
|
||||
alpha = 0
|
||||
if len(points) == 3:
|
||||
return cross_product
|
||||
if np.linalg.norm(cross_product) == 0:
|
||||
return cross_product
|
||||
alpha += self._angle(vector_2, vector_3, cross_product)
|
||||
for i in range(0, len(points) - 4):
|
||||
vector_1 = points[i + 1] - point_origin
|
||||
vector_2 = points[i + 2] - point_origin
|
||||
alpha += self._angle(vector_1, vector_2, cross_product)
|
||||
vector_1 = points[len(points) - 1] - point_origin
|
||||
vector_2 = points[0] - point_origin
|
||||
if alpha < 0:
|
||||
cross_product = np.cross(vector_2, vector_1)
|
||||
else:
|
||||
cross_product = np.cross(vector_1, vector_2)
|
||||
self._normal = cross_product / np.linalg.norm(cross_product)
|
||||
return self._normal
|
||||
|
||||
@staticmethod
|
||||
def _angle(vector_1, vector_2, cross_product):
|
||||
"""
|
||||
alpha angle in radians
|
||||
:param vector_1: [float]
|
||||
:param vector_2: [float]
|
||||
:param cross_product: [float]
|
||||
:return: float
|
||||
"""
|
||||
accepted_normal_difference = 0.01
|
||||
cross_product_next = np.cross(vector_1, vector_2)
|
||||
if np.linalg.norm(cross_product_next) != 0:
|
||||
cross_product_next = cross_product_next / np.linalg.norm(cross_product_next)
|
||||
alpha = Polygon._angle_between_vectors(vector_1, vector_2)
|
||||
else:
|
||||
cross_product_next = [0, 0, 0]
|
||||
alpha = 0
|
||||
delta_normals = 0
|
||||
for j in range(0, 3):
|
||||
delta_normals += cross_product[j] - cross_product_next[j]
|
||||
if np.abs(delta_normals) < accepted_normal_difference:
|
||||
return alpha
|
||||
return -alpha
|
||||
|
||||
@staticmethod
|
||||
def triangle_mesh(vertices, normal):
|
||||
min_x = 1e16
|
||||
min_y = 1e16
|
||||
min_z = 1e16
|
||||
for vertex in vertices:
|
||||
if vertex[0] < min_x:
|
||||
min_x = vertex[0]
|
||||
if vertex[1] < min_y:
|
||||
min_y = vertex[1]
|
||||
if vertex[2] < min_z:
|
||||
min_z = vertex[2]
|
||||
|
||||
new_vertices = []
|
||||
for vertex in vertices:
|
||||
vertex = [vertex[0]-min_x, vertex[1]-min_y, vertex[2]-min_z]
|
||||
new_vertices.append(vertex)
|
||||
|
||||
transformation_matrix = trimesh.geometry.plane_transform(origin=new_vertices[0], normal=normal)
|
||||
|
||||
coordinates = []
|
||||
for vertex in vertices:
|
||||
transformed_vertex = [vertex[0]-min_x, vertex[1]-min_y, vertex[2]-min_z, 1]
|
||||
transformed_vertex = np.dot(transformation_matrix, transformed_vertex)
|
||||
coordinate = [transformed_vertex[0], transformed_vertex[1]]
|
||||
coordinates.append(coordinate)
|
||||
|
||||
polygon = shapley_polygon(coordinates)
|
||||
|
||||
try:
|
||||
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
|
||||
mesh = Trimesh(vertices=vertices, faces=faces)
|
||||
|
||||
# check orientation
|
||||
normal_sum = 0
|
||||
for i in range(0, 3):
|
||||
normal_sum += normal[i] + mesh.face_normals[0][i]
|
||||
|
||||
if abs(normal_sum) <= 1E-10:
|
||||
new_faces = []
|
||||
for face in faces:
|
||||
new_face = []
|
||||
for i in range(0, len(face)):
|
||||
new_face.append(face[len(face)-i-1])
|
||||
new_faces.append(new_face)
|
||||
mesh = Trimesh(vertices=vertices, faces=new_faces)
|
||||
|
||||
return mesh
|
||||
|
||||
except ValueError:
|
||||
logger.error(f'Not able to triangulate polygon\n')
|
||||
sys.stderr.write(f'Not able to triangulate polygon\n')
|
||||
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
|
||||
_faces = [[0, 1, 2]]
|
||||
return Trimesh(vertices=_vertices, faces=_faces)
|
||||
|
||||
@property
|
||||
def triangles(self) -> List[Polygon]:
|
||||
if self._triangles is None:
|
||||
self._triangles = []
|
||||
_mesh = self.triangle_mesh(self.coordinates, self.normal)
|
||||
for face in _mesh.faces:
|
||||
points = []
|
||||
for vertex in face:
|
||||
points.append(self.coordinates[vertex])
|
||||
polygon = Polygon(points)
|
||||
self._triangles.append(polygon)
|
||||
return self._triangles
|
||||
|
||||
@staticmethod
|
||||
def _angle_between_vectors(vec_1, vec_2):
|
||||
"""
|
||||
angle between vectors in radians
|
||||
:param vec_1: vector
|
||||
:param vec_2: vector
|
||||
:return: float
|
||||
"""
|
||||
if np.linalg.norm(vec_1) == 0 or np.linalg.norm(vec_2) == 0:
|
||||
sys.stderr.write("Warning: impossible to calculate angle between planes' normal. Return 0\n")
|
||||
return 0
|
||||
cosine = np.dot(vec_1, vec_2) / np.linalg.norm(vec_1) / np.linalg.norm(vec_2)
|
||||
if cosine > 1 and cosine - 1 < 1e-5:
|
||||
cosine = 1
|
||||
elif cosine < -1 and cosine + 1 > -1e-5:
|
||||
cosine = -1
|
||||
alpha = math.acos(cosine)
|
||||
return alpha
|
||||
|
||||
@property
|
||||
def inverse(self):
|
||||
"""
|
||||
Get the polygon coordinates in reversed order
|
||||
:return: [np.ndarray]
|
||||
"""
|
||||
if self._inverse is None:
|
||||
self._inverse = self.coordinates[::-1]
|
||||
return self._inverse
|
||||
|
||||
def divide(self, plane):
|
||||
"""
|
||||
Divides the polygon in two by a plane
|
||||
:param plane: plane that intersects with self to divide it in two parts (Plane)
|
||||
:return: Polygon, Polygon, [Point]
|
||||
"""
|
||||
tri_polygons = Trimesh(vertices=self.vertices, faces=self.faces)
|
||||
intersection = trimesh.intersections.mesh_plane(tri_polygons, plane.normal, plane.origin.coordinates)
|
||||
polys_1 = trimesh.intersections.slice_mesh_plane(tri_polygons, plane.opposite_normal, plane.origin.coordinates)
|
||||
polys_2 = trimesh.intersections.slice_mesh_plane(tri_polygons, plane.normal, plane.origin.coordinates)
|
||||
triangles_1 = []
|
||||
for triangle in polys_1.triangles:
|
||||
triangles_1.append(Polygon(triangle))
|
||||
polygon_1 = self._reshape(triangles_1)
|
||||
triangles_2 = []
|
||||
for triangle in polys_2.triangles:
|
||||
triangles_2.append(Polygon(triangle))
|
||||
polygon_2 = self._reshape(triangles_2)
|
||||
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:
|
||||
if not self._edge_in_edges_list(edge, edges_list):
|
||||
edges_list.append(edge)
|
||||
else:
|
||||
edges_list = self._remove_from_list(edge, edges_list)
|
||||
points = self._order_points(edges_list)
|
||||
return Polygon(points)
|
||||
|
||||
@staticmethod
|
||||
def _edge_in_edges_list(edge, edges_list):
|
||||
for edge_element in edges_list:
|
||||
if (edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(edge[1]) == 0) or \
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(
|
||||
edge[1]) == 0):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _order_points(edges_list):
|
||||
# todo: not sure that this method works for any case -> RECHECK
|
||||
points = edges_list[0]
|
||||
for _ in range(0, len(points)):
|
||||
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:
|
||||
array_points.append(point.coordinates)
|
||||
return np.array(array_points)
|
||||
|
||||
@staticmethod
|
||||
def _remove_from_list(edge, edges_list):
|
||||
new_list = []
|
||||
for edge_element in edges_list:
|
||||
if not ((edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(
|
||||
edge[1]) == 0) or
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(
|
||||
edge[1]) == 0)):
|
||||
new_list.append(edge_element)
|
||||
return new_list
|
||||
|
||||
@property
|
||||
def vertices(self) -> np.ndarray:
|
||||
"""
|
||||
Get polygon vertices
|
||||
:return: np.ndarray(int)
|
||||
"""
|
||||
if self._vertices is None:
|
||||
vertices, self._vertices = [], []
|
||||
_ = [vertices.extend(s.coordinates) for s in self.triangles]
|
||||
for vertex_1 in vertices:
|
||||
found = False
|
||||
for vertex_2 in self._vertices:
|
||||
found = False
|
||||
power = 0
|
||||
for dimension in range(0, 3):
|
||||
power += math.pow(vertex_2[dimension] - vertex_1[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
if distance == 0:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
self._vertices.append(vertex_1)
|
||||
self._vertices = np.asarray(self._vertices)
|
||||
return self._vertices
|
||||
|
||||
@property
|
||||
def faces(self) -> List[List[int]]:
|
||||
"""
|
||||
Get polygon triangular faces
|
||||
:return: [face]
|
||||
"""
|
||||
if self._faces is None:
|
||||
self._faces = []
|
||||
|
||||
for polygon in self.triangles:
|
||||
face = []
|
||||
points = polygon.coordinates
|
||||
if len(points) != 3:
|
||||
sub_polygons = polygon.triangles
|
||||
# todo: I modified this! To be checked @Guille
|
||||
if len(sub_polygons) >= 1:
|
||||
for sub_polygon in sub_polygons:
|
||||
face = []
|
||||
points = sub_polygon.coordinates
|
||||
for point in points:
|
||||
face.append(self._position_of(point, face))
|
||||
self._faces.append(face)
|
||||
else:
|
||||
for point in points:
|
||||
face.append(self._position_of(point, face))
|
||||
self._faces.append(face)
|
||||
return self._faces
|
||||
|
||||
def _position_of(self, point, face):
|
||||
"""
|
||||
position of a specific point in the list of points that define a face
|
||||
:return: int
|
||||
"""
|
||||
vertices = self.vertices
|
||||
for i in range(len(vertices)):
|
||||
# ensure not duplicated vertex
|
||||
power = 0
|
||||
vertex2 = vertices[i]
|
||||
for dimension in range(0, 3):
|
||||
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
if i not in face and distance == 0:
|
||||
return i
|
||||
return -1
|
|
@ -1,254 +0,0 @@
|
|||
"""
|
||||
Polyhedron module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import List, Union
|
||||
import sys
|
||||
import math
|
||||
import numpy as np
|
||||
from trimesh import Trimesh
|
||||
from hub.helpers.configuration_helper import ConfigurationHelper
|
||||
|
||||
|
||||
class Polyhedron:
|
||||
"""
|
||||
Polyhedron class
|
||||
"""
|
||||
|
||||
def __init__(self, polygons):
|
||||
self._polygons = polygons
|
||||
self._polyhedron = None
|
||||
self._triangulated_polyhedron = None
|
||||
self._volume = None
|
||||
self._faces = None
|
||||
self._vertices = None
|
||||
self._trimesh = None
|
||||
self._centroid = None
|
||||
self._max_z = None
|
||||
self._max_y = None
|
||||
self._max_x = None
|
||||
self._min_z = None
|
||||
self._min_y = None
|
||||
self._min_x = None
|
||||
|
||||
def _position_of(self, point, face):
|
||||
"""
|
||||
position of a specific point in the list of points that define a face
|
||||
:return: int
|
||||
"""
|
||||
vertices = self.vertices
|
||||
for i in range(len(vertices)):
|
||||
# ensure not duplicated vertex
|
||||
power = 0
|
||||
vertex2 = vertices[i]
|
||||
for dimension in range(0, 3):
|
||||
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
if i not in face and distance == 0:
|
||||
return i
|
||||
return -1
|
||||
|
||||
@property
|
||||
def vertices(self) -> np.ndarray:
|
||||
"""
|
||||
Get polyhedron vertices
|
||||
:return: np.ndarray(int)
|
||||
"""
|
||||
if self._vertices is None:
|
||||
vertices, self._vertices = [], []
|
||||
_ = [vertices.extend(s.coordinates) for s in self._polygons]
|
||||
for vertex_1 in vertices:
|
||||
found = False
|
||||
for vertex_2 in self._vertices:
|
||||
found = False
|
||||
power = 0
|
||||
for dimension in range(0, 3):
|
||||
power += math.pow(vertex_2[dimension] - vertex_1[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
if distance == 0:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
self._vertices.append(vertex_1)
|
||||
self._vertices = np.asarray(self._vertices)
|
||||
return self._vertices
|
||||
|
||||
@property
|
||||
def faces(self) -> List[List[int]]:
|
||||
"""
|
||||
Get polyhedron triangular faces
|
||||
:return: [face]
|
||||
"""
|
||||
if self._faces is None:
|
||||
self._faces = []
|
||||
|
||||
for polygon in self._polygons:
|
||||
|
||||
face = []
|
||||
points = polygon.coordinates
|
||||
if len(points) != 3:
|
||||
sub_polygons = polygon.triangles
|
||||
# todo: I modified this! To be checked @Guille
|
||||
if len(sub_polygons) >= 1:
|
||||
for sub_polygon in sub_polygons:
|
||||
face = []
|
||||
points = sub_polygon.coordinates
|
||||
for point in points:
|
||||
face.append(self._position_of(point, face))
|
||||
self._faces.append(face)
|
||||
else:
|
||||
for point in points:
|
||||
face.append(self._position_of(point, face))
|
||||
self._faces.append(face)
|
||||
return self._faces
|
||||
|
||||
@property
|
||||
def trimesh(self) -> Union[Trimesh, None]:
|
||||
"""
|
||||
Get polyhedron trimesh
|
||||
:return: Trimesh
|
||||
"""
|
||||
if self._trimesh is None:
|
||||
for face in self.faces:
|
||||
if len(face) != 3:
|
||||
sys.stderr.write('Not able to generate trimesh\n')
|
||||
return None
|
||||
self._trimesh = Trimesh(vertices=self.vertices, faces=self.faces)
|
||||
return self._trimesh
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
"""
|
||||
Get polyhedron volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
if self._volume is None:
|
||||
if self.trimesh is None:
|
||||
self._volume = np.inf
|
||||
elif not self.trimesh.is_volume:
|
||||
self._volume = np.inf
|
||||
else:
|
||||
self._volume = self.trimesh.volume
|
||||
return self._volume
|
||||
|
||||
@property
|
||||
def max_z(self):
|
||||
"""
|
||||
Get polyhedron maximal z value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._max_z is None:
|
||||
self._max_z = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
self._max_z = max(self._max_z, point[2])
|
||||
return self._max_z
|
||||
|
||||
@property
|
||||
def max_y(self):
|
||||
"""
|
||||
Get polyhedron maximal y value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._max_y is None:
|
||||
self._max_y = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
if self._max_y < point[1]:
|
||||
self._max_y = point[1]
|
||||
return self._max_y
|
||||
|
||||
@property
|
||||
def max_x(self):
|
||||
"""
|
||||
Get polyhedron maximal x value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._max_x is None:
|
||||
self._max_x = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
self._max_x = max(self._max_x, point[0])
|
||||
return self._max_x
|
||||
|
||||
@property
|
||||
def min_z(self):
|
||||
"""
|
||||
Get polyhedron minimal z value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._min_z is None:
|
||||
self._min_z = self.max_z
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_z > point[2]:
|
||||
self._min_z = point[2]
|
||||
return self._min_z
|
||||
|
||||
@property
|
||||
def min_y(self):
|
||||
"""
|
||||
Get polyhedron minimal y value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._min_y is None:
|
||||
self._min_y = self.max_y
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_y > point[1]:
|
||||
self._min_y = point[1]
|
||||
return self._min_y
|
||||
|
||||
@property
|
||||
def min_x(self):
|
||||
"""
|
||||
Get polyhedron minimal x value in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._min_x is None:
|
||||
self._min_x = self.max_x
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.coordinates:
|
||||
if self._min_x > point[0]:
|
||||
self._min_x = point[0]
|
||||
return self._min_x
|
||||
|
||||
@property
|
||||
def centroid(self) -> Union[None, List[float]]:
|
||||
"""
|
||||
Get polyhedron centroid
|
||||
:return: [x,y,z]
|
||||
"""
|
||||
if self._centroid is None:
|
||||
trimesh = self.trimesh
|
||||
if trimesh is None:
|
||||
return None
|
||||
self._centroid = self.trimesh.centroid
|
||||
return self._centroid
|
||||
|
||||
def stl_export(self, full_path):
|
||||
"""
|
||||
Export the polyhedron to stl given file
|
||||
:param full_path: str
|
||||
:return: None
|
||||
"""
|
||||
self.trimesh.export(full_path, 'stl_ascii')
|
||||
|
||||
def obj_export(self, full_path):
|
||||
"""
|
||||
Export the polyhedron to obj given file
|
||||
:param full_path: str
|
||||
:return: None
|
||||
"""
|
||||
self.trimesh.export(full_path, 'obj')
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Auxiliary function to render the polyhedron
|
||||
:return: None
|
||||
"""
|
||||
self.trimesh.show()
|
|
@ -9,7 +9,7 @@ import uuid
|
|||
from typing import Union, List
|
||||
from hub.city_model_structure.building_demand.usage import Usage
|
||||
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||
from geometry import Polyhedron
|
||||
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ from hub.city_model_structure.iot.station import Station
|
|||
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||
from hub.city_model_structure.machine import Machine
|
||||
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||
from hub.helpers.geometry_helper import GeometryHelper
|
||||
from geometry import Library as GeometryHelper
|
||||
from hub.helpers.location import Location
|
||||
from hub.city_model_structure.energy_system import EnergySystem
|
||||
from hub.city_model_structure.lca_material import LcaMaterial
|
||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Atiya atiya.atiya@mail.concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Fuel:
|
||||
def __init__(self, fuel_id, name, carbon_emission_factor, unit):
|
||||
self._fuel_id = fuel_id
|
||||
|
|
|
@ -7,6 +7,7 @@ Project Coder atiya.atiya@mail.concordia.ca
|
|||
|
||||
from typing import Union
|
||||
|
||||
|
||||
class LcaMaterial:
|
||||
def __init__(self):
|
||||
self._id = None
|
||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Atiya atiya.atiya@mail.concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Vehicle:
|
||||
"""
|
||||
Vehicle class
|
||||
|
|
|
@ -1,301 +0,0 @@
|
|||
"""
|
||||
Geometry helper
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from trimesh import Trimesh
|
||||
from trimesh import intersections
|
||||
|
||||
from hub.city_model_structure.attributes.polygon import Polygon
|
||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||
from hub.helpers.location import Location
|
||||
|
||||
|
||||
class MapPoint:
|
||||
def __init__(self, x, y):
|
||||
self._x = int(x)
|
||||
self._y = int(y)
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._y
|
||||
|
||||
def __str__(self):
|
||||
return f'({self.x}, {self.y})'
|
||||
|
||||
def __len__(self):
|
||||
return 1
|
||||
|
||||
def __getitem__(self, index):
|
||||
if index == 0:
|
||||
return self._x
|
||||
elif index == 1:
|
||||
return self._y
|
||||
else:
|
||||
raise IndexError('Index error')
|
||||
|
||||
|
||||
class GeometryHelper:
|
||||
"""
|
||||
Geometry helper class
|
||||
"""
|
||||
# todo: complete dictionary
|
||||
srs_transformations = {
|
||||
'urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH': 'epsg:25832'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def factor():
|
||||
return 0.5
|
||||
|
||||
def __init__(self, delta=0, area_delta=0):
|
||||
self._delta = delta
|
||||
self._area_delta = area_delta
|
||||
|
||||
@staticmethod
|
||||
def coordinate_to_map_point(coordinate, city):
|
||||
factor = GeometryHelper.factor()
|
||||
return MapPoint(((coordinate[0] - city.lower_corner[0]) * factor), ((coordinate[1] - city.lower_corner[1]) * factor))
|
||||
|
||||
@staticmethod
|
||||
def city_mapping(city, building_names=None, plot=False):
|
||||
|
||||
"""
|
||||
|
||||
Returns a shared_information dictionary like
|
||||
{
|
||||
"building_name" : [{line: 0 coordinate_1: [x,y,z], coordinate_2:[x, y, z], points: 0}]
|
||||
}
|
||||
"""
|
||||
lines_information = {}
|
||||
if building_names is None:
|
||||
building_names = [b.name for b in city.buildings]
|
||||
factor = GeometryHelper.factor()
|
||||
x = math.ceil((city.upper_corner[0] - city.lower_corner[0]) * factor) + 1
|
||||
y = math.ceil((city.upper_corner[1] - city.lower_corner[1]) * factor) + 1
|
||||
city_map = [['' for _ in range(y + 1)] for _ in range(x + 1)]
|
||||
map_info = [[{} for _ in range(y + 1)] for _ in range(x + 1)]
|
||||
img = Image.new('RGB', (x + 1, y + 1), "black") # create a new black image
|
||||
city_image = img.load() # create the pixel map
|
||||
for building_name in building_names:
|
||||
building = city.city_object(building_name)
|
||||
line = 0
|
||||
for ground in building.grounds:
|
||||
length = len(ground.perimeter_polygon.coordinates) - 1
|
||||
for i, coordinate in enumerate(ground.perimeter_polygon.coordinates):
|
||||
|
||||
j = i + 1
|
||||
if i == length:
|
||||
j = 0
|
||||
next_coordinate = ground.perimeter_polygon.coordinates[j]
|
||||
distance = GeometryHelper.distance_between_points(coordinate, next_coordinate)
|
||||
steps = int(distance * factor * 2)
|
||||
if steps == 0:
|
||||
continue
|
||||
delta_x = (next_coordinate[0] - coordinate[0]) / steps
|
||||
delta_y = (next_coordinate[1] - coordinate[1]) / steps
|
||||
|
||||
for k in range(0, steps):
|
||||
new_coordinate = (coordinate[0] + (delta_x * k), coordinate[1] + (delta_y * k))
|
||||
point = GeometryHelper.coordinate_to_map_point(new_coordinate, city)
|
||||
x = point.x
|
||||
y = point.y
|
||||
if city_map[x][y] == '':
|
||||
city_map[x][y] = building.name
|
||||
map_info[x][y] = {
|
||||
'line_start': (coordinate[0], coordinate[1]),
|
||||
'line_end': (next_coordinate[0], next_coordinate[1]),
|
||||
}
|
||||
city_image[x, y] = (100, 0, 0)
|
||||
elif city_map[x][y] != building.name:
|
||||
neighbour = city.city_object(city_map[x][y])
|
||||
neighbour_info = map_info[x][y]
|
||||
|
||||
# prepare the keys
|
||||
neighbour_start_coordinate = f'{GeometryHelper.coordinate_to_map_point(neighbour_info["line_start"], city)}'
|
||||
building_start_coordinate = f'{GeometryHelper.coordinate_to_map_point(coordinate, city)}'
|
||||
neighbour_key = f'{neighbour.name}_{neighbour_start_coordinate}_{building_start_coordinate}'
|
||||
building_key = f'{building.name}_{building_start_coordinate}_{neighbour_start_coordinate}'
|
||||
|
||||
# Add my neighbour info to my shared lines
|
||||
if building.name in lines_information.keys() and neighbour_key in lines_information[building.name]:
|
||||
shared_points = int(lines_information[building.name][neighbour_key]['shared_points'])
|
||||
lines_information[building.name][neighbour_key]['shared_points'] = shared_points + 1
|
||||
else:
|
||||
if building.name not in lines_information.keys():
|
||||
lines_information[building.name] = {}
|
||||
lines_information[building.name][neighbour_key] = {
|
||||
'neighbour_name': neighbour.name,
|
||||
'line_start': (coordinate[0], coordinate[1]),
|
||||
'line_end': (next_coordinate[0], next_coordinate[1]),
|
||||
'neighbour_line_start': neighbour_info['line_start'],
|
||||
'neighbour_line_end': neighbour_info['line_end'],
|
||||
'coordinate_start': f"{GeometryHelper.coordinate_to_map_point(coordinate, city)}",
|
||||
'coordinate_end': f"{GeometryHelper.coordinate_to_map_point(next_coordinate, city)}",
|
||||
'neighbour_start': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_start'], city)}",
|
||||
'neighbour_end': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_end'], city)}",
|
||||
'shared_points': 1
|
||||
}
|
||||
|
||||
# Add my info to my neighbour shared lines
|
||||
if neighbour.name in lines_information.keys() and building_key in lines_information[neighbour.name]:
|
||||
shared_points = int(lines_information[neighbour.name][building_key]['shared_points'])
|
||||
lines_information[neighbour.name][building_key]['shared_points'] = shared_points + 1
|
||||
else:
|
||||
if neighbour.name not in lines_information.keys():
|
||||
lines_information[neighbour.name] = {}
|
||||
lines_information[neighbour.name][building_key] = {
|
||||
'neighbour_name': building.name,
|
||||
'line_start': neighbour_info['line_start'],
|
||||
'line_end': neighbour_info['line_end'],
|
||||
'neighbour_line_start': (coordinate[0], coordinate[1]),
|
||||
'neighbour_line_end': (next_coordinate[0], next_coordinate[1]),
|
||||
'neighbour_start': f"{GeometryHelper.coordinate_to_map_point(coordinate, city)}",
|
||||
'neighbour_end': f"{GeometryHelper.coordinate_to_map_point(next_coordinate, city)}",
|
||||
'coordinate_start': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_start'], city)}",
|
||||
'coordinate_end': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_end'], city)}",
|
||||
'shared_points': 1
|
||||
}
|
||||
|
||||
if building.neighbours is None:
|
||||
building.neighbours = [neighbour]
|
||||
elif neighbour not in building.neighbours:
|
||||
building.neighbours.append(neighbour)
|
||||
if neighbour.neighbours is None:
|
||||
neighbour.neighbours = [building]
|
||||
elif building not in neighbour.neighbours:
|
||||
neighbour.neighbours.append(building)
|
||||
line += 1
|
||||
|
||||
if plot:
|
||||
img.show()
|
||||
return lines_information
|
||||
|
||||
@staticmethod
|
||||
def segment_list_to_trimesh(lines) -> Trimesh:
|
||||
"""
|
||||
Transform a list of segments into a Trimesh
|
||||
"""
|
||||
# todo: trimesh has a method for this
|
||||
line_points = [lines[0][0], lines[0][1]]
|
||||
lines.remove(lines[0])
|
||||
while len(lines) > 1:
|
||||
i = 0
|
||||
for line in lines:
|
||||
i += 1
|
||||
if GeometryHelper.distance_between_points(line[0], line_points[len(line_points) - 1]) < 1e-8:
|
||||
line_points.append(line[1])
|
||||
lines.pop(i - 1)
|
||||
break
|
||||
if GeometryHelper.distance_between_points(line[1], line_points[len(line_points) - 1]) < 1e-8:
|
||||
line_points.append(line[0])
|
||||
lines.pop(i - 1)
|
||||
break
|
||||
polyhedron = Polyhedron(Polygon(line_points).triangles)
|
||||
trimesh = Trimesh(polyhedron.vertices, polyhedron.faces)
|
||||
return trimesh
|
||||
|
||||
@staticmethod
|
||||
def _merge_meshes(mesh1, mesh2):
|
||||
v_1 = mesh1.vertices
|
||||
f_1 = mesh1.faces
|
||||
v_2 = mesh2.vertices
|
||||
f_2 = mesh2.faces
|
||||
length = len(v_1)
|
||||
v_merge = np.concatenate((v_1, v_2))
|
||||
f_merge = np.asarray(f_1)
|
||||
|
||||
for item in f_2:
|
||||
point1 = item.item(0) + length
|
||||
point2 = item.item(1) + length
|
||||
point3 = item.item(2) + length
|
||||
surface = np.asarray([point1, point2, point3])
|
||||
f_merge = np.concatenate((f_merge, [surface]))
|
||||
|
||||
mesh_merge = Trimesh(vertices=v_merge, faces=f_merge)
|
||||
mesh_merge.fix_normals()
|
||||
|
||||
return mesh_merge
|
||||
|
||||
@staticmethod
|
||||
def divide_mesh_by_plane(trimesh, normal_plane, point_plane):
|
||||
"""
|
||||
Divide a mesh by a plane
|
||||
:param trimesh: Trimesh
|
||||
:param normal_plane: [x, y, z]
|
||||
:param point_plane: [x, y, z]
|
||||
:return: [Trimesh]
|
||||
"""
|
||||
# The first mesh returns the positive side of the plane and the second the negative side.
|
||||
# If the plane does not divide the mesh (i.e. it does not touch it or it is coplanar with one or more faces),
|
||||
# then it returns only the original mesh.
|
||||
# todo: review split method in https://github.com/mikedh/trimesh/issues/235,
|
||||
# once triangulate_polygon in Polygon class is solved
|
||||
|
||||
normal_plane_opp = [None] * len(normal_plane)
|
||||
for i in range(0, len(normal_plane)):
|
||||
normal_plane_opp[i] = - normal_plane[i]
|
||||
|
||||
section_1 = intersections.slice_mesh_plane(trimesh, normal_plane, point_plane)
|
||||
if section_1 is None:
|
||||
return [trimesh]
|
||||
lines = list(intersections.mesh_plane(trimesh, normal_plane, point_plane))
|
||||
cap = GeometryHelper.segment_list_to_trimesh(lines)
|
||||
trimesh_1 = GeometryHelper._merge_meshes(section_1, cap)
|
||||
|
||||
section_2 = intersections.slice_mesh_plane(trimesh, normal_plane_opp, point_plane)
|
||||
if section_2 is None:
|
||||
return [trimesh_1]
|
||||
trimesh_2 = GeometryHelper._merge_meshes(section_2, cap)
|
||||
|
||||
return [trimesh_1, trimesh_2]
|
||||
|
||||
@staticmethod
|
||||
def get_location(latitude, longitude) -> Location:
|
||||
"""
|
||||
Get Location from latitude and longitude
|
||||
"""
|
||||
_data_path = Path(Path(__file__).parent.parent / 'data/geolocation/cities15000.txt').resolve()
|
||||
latitude = float(latitude)
|
||||
longitude = float(longitude)
|
||||
distance = math.inf
|
||||
country = 'Unknown'
|
||||
city = 'Unknown'
|
||||
with open(_data_path, 'r', encoding='utf-8') as f:
|
||||
for line_number, line in enumerate(f):
|
||||
fields = line.split('\t')
|
||||
file_city_name = fields[2]
|
||||
file_latitude = float(fields[4])
|
||||
file_longitude = float(fields[5])
|
||||
file_country_code = fields[8]
|
||||
new_distance = math.sqrt(pow((latitude - file_latitude), 2) + pow((longitude - file_longitude), 2))
|
||||
if distance > new_distance:
|
||||
distance = new_distance
|
||||
country = file_country_code
|
||||
city = file_city_name
|
||||
return Location(country, city)
|
||||
|
||||
@staticmethod
|
||||
def distance_between_points(vertex1, vertex2):
|
||||
"""
|
||||
distance between points in an n-D Euclidean space
|
||||
:param vertex1: point or vertex
|
||||
:param vertex2: point or vertex
|
||||
:return: float
|
||||
"""
|
||||
power = 0
|
||||
for dimension in range(0, len(vertex1)):
|
||||
power += math.pow(vertex2[dimension] - vertex1[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
return distance
|
|
@ -1,30 +0,0 @@
|
|||
"""
|
||||
Location module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Location:
|
||||
"""
|
||||
Location
|
||||
"""
|
||||
def __init__(self, country, city):
|
||||
self._country = country
|
||||
self._city = city
|
||||
|
||||
@property
|
||||
def city(self):
|
||||
"""
|
||||
City name
|
||||
"""
|
||||
return self._city
|
||||
|
||||
@property
|
||||
def country(self):
|
||||
"""
|
||||
Country code
|
||||
"""
|
||||
return self._country
|
|
@ -11,8 +11,8 @@ import numpy as np
|
|||
from typing import List
|
||||
|
||||
from hub.helpers import constants as cte
|
||||
from hub.city_model_structure.attributes.polygon import Polygon
|
||||
from hub.city_model_structure.attributes.point import Point
|
||||
from geometry import Polygon
|
||||
from geometry import Point
|
||||
from hub.city_model_structure.building_demand.storey import Storey
|
||||
from hub.city_model_structure.building_demand.surface import Surface
|
||||
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||
|
|
|
@ -12,8 +12,8 @@ import numpy as np
|
|||
from pyproj import Transformer
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
from hub.helpers.geometry_helper import GeometryHelper
|
||||
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper as igh
|
||||
from geometry import Library as GeometryHelper
|
||||
from geometry import Helper as igh
|
||||
from hub.city_model_structure.building import Building
|
||||
from hub.city_model_structure.building_demand.surface import Surface
|
||||
from hub.city_model_structure.city import City
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
"""
|
||||
Geometry helper
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import math
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
class GeometryHelper:
|
||||
"""
|
||||
Geometry helper
|
||||
"""
|
||||
@staticmethod
|
||||
def to_points_matrix(points):
|
||||
"""
|
||||
Transform a point vector into a point matrix
|
||||
:param points: [x, y, z, x, y, z ...]
|
||||
:return: [[x,y,z],[x,y,z]...]
|
||||
"""
|
||||
rows = points.size // 3
|
||||
points = points.reshape(rows, 3)
|
||||
return points
|
||||
|
||||
@staticmethod
|
||||
def gml_surface_to_libs(surface):
|
||||
"""
|
||||
Transform citygml surface names into hub names
|
||||
"""
|
||||
if surface == 'WallSurface':
|
||||
return 'Wall'
|
||||
if surface == 'GroundSurface':
|
||||
return 'Ground'
|
||||
return 'Roof'
|
||||
|
||||
@staticmethod
|
||||
def points_from_string(coordinates) -> np.ndarray:
|
||||
points = np.fromstring(coordinates, dtype=float, sep=' ')
|
||||
points = GeometryHelper.to_points_matrix(points)
|
||||
return points
|
||||
|
||||
@staticmethod
|
||||
def remove_last_point_from_string(points):
|
||||
array = points.split(' ')
|
||||
res = " "
|
||||
return res.join(array[0:len(array) - 3])
|
||||
|
||||
@staticmethod
|
||||
def invert_points(points):
|
||||
res = []
|
||||
for point in points:
|
||||
res.insert(0, point)
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def ground_area(points):
|
||||
"""
|
||||
Get ground surface area in square meters
|
||||
:return: float
|
||||
"""
|
||||
# New method to calculate area
|
||||
|
||||
if len(points) < 3:
|
||||
sys.stderr.write('Warning: the area of a line or point cannot be calculated 1. Area = 0\n')
|
||||
return 0
|
||||
alpha = 0
|
||||
vec_1 = points[1] - points[0]
|
||||
for i in range(2, len(points)):
|
||||
vec_2 = points[i] - points[0]
|
||||
alpha += GeometryHelper.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')
|
||||
return 0
|
||||
#
|
||||
horizontal_points = points
|
||||
area = 0
|
||||
for i in range(0, len(horizontal_points) - 1):
|
||||
point = horizontal_points[i]
|
||||
next_point = horizontal_points[i + 1]
|
||||
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
|
||||
next_point = horizontal_points[0]
|
||||
point = horizontal_points[len(horizontal_points) - 1]
|
||||
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
|
||||
_area = abs(area)
|
||||
return _area
|
||||
|
||||
@staticmethod
|
||||
def angle_between_vectors(vec_1, vec_2):
|
||||
"""
|
||||
angle between vectors in radians
|
||||
:param vec_1: vector
|
||||
:param vec_2: vector
|
||||
:return: float
|
||||
"""
|
||||
if np.linalg.norm(vec_1) == 0 or np.linalg.norm(vec_2) == 0:
|
||||
sys.stderr.write("Warning: impossible to calculate angle between planes' normal. Return 0\n")
|
||||
return 0
|
||||
cosine = np.dot(vec_1, vec_2) / np.linalg.norm(vec_1) / np.linalg.norm(vec_2)
|
||||
if cosine > 1 and cosine - 1 < 1e-5:
|
||||
cosine = 1
|
||||
elif cosine < -1 and cosine + 1 > -1e-5:
|
||||
cosine = -1
|
||||
alpha = math.acos(cosine)
|
||||
return alpha
|
|
@ -2,7 +2,7 @@
|
|||
Insel Heap pump energy demand and fossil fuel consumption
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder peter.yefi@gmail.cm
|
||||
Project Coder peter.yefi@gmail.com
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
|
|
@ -11,6 +11,7 @@ from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
|||
from sqlalchemy import DateTime
|
||||
from hub.persistence.configuration import Models
|
||||
|
||||
|
||||
class CityObject(Models):
|
||||
"""
|
||||
A model representation of an application
|
||||
|
|
|
@ -12,7 +12,7 @@ from hub.imports.usage_factory import UsageFactory
|
|||
|
||||
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from hub.helpers.dictionaries import MontrealFunctionToHubFunction, Dictionaries
|
||||
from hub.helpers.geometry_helper import GeometryHelper
|
||||
from geometry import Library as GeometryHelper
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
|
||||
|
|
483
hub/unittests/tests_data/concordia_159_multipart.geojson
Normal file
483
hub/unittests/tests_data/concordia_159_multipart.geojson
Normal file
|
@ -0,0 +1,483 @@
|
|||
{
|
||||
"type":"FeatureCollection",
|
||||
"features":[
|
||||
{
|
||||
"type":"Feature",
|
||||
"id":159,
|
||||
"geometry":{
|
||||
"type":"MultiPolygon",
|
||||
"coordinates":[
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.577698789303398,
|
||||
45.495622856681265
|
||||
],
|
||||
[
|
||||
-73.577695682391294,
|
||||
45.495624487512899
|
||||
],
|
||||
[
|
||||
-73.577694801537987,
|
||||
45.495625936861458
|
||||
],
|
||||
[
|
||||
-73.577693920684638,
|
||||
45.49562738621006
|
||||
],
|
||||
[
|
||||
-73.577694615888902,
|
||||
45.495630499198704
|
||||
],
|
||||
[
|
||||
-73.577697062628715,
|
||||
45.495632621167189
|
||||
],
|
||||
[
|
||||
-73.577698848255025,
|
||||
45.495633159859175
|
||||
],
|
||||
[
|
||||
-73.577700633881378,
|
||||
45.495633698551167
|
||||
],
|
||||
[
|
||||
-73.577705085987418,
|
||||
45.495633326586457
|
||||
],
|
||||
[
|
||||
-73.577708563468136,
|
||||
45.495631344563115
|
||||
],
|
||||
[
|
||||
-73.577709259030797,
|
||||
45.495630066310945
|
||||
],
|
||||
[
|
||||
-73.577709954593416,
|
||||
45.495628788058717
|
||||
],
|
||||
[
|
||||
-73.577709490252843,
|
||||
45.49562607984307
|
||||
],
|
||||
[
|
||||
-73.577706812660736,
|
||||
45.495623562100398
|
||||
],
|
||||
[
|
||||
-73.577702627180884,
|
||||
45.495622431143737
|
||||
],
|
||||
[
|
||||
-73.577698789303398,
|
||||
45.495622856681265
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.57791718974444,
|
||||
45.495793264412136
|
||||
],
|
||||
[
|
||||
-73.577966456490742,
|
||||
45.495742218619156
|
||||
],
|
||||
[
|
||||
-73.577878164750075,
|
||||
45.495700076149248
|
||||
],
|
||||
[
|
||||
-73.577859178652233,
|
||||
45.49571975069135
|
||||
],
|
||||
[
|
||||
-73.577861956965407,
|
||||
45.495721071568774
|
||||
],
|
||||
[
|
||||
-73.577879805943169,
|
||||
45.495702576597608
|
||||
],
|
||||
[
|
||||
-73.577962515440873,
|
||||
45.49574205933709
|
||||
],
|
||||
[
|
||||
-73.577916838945768,
|
||||
45.495789395320777
|
||||
],
|
||||
[
|
||||
-73.57787497843664,
|
||||
45.495769415828214
|
||||
],
|
||||
[
|
||||
-73.577833117957056,
|
||||
45.495749436320196
|
||||
],
|
||||
[
|
||||
-73.577851465247122,
|
||||
45.495730428102746
|
||||
],
|
||||
[
|
||||
-73.577849480737555,
|
||||
45.495729484618735
|
||||
],
|
||||
[
|
||||
-73.577828693118363,
|
||||
45.495751032059708
|
||||
],
|
||||
[
|
||||
-73.57791718974444,
|
||||
45.495793264412136
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.578428233148927,
|
||||
45.495941982883387
|
||||
],
|
||||
[
|
||||
-73.578530103183425,
|
||||
45.495838322814635
|
||||
],
|
||||
[
|
||||
-73.578499329919453,
|
||||
45.49582345154311
|
||||
],
|
||||
[
|
||||
-73.578468556671695,
|
||||
45.495808580263336
|
||||
],
|
||||
[
|
||||
-73.578447353643782,
|
||||
45.495830285574655
|
||||
],
|
||||
[
|
||||
-73.578426150599569,
|
||||
45.495851990882095
|
||||
],
|
||||
[
|
||||
-73.578417604248173,
|
||||
45.495847857465606
|
||||
],
|
||||
[
|
||||
-73.578409057898043,
|
||||
45.495843724048513
|
||||
],
|
||||
[
|
||||
-73.578452403084299,
|
||||
45.495799363455262
|
||||
],
|
||||
[
|
||||
-73.578495748202485,
|
||||
45.495755002845257
|
||||
],
|
||||
[
|
||||
-73.578433049485312,
|
||||
45.495724703162658
|
||||
],
|
||||
[
|
||||
-73.578459637880272,
|
||||
45.495697491606336
|
||||
],
|
||||
[
|
||||
-73.578486226249623,
|
||||
45.495670280043669
|
||||
],
|
||||
[
|
||||
-73.578541754972733,
|
||||
45.495697111228424
|
||||
],
|
||||
[
|
||||
-73.578605197672417,
|
||||
45.495632179810727
|
||||
],
|
||||
[
|
||||
-73.578668640226383,
|
||||
45.49556724835714
|
||||
],
|
||||
[
|
||||
-73.578644249614086,
|
||||
45.495555468192734
|
||||
],
|
||||
[
|
||||
-73.578649591722638,
|
||||
45.495551055277119
|
||||
],
|
||||
[
|
||||
-73.578654933830336,
|
||||
45.495546642361241
|
||||
],
|
||||
[
|
||||
-73.578658928415678,
|
||||
45.495548502288408
|
||||
],
|
||||
[
|
||||
-73.578662923001303,
|
||||
45.495550362215432
|
||||
],
|
||||
[
|
||||
-73.578665886920362,
|
||||
45.495547138731361
|
||||
],
|
||||
[
|
||||
-73.578366044120955,
|
||||
45.495412170209917
|
||||
],
|
||||
[
|
||||
-73.578319210166981,
|
||||
45.495390187637788
|
||||
],
|
||||
[
|
||||
-73.578272376249373,
|
||||
45.49536820504634
|
||||
],
|
||||
[
|
||||
-73.578023430733111,
|
||||
45.495259386206158
|
||||
],
|
||||
[
|
||||
-73.578020811505979,
|
||||
45.495262069531542
|
||||
],
|
||||
[
|
||||
-73.577943110783622,
|
||||
45.495226466242045
|
||||
],
|
||||
[
|
||||
-73.57786541015912,
|
||||
45.495190862899364
|
||||
],
|
||||
[
|
||||
-73.577617016117856,
|
||||
45.495445076029839
|
||||
],
|
||||
[
|
||||
-73.577546091624328,
|
||||
45.495517669656074
|
||||
],
|
||||
[
|
||||
-73.57763021606263,
|
||||
45.495558325973803
|
||||
],
|
||||
[
|
||||
-73.577714340621938,
|
||||
45.495598982229176
|
||||
],
|
||||
[
|
||||
-73.577712104671733,
|
||||
45.495601273854334
|
||||
],
|
||||
[
|
||||
-73.577709868721371,
|
||||
45.495603565479428
|
||||
],
|
||||
[
|
||||
-73.578004398472899,
|
||||
45.49574590907234
|
||||
],
|
||||
[
|
||||
-73.578007567133241,
|
||||
45.495742667468747
|
||||
],
|
||||
[
|
||||
-73.578017041689648,
|
||||
45.495747250204211
|
||||
],
|
||||
[
|
||||
-73.578002412186507,
|
||||
45.495762215608373
|
||||
],
|
||||
[
|
||||
-73.578330770393634,
|
||||
45.495920903418444
|
||||
],
|
||||
[
|
||||
-73.578336762732036,
|
||||
45.495914780367642
|
||||
],
|
||||
[
|
||||
-73.578314727876958,
|
||||
45.495904132321797
|
||||
],
|
||||
[
|
||||
-73.578326009792079,
|
||||
45.49589257958354
|
||||
],
|
||||
[
|
||||
-73.578428233148927,
|
||||
45.495941982883387
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"properties":{
|
||||
"OBJECTID_12":159,
|
||||
"gml_id":"1066157",
|
||||
"gml_parent":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_ta":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_fe":"cityObjectMember",
|
||||
"citygml__1":" ",
|
||||
"citygml__2":" ",
|
||||
"gml_descri":" ",
|
||||
"gml_name":" ",
|
||||
"citygml_cr":" ",
|
||||
"citygml_te":" ",
|
||||
"externalRe":" ",
|
||||
"external_1":" ",
|
||||
"external_2":" ",
|
||||
"citygml_ge":" ",
|
||||
"citygml_re":" ",
|
||||
"citygml__3":" ",
|
||||
"citygml_ap":" ",
|
||||
"citygml_cl":" ",
|
||||
"citygml__4":" ",
|
||||
"citygml_fu":" ",
|
||||
"citygml__5":" ",
|
||||
"citygml_us":" ",
|
||||
"citygml__6":" ",
|
||||
"citygml_ye":" ",
|
||||
"citygml__7":" ",
|
||||
"citygml_ro":" ",
|
||||
"citygml__8":" ",
|
||||
"citygml_me":84.731999999999999,
|
||||
"citygml__9":"#m",
|
||||
"citygml_st":" ",
|
||||
"citygml_10":" ",
|
||||
"citygml_11":" ",
|
||||
"citygml_12":" ",
|
||||
"citygml_13":" ",
|
||||
"citygml_14":" ",
|
||||
"citygml_ou":" ",
|
||||
"citygml_in":" ",
|
||||
"citygml_bo":" ",
|
||||
"citygml_le":" ",
|
||||
"citygml_15":" ",
|
||||
"citygml_co":" ",
|
||||
"citygml_ad":" ",
|
||||
"Volume":"204394.697",
|
||||
"parcelle":" ",
|
||||
"OBJECTID":7583,
|
||||
"gml_id_1":"722b1b20-dfce-4154-a8e6-569f8188f693",
|
||||
"gml_pare_1":"1066157",
|
||||
"citygml_16":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_17":"boundedBy",
|
||||
"citygml_18":" ",
|
||||
"citygml_19":" ",
|
||||
"gml_desc_1":" ",
|
||||
"gml_name_1":" ",
|
||||
"citygml_20":" ",
|
||||
"citygml_21":" ",
|
||||
"external_3":" ",
|
||||
"external_4":" ",
|
||||
"external_5":" ",
|
||||
"citygml_22":" ",
|
||||
"citygml_23":" ",
|
||||
"citygml_24":" ",
|
||||
"citygml_25":" ",
|
||||
"citygml_26":" ",
|
||||
"citygml_op":" ",
|
||||
"Area":"3600.391",
|
||||
"FID_":0,
|
||||
"Join_Count":2,
|
||||
"TARGET_FID":7588,
|
||||
"gml_id_12":"1066157",
|
||||
"gml_pare_2":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_27":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_28":"cityObjectMember",
|
||||
"citygml_29":" ",
|
||||
"citygml_30":" ",
|
||||
"gml_desc_2":" ",
|
||||
"gml_name_2":" ",
|
||||
"citygml_31":" ",
|
||||
"citygml_32":" ",
|
||||
"external_6":" ",
|
||||
"external_7":" ",
|
||||
"external_8":" ",
|
||||
"citygml_33":" ",
|
||||
"citygml_34":" ",
|
||||
"citygml_35":" ",
|
||||
"citygml_36":" ",
|
||||
"citygml_37":" ",
|
||||
"citygml_38":" ",
|
||||
"citygml_39":" ",
|
||||
"citygml_40":" ",
|
||||
"citygml_41":" ",
|
||||
"citygml_42":" ",
|
||||
"citygml_43":" ",
|
||||
"citygml_44":" ",
|
||||
"citygml_45":" ",
|
||||
"citygml_46":" ",
|
||||
"citygml_47":84.731999999999999,
|
||||
"citygml_48":"#m",
|
||||
"citygml_49":" ",
|
||||
"citygml_50":" ",
|
||||
"citygml_51":" ",
|
||||
"citygml_52":" ",
|
||||
"citygml_53":" ",
|
||||
"citygml_54":" ",
|
||||
"citygml_55":" ",
|
||||
"citygml_56":" ",
|
||||
"citygml_57":" ",
|
||||
"citygml_58":" ",
|
||||
"citygml_59":" ",
|
||||
"citygml_60":" ",
|
||||
"citygml_61":" ",
|
||||
"Volume_1":"204394.697",
|
||||
"Field":0,
|
||||
"Field1":0,
|
||||
"OBJECTID_1":7583,
|
||||
"gml_id_12_":"722b1b20-dfce-4154-a8e6-569f8188f693",
|
||||
"gml_pare_3":"1066157",
|
||||
"citygml_62":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_63":"boundedBy",
|
||||
"citygml_64":" ",
|
||||
"citygml_65":" ",
|
||||
"gml_desc_3":" ",
|
||||
"gml_name_3":" ",
|
||||
"citygml_66":" ",
|
||||
"citygml_67":" ",
|
||||
"external_9":" ",
|
||||
"externa_10":" ",
|
||||
"externa_11":" ",
|
||||
"citygml_68":" ",
|
||||
"citygml_69":" ",
|
||||
"citygml_70":" ",
|
||||
"citygml_71":" ",
|
||||
"citygml_72":" ",
|
||||
"citygml_73":" ",
|
||||
"Area_1":"3600.391",
|
||||
"cityGML_hi":0,
|
||||
"Z_Min":41.366500000000002,
|
||||
"Z_Max":126.099,
|
||||
"Shape_Leng":352.31158223,
|
||||
"ID_UEV":"01111020",
|
||||
"CIVIQUE_DE":" 1515",
|
||||
"CIVIQUE_FI":" 1515",
|
||||
"NOM_RUE":"rue Sainte-Catherine Ouest (MTL+WMT)",
|
||||
"MUNICIPALI":"50",
|
||||
"ETAGE_HORS":17,
|
||||
"NOMBRE_LOG":1,
|
||||
"ANNEE_CONS":2005,
|
||||
"CODE_UTILI":"6821",
|
||||
"LIBELLE_UT":"Université",
|
||||
"CATEGORIE_":"Régulier",
|
||||
"MATRICULE8":"9839-75-0526-8-000-0000",
|
||||
"SUPERFICIE":5949,
|
||||
"SUPERFIC_1":259,
|
||||
"NO_ARROND_":"REM19",
|
||||
"Shape_Le_1":0.0037693215640499998,
|
||||
"Shape_Ar_1":6.8474298198599997e-07,
|
||||
"Z_Min_1":null,
|
||||
"Z_Max_1":null,
|
||||
"Shape_Length":352.31158223020242,
|
||||
"Shape_Area":3597.4347830048478
|
||||
}
|
||||
}
|
||||
]}
|
209
hub/unittests/tests_data/concordia_164.geojson
Normal file
209
hub/unittests/tests_data/concordia_164.geojson
Normal file
|
@ -0,0 +1,209 @@
|
|||
{
|
||||
"type":"FeatureCollection",
|
||||
"features":[
|
||||
{
|
||||
"type":"Feature",
|
||||
"id":164,
|
||||
"geometry":{
|
||||
"type":"Polygon",
|
||||
"coordinates":[
|
||||
[
|
||||
[
|
||||
-73.577465563026294,
|
||||
45.495808553995417
|
||||
],
|
||||
[
|
||||
-73.577627737571262,
|
||||
45.49588695081647
|
||||
],
|
||||
[
|
||||
-73.577789912566104,
|
||||
45.4959653474059
|
||||
],
|
||||
[
|
||||
-73.577897155727669,
|
||||
45.495855628290393
|
||||
],
|
||||
[
|
||||
-73.578004398472899,
|
||||
45.49574590907234
|
||||
],
|
||||
[
|
||||
-73.577709868721371,
|
||||
45.495603565479428
|
||||
],
|
||||
[
|
||||
-73.577680024034251,
|
||||
45.495589134278653
|
||||
],
|
||||
[
|
||||
-73.577465563026294,
|
||||
45.495808553995417
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"properties":{
|
||||
"OBJECTID_12":164,
|
||||
"gml_id":"1066826",
|
||||
"gml_parent":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_ta":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_fe":"cityObjectMember",
|
||||
"citygml__1":" ",
|
||||
"citygml__2":" ",
|
||||
"gml_descri":" ",
|
||||
"gml_name":" ",
|
||||
"citygml_cr":" ",
|
||||
"citygml_te":" ",
|
||||
"externalRe":" ",
|
||||
"external_1":" ",
|
||||
"external_2":" ",
|
||||
"citygml_ge":" ",
|
||||
"citygml_re":" ",
|
||||
"citygml__3":" ",
|
||||
"citygml_ap":" ",
|
||||
"citygml_cl":" ",
|
||||
"citygml__4":" ",
|
||||
"citygml_fu":" ",
|
||||
"citygml__5":" ",
|
||||
"citygml_us":" ",
|
||||
"citygml__6":" ",
|
||||
"citygml_ye":" ",
|
||||
"citygml__7":" ",
|
||||
"citygml_ro":" ",
|
||||
"citygml__8":" ",
|
||||
"citygml_me":65.929000000000002,
|
||||
"citygml__9":"#m",
|
||||
"citygml_st":" ",
|
||||
"citygml_10":" ",
|
||||
"citygml_11":" ",
|
||||
"citygml_12":" ",
|
||||
"citygml_13":" ",
|
||||
"citygml_14":" ",
|
||||
"citygml_ou":" ",
|
||||
"citygml_in":" ",
|
||||
"citygml_bo":" ",
|
||||
"citygml_le":" ",
|
||||
"citygml_15":" ",
|
||||
"citygml_co":" ",
|
||||
"citygml_ad":" ",
|
||||
"Volume":"52877.804",
|
||||
"parcelle":" ",
|
||||
"OBJECTID":7589,
|
||||
"gml_id_1":"46c9507d-33c9-40e9-9bda-00ad6fa8cd8f",
|
||||
"gml_pare_1":"1066826",
|
||||
"citygml_16":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_17":"boundedBy",
|
||||
"citygml_18":" ",
|
||||
"citygml_19":" ",
|
||||
"gml_desc_1":" ",
|
||||
"gml_name_1":" ",
|
||||
"citygml_20":" ",
|
||||
"citygml_21":" ",
|
||||
"external_3":" ",
|
||||
"external_4":" ",
|
||||
"external_5":" ",
|
||||
"citygml_22":" ",
|
||||
"citygml_23":" ",
|
||||
"citygml_24":" ",
|
||||
"citygml_25":" ",
|
||||
"citygml_26":" ",
|
||||
"citygml_op":" ",
|
||||
"Area":"911.899",
|
||||
"FID_":0,
|
||||
"Join_Count":1,
|
||||
"TARGET_FID":7594,
|
||||
"gml_id_12":"1066826",
|
||||
"gml_pare_2":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_27":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_28":"cityObjectMember",
|
||||
"citygml_29":" ",
|
||||
"citygml_30":" ",
|
||||
"gml_desc_2":" ",
|
||||
"gml_name_2":" ",
|
||||
"citygml_31":" ",
|
||||
"citygml_32":" ",
|
||||
"external_6":" ",
|
||||
"external_7":" ",
|
||||
"external_8":" ",
|
||||
"citygml_33":" ",
|
||||
"citygml_34":" ",
|
||||
"citygml_35":" ",
|
||||
"citygml_36":" ",
|
||||
"citygml_37":" ",
|
||||
"citygml_38":" ",
|
||||
"citygml_39":" ",
|
||||
"citygml_40":" ",
|
||||
"citygml_41":" ",
|
||||
"citygml_42":" ",
|
||||
"citygml_43":" ",
|
||||
"citygml_44":" ",
|
||||
"citygml_45":" ",
|
||||
"citygml_46":" ",
|
||||
"citygml_47":65.929000000000002,
|
||||
"citygml_48":"#m",
|
||||
"citygml_49":" ",
|
||||
"citygml_50":" ",
|
||||
"citygml_51":" ",
|
||||
"citygml_52":" ",
|
||||
"citygml_53":" ",
|
||||
"citygml_54":" ",
|
||||
"citygml_55":" ",
|
||||
"citygml_56":" ",
|
||||
"citygml_57":" ",
|
||||
"citygml_58":" ",
|
||||
"citygml_59":" ",
|
||||
"citygml_60":" ",
|
||||
"citygml_61":" ",
|
||||
"Volume_1":"52877.804",
|
||||
"Field":0,
|
||||
"Field1":0,
|
||||
"OBJECTID_1":7589,
|
||||
"gml_id_12_":"46c9507d-33c9-40e9-9bda-00ad6fa8cd8f",
|
||||
"gml_pare_3":"1066826",
|
||||
"citygml_62":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_63":"boundedBy",
|
||||
"citygml_64":" ",
|
||||
"citygml_65":" ",
|
||||
"gml_desc_3":" ",
|
||||
"gml_name_3":" ",
|
||||
"citygml_66":" ",
|
||||
"citygml_67":" ",
|
||||
"external_9":" ",
|
||||
"externa_10":" ",
|
||||
"externa_11":" ",
|
||||
"citygml_68":" ",
|
||||
"citygml_69":" ",
|
||||
"citygml_70":" ",
|
||||
"citygml_71":" ",
|
||||
"citygml_72":" ",
|
||||
"citygml_73":" ",
|
||||
"Area_1":"911.899",
|
||||
"cityGML_hi":0,
|
||||
"Z_Min":41.631399999999999,
|
||||
"Z_Max":107.56,
|
||||
"Shape_Leng":120.703852102,
|
||||
"ID_UEV":"01111020",
|
||||
"CIVIQUE_DE":" 1515",
|
||||
"CIVIQUE_FI":" 1515",
|
||||
"NOM_RUE":"rue Sainte-Catherine Ouest (MTL+WMT)",
|
||||
"MUNICIPALI":"50",
|
||||
"ETAGE_HORS":17,
|
||||
"NOMBRE_LOG":1,
|
||||
"ANNEE_CONS":2005,
|
||||
"CODE_UTILI":"6821",
|
||||
"LIBELLE_UT":"Université",
|
||||
"CATEGORIE_":"Régulier",
|
||||
"MATRICULE8":"9839-75-0526-8-000-0000",
|
||||
"SUPERFICIE":5949,
|
||||
"SUPERFIC_1":259,
|
||||
"NO_ARROND_":"REM19",
|
||||
"Shape_Le_1":0.0037693215640499998,
|
||||
"Shape_Ar_1":6.8474298198599997e-07,
|
||||
"Z_Min_1":null,
|
||||
"Z_Max_1":null,
|
||||
"Shape_Length":120.70385210151841,
|
||||
"Shape_Area":910.23684745179321
|
||||
}
|
||||
}
|
||||
]}
|
751
hub/unittests/tests_data/concordia_71_decoration.geojson
Normal file
751
hub/unittests/tests_data/concordia_71_decoration.geojson
Normal file
|
@ -0,0 +1,751 @@
|
|||
{
|
||||
"type":"FeatureCollection",
|
||||
"features":[
|
||||
{
|
||||
"type":"Feature",
|
||||
"id":71,
|
||||
"geometry":{
|
||||
"type":"MultiPolygon",
|
||||
"coordinates":[
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.577175184964275,
|
||||
45.493009748049133
|
||||
],
|
||||
[
|
||||
-73.577175709879739,
|
||||
45.493010004150236
|
||||
],
|
||||
[
|
||||
-73.577176234795175,
|
||||
45.493010260251353
|
||||
],
|
||||
[
|
||||
-73.577180541619128,
|
||||
45.493012329683943
|
||||
],
|
||||
[
|
||||
-73.57718401883858,
|
||||
45.493014007344591
|
||||
],
|
||||
[
|
||||
-73.577185017447064,
|
||||
45.493014486287095
|
||||
],
|
||||
[
|
||||
-73.57718589443131,
|
||||
45.493014907721673
|
||||
],
|
||||
[
|
||||
-73.57718677141429,
|
||||
45.493015328256433
|
||||
],
|
||||
[
|
||||
-73.577189129927973,
|
||||
45.493012904280477
|
||||
],
|
||||
[
|
||||
-73.577191795074896,
|
||||
45.493010166051512
|
||||
],
|
||||
[
|
||||
-73.57718903993181,
|
||||
45.493008838842606
|
||||
],
|
||||
[
|
||||
-73.57718557167837,
|
||||
45.49300716837481
|
||||
],
|
||||
[
|
||||
-73.577181255888817,
|
||||
45.49300509174968
|
||||
],
|
||||
[
|
||||
-73.577180204793308,
|
||||
45.493004590346501
|
||||
],
|
||||
[
|
||||
-73.577175184964275,
|
||||
45.493009748049133
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.577161621930131,
|
||||
45.49300707387485
|
||||
],
|
||||
[
|
||||
-73.57716126163794,
|
||||
45.493007444854243
|
||||
],
|
||||
[
|
||||
-73.577158338413994,
|
||||
45.493010453210324
|
||||
],
|
||||
[
|
||||
-73.577158245146066,
|
||||
45.493010548656898
|
||||
],
|
||||
[
|
||||
-73.577158153157541,
|
||||
45.493010644102561
|
||||
],
|
||||
[
|
||||
-73.577155935178141,
|
||||
45.493012920408361
|
||||
],
|
||||
[
|
||||
-73.577154054500497,
|
||||
45.493014854545287
|
||||
],
|
||||
[
|
||||
-73.577157722475633,
|
||||
45.493016621162525
|
||||
],
|
||||
[
|
||||
-73.577161391729192,
|
||||
45.493018386878951
|
||||
],
|
||||
[
|
||||
-73.577162330787303,
|
||||
45.493017418911435
|
||||
],
|
||||
[
|
||||
-73.5771632698454,
|
||||
45.493016450943962
|
||||
],
|
||||
[
|
||||
-73.577165494226676,
|
||||
45.493014178233089
|
||||
],
|
||||
[
|
||||
-73.577165684595926,
|
||||
45.493013983737988
|
||||
],
|
||||
[
|
||||
-73.57716714748787,
|
||||
45.493012480008922
|
||||
],
|
||||
[
|
||||
-73.577168610379744,
|
||||
45.493010976279884
|
||||
],
|
||||
[
|
||||
-73.577168968115487,
|
||||
45.493010607101823
|
||||
],
|
||||
[
|
||||
-73.577169325851216,
|
||||
45.493010237923791
|
||||
],
|
||||
[
|
||||
-73.577165654036648,
|
||||
45.493008470409642
|
||||
],
|
||||
[
|
||||
-73.577161983502947,
|
||||
45.493006703794386
|
||||
],
|
||||
[
|
||||
-73.577161621930131,
|
||||
45.49300707387485
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.577186751468034,
|
||||
45.49301945855742
|
||||
],
|
||||
[
|
||||
-73.577186393732333,
|
||||
45.493019827735587
|
||||
],
|
||||
[
|
||||
-73.577183467949027,
|
||||
45.493022835194147
|
||||
],
|
||||
[
|
||||
-73.577182260574006,
|
||||
45.493024068797311
|
||||
],
|
||||
[
|
||||
-73.577181053198899,
|
||||
45.493025302400483
|
||||
],
|
||||
[
|
||||
-73.577180114140987,
|
||||
45.493026270368098
|
||||
],
|
||||
[
|
||||
-73.577179175083018,
|
||||
45.493027238335756
|
||||
],
|
||||
[
|
||||
-73.577186512314881,
|
||||
45.493030770667808
|
||||
],
|
||||
[
|
||||
-73.577188399384184,
|
||||
45.493028832926697
|
||||
],
|
||||
[
|
||||
-73.577190803899896,
|
||||
45.49302636662695
|
||||
],
|
||||
[
|
||||
-73.57719372968306,
|
||||
45.493023359168184
|
||||
],
|
||||
[
|
||||
-73.57719444643503,
|
||||
45.493022621710921
|
||||
],
|
||||
[
|
||||
-73.577190778458359,
|
||||
45.493020855094827
|
||||
],
|
||||
[
|
||||
-73.57718710920372,
|
||||
45.493019089379374
|
||||
],
|
||||
[
|
||||
-73.577186751468034,
|
||||
45.49301945855742
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.577158105526706,
|
||||
45.493027294862564
|
||||
],
|
||||
[
|
||||
-73.577158630437324,
|
||||
45.493027547364392
|
||||
],
|
||||
[
|
||||
-73.577159154067289,
|
||||
45.493027798967226
|
||||
],
|
||||
[
|
||||
-73.577163468582043,
|
||||
45.493029878293505
|
||||
],
|
||||
[
|
||||
-73.577166936833777,
|
||||
45.493031546962328
|
||||
],
|
||||
[
|
||||
-73.577168313129235,
|
||||
45.493032212817511
|
||||
],
|
||||
[
|
||||
-73.577169689423513,
|
||||
45.493032877772869
|
||||
],
|
||||
[
|
||||
-73.577172765980194,
|
||||
45.493029723538051
|
||||
],
|
||||
[
|
||||
-73.577174723326266,
|
||||
45.493027718261317
|
||||
],
|
||||
[
|
||||
-73.577173195960071,
|
||||
45.493026980520661
|
||||
],
|
||||
[
|
||||
-73.577172583988087,
|
||||
45.493026683985356
|
||||
],
|
||||
[
|
||||
-73.577171970737936,
|
||||
45.493026388350778
|
||||
],
|
||||
[
|
||||
-73.57717023085408,
|
||||
45.493025553570391
|
||||
],
|
||||
[
|
||||
-73.577168489690877,
|
||||
45.493024718790927
|
||||
],
|
||||
[
|
||||
-73.5771663324348,
|
||||
45.493023680027704
|
||||
],
|
||||
[
|
||||
-73.577164173899348,
|
||||
45.493022641265334
|
||||
],
|
||||
[
|
||||
-73.577163648989981,
|
||||
45.493022389663381
|
||||
],
|
||||
[
|
||||
-73.577163124080599,
|
||||
45.493022138061441
|
||||
],
|
||||
[
|
||||
-73.577158105526706,
|
||||
45.493027294862564
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.576295787761836,
|
||||
45.493913665926286
|
||||
],
|
||||
[
|
||||
-73.576296837589425,
|
||||
45.493914169138101
|
||||
],
|
||||
[
|
||||
-73.576301039479546,
|
||||
45.493916197280711
|
||||
],
|
||||
[
|
||||
-73.576302830589938,
|
||||
45.49391705723562
|
||||
],
|
||||
[
|
||||
-73.57630462169918,
|
||||
45.493917916290606
|
||||
],
|
||||
[
|
||||
-73.576305247758725,
|
||||
45.493918219120054
|
||||
],
|
||||
[
|
||||
-73.57630587381702,
|
||||
45.493918521049629
|
||||
],
|
||||
[
|
||||
-73.57630737431063,
|
||||
45.493919246221878
|
||||
],
|
||||
[
|
||||
-73.576309884937643,
|
||||
45.493916661990525
|
||||
],
|
||||
[
|
||||
-73.576312395564457,
|
||||
45.493914077759158
|
||||
],
|
||||
[
|
||||
-73.576311646601368,
|
||||
45.493913718321629
|
||||
],
|
||||
[
|
||||
-73.57631089891899,
|
||||
45.493913359783129
|
||||
],
|
||||
[
|
||||
-73.576309642965299,
|
||||
45.493912756826411
|
||||
],
|
||||
[
|
||||
-73.576307858246111,
|
||||
45.493911892368182
|
||||
],
|
||||
[
|
||||
-73.576306072248741,
|
||||
45.493911028810601
|
||||
],
|
||||
[
|
||||
-73.576303966191389,
|
||||
45.493910018792064
|
||||
],
|
||||
[
|
||||
-73.576301858855928,
|
||||
45.493909009674262
|
||||
],
|
||||
[
|
||||
-73.576301333936073,
|
||||
45.493908753569144
|
||||
],
|
||||
[
|
||||
-73.576300809016217,
|
||||
45.493908497464098
|
||||
],
|
||||
[
|
||||
-73.576295787761836,
|
||||
45.493913665926286
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.576281868077018,
|
||||
45.493911355423414
|
||||
],
|
||||
[
|
||||
-73.576278944759551,
|
||||
45.493914363756595
|
||||
],
|
||||
[
|
||||
-73.576278760774173,
|
||||
45.49391455284681
|
||||
],
|
||||
[
|
||||
-73.576276536337616,
|
||||
45.493916837238075
|
||||
],
|
||||
[
|
||||
-73.576274654320343,
|
||||
45.493918771361088
|
||||
],
|
||||
[
|
||||
-73.57628199417168,
|
||||
45.493922304648777
|
||||
],
|
||||
[
|
||||
-73.57628293325989,
|
||||
45.493921336688672
|
||||
],
|
||||
[
|
||||
-73.576283872348057,
|
||||
45.493920368728524
|
||||
],
|
||||
[
|
||||
-73.576286287163398,
|
||||
45.493917892543038
|
||||
],
|
||||
[
|
||||
-73.576289213052945,
|
||||
45.493914894106311
|
||||
],
|
||||
[
|
||||
-73.576289570800171,
|
||||
45.493914524931085
|
||||
],
|
||||
[
|
||||
-73.576289928547396,
|
||||
45.493914155755824
|
||||
],
|
||||
[
|
||||
-73.576286259255554,
|
||||
45.493912384612671
|
||||
],
|
||||
[
|
||||
-73.576282589965118,
|
||||
45.493910614369184
|
||||
],
|
||||
[
|
||||
-73.576281868077018,
|
||||
45.493911355423414
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.576307347890392,
|
||||
45.493923367527955
|
||||
],
|
||||
[
|
||||
-73.576306983746036,
|
||||
45.493923736707529
|
||||
],
|
||||
[
|
||||
-73.576304085996327,
|
||||
45.493926728826999
|
||||
],
|
||||
[
|
||||
-73.576302870921879,
|
||||
45.493927974123842
|
||||
],
|
||||
[
|
||||
-73.576301655848624,
|
||||
45.493929220320432
|
||||
],
|
||||
[
|
||||
-73.576300716760628,
|
||||
45.493930188280771
|
||||
],
|
||||
[
|
||||
-73.57629977767256,
|
||||
45.49393115624099
|
||||
],
|
||||
[
|
||||
-73.576307112405672,
|
||||
45.493934686830961
|
||||
],
|
||||
[
|
||||
-73.576308055330799,
|
||||
45.493933717968225
|
||||
],
|
||||
[
|
||||
-73.576308998255868,
|
||||
45.493932749105475
|
||||
],
|
||||
[
|
||||
-73.576310210772562,
|
||||
45.493931504710126
|
||||
],
|
||||
[
|
||||
-73.57631142200978,
|
||||
45.493930260315651
|
||||
],
|
||||
[
|
||||
-73.576314332565914,
|
||||
45.493927277185904
|
||||
],
|
||||
[
|
||||
-73.576315046779513,
|
||||
45.493926537936289
|
||||
],
|
||||
[
|
||||
-73.576307712034833,
|
||||
45.493922998348388
|
||||
],
|
||||
[
|
||||
-73.576307347890392,
|
||||
45.493923367527955
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
[
|
||||
-73.576281214567445,
|
||||
45.493928627477864
|
||||
],
|
||||
[
|
||||
-73.57627870393371,
|
||||
45.493931208109188
|
||||
],
|
||||
[
|
||||
-73.576279757605903,
|
||||
45.493931715817787
|
||||
],
|
||||
[
|
||||
-73.57628396717584,
|
||||
45.493933745755605
|
||||
],
|
||||
[
|
||||
-73.576287542993938,
|
||||
45.493935461170913
|
||||
],
|
||||
[
|
||||
-73.576288916739799,
|
||||
45.493936125238591
|
||||
],
|
||||
[
|
||||
-73.576290290484408,
|
||||
45.493936788406444
|
||||
],
|
||||
[
|
||||
-73.576295325825015,
|
||||
45.493931627133833
|
||||
],
|
||||
[
|
||||
-73.576292573225402,
|
||||
45.49393030620076
|
||||
],
|
||||
[
|
||||
-73.576290782108643,
|
||||
45.493929441746488
|
||||
],
|
||||
[
|
||||
-73.576288990993191,
|
||||
45.49392857819204
|
||||
],
|
||||
[
|
||||
-73.576286883649999,
|
||||
45.493927563674859
|
||||
],
|
||||
[
|
||||
-73.576284776308086,
|
||||
45.493926550057552
|
||||
],
|
||||
[
|
||||
-73.57628425139427,
|
||||
45.493926298451555
|
||||
],
|
||||
[
|
||||
-73.576283726480384,
|
||||
45.493926046845594
|
||||
],
|
||||
[
|
||||
-73.576281214567445,
|
||||
45.493928627477864
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"properties":{
|
||||
"OBJECTID_12":71,
|
||||
"gml_id":"Groupe9998743",
|
||||
"gml_parent":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_ta":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_fe":"cityObjectMember",
|
||||
"citygml__1":" ",
|
||||
"citygml__2":" ",
|
||||
"gml_descri":" ",
|
||||
"gml_name":" ",
|
||||
"citygml_cr":" ",
|
||||
"citygml_te":" ",
|
||||
"externalRe":" ",
|
||||
"external_1":" ",
|
||||
"external_2":" ",
|
||||
"citygml_ge":" ",
|
||||
"citygml_re":" ",
|
||||
"citygml__3":" ",
|
||||
"citygml_ap":" ",
|
||||
"citygml_cl":" ",
|
||||
"citygml__4":" ",
|
||||
"citygml_fu":" ",
|
||||
"citygml__5":" ",
|
||||
"citygml_us":" ",
|
||||
"citygml__6":" ",
|
||||
"citygml_ye":" ",
|
||||
"citygml__7":" ",
|
||||
"citygml_ro":" ",
|
||||
"citygml__8":" ",
|
||||
"citygml_me":33.756,
|
||||
"citygml__9":"#m",
|
||||
"citygml_st":" ",
|
||||
"citygml_10":" ",
|
||||
"citygml_11":" ",
|
||||
"citygml_12":" ",
|
||||
"citygml_13":" ",
|
||||
"citygml_14":" ",
|
||||
"citygml_ou":" ",
|
||||
"citygml_in":" ",
|
||||
"citygml_bo":" ",
|
||||
"citygml_le":" ",
|
||||
"citygml_15":" ",
|
||||
"citygml_co":" ",
|
||||
"citygml_ad":" ",
|
||||
"Volume":"198.772",
|
||||
"parcelle":" ",
|
||||
"OBJECTID":7095,
|
||||
"gml_id_1":"8c3496a9-534a-49c2-80ee-8ef0651c1675",
|
||||
"gml_pare_1":"Groupe9998743",
|
||||
"citygml_16":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_17":"boundedBy",
|
||||
"citygml_18":" ",
|
||||
"citygml_19":" ",
|
||||
"gml_desc_1":" ",
|
||||
"gml_name_1":" ",
|
||||
"citygml_20":" ",
|
||||
"citygml_21":" ",
|
||||
"external_3":" ",
|
||||
"external_4":" ",
|
||||
"external_5":" ",
|
||||
"citygml_22":" ",
|
||||
"citygml_23":" ",
|
||||
"citygml_24":" ",
|
||||
"citygml_25":" ",
|
||||
"citygml_26":" ",
|
||||
"citygml_op":" ",
|
||||
"Area":"11.527",
|
||||
"FID_":0,
|
||||
"Join_Count":2,
|
||||
"TARGET_FID":7100,
|
||||
"gml_id_12":"Groupe9998743",
|
||||
"gml_pare_2":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_27":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_28":"cityObjectMember",
|
||||
"citygml_29":" ",
|
||||
"citygml_30":" ",
|
||||
"gml_desc_2":" ",
|
||||
"gml_name_2":" ",
|
||||
"citygml_31":" ",
|
||||
"citygml_32":" ",
|
||||
"external_6":" ",
|
||||
"external_7":" ",
|
||||
"external_8":" ",
|
||||
"citygml_33":" ",
|
||||
"citygml_34":" ",
|
||||
"citygml_35":" ",
|
||||
"citygml_36":" ",
|
||||
"citygml_37":" ",
|
||||
"citygml_38":" ",
|
||||
"citygml_39":" ",
|
||||
"citygml_40":" ",
|
||||
"citygml_41":" ",
|
||||
"citygml_42":" ",
|
||||
"citygml_43":" ",
|
||||
"citygml_44":" ",
|
||||
"citygml_45":" ",
|
||||
"citygml_46":" ",
|
||||
"citygml_47":33.756,
|
||||
"citygml_48":"#m",
|
||||
"citygml_49":" ",
|
||||
"citygml_50":" ",
|
||||
"citygml_51":" ",
|
||||
"citygml_52":" ",
|
||||
"citygml_53":" ",
|
||||
"citygml_54":" ",
|
||||
"citygml_55":" ",
|
||||
"citygml_56":" ",
|
||||
"citygml_57":" ",
|
||||
"citygml_58":" ",
|
||||
"citygml_59":" ",
|
||||
"citygml_60":" ",
|
||||
"citygml_61":" ",
|
||||
"Volume_1":"198.772",
|
||||
"Field":0,
|
||||
"Field1":0,
|
||||
"OBJECTID_1":7095,
|
||||
"gml_id_12_":"8c3496a9-534a-49c2-80ee-8ef0651c1675",
|
||||
"gml_pare_3":"Groupe9998743",
|
||||
"citygml_62":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_63":"boundedBy",
|
||||
"citygml_64":" ",
|
||||
"citygml_65":" ",
|
||||
"gml_desc_3":" ",
|
||||
"gml_name_3":" ",
|
||||
"citygml_66":" ",
|
||||
"citygml_67":" ",
|
||||
"external_9":" ",
|
||||
"externa_10":" ",
|
||||
"externa_11":" ",
|
||||
"citygml_68":" ",
|
||||
"citygml_69":" ",
|
||||
"citygml_70":" ",
|
||||
"citygml_71":" ",
|
||||
"citygml_72":" ",
|
||||
"citygml_73":" ",
|
||||
"Area_1":"11.527",
|
||||
"cityGML_hi":0,
|
||||
"Z_Min":39.7303,
|
||||
"Z_Max":72.902000000000001,
|
||||
"Shape_Leng":28.686961738400001,
|
||||
"ID_UEV":"05221230",
|
||||
"CIVIQUE_DE":" 1190",
|
||||
"CIVIQUE_FI":" 1200",
|
||||
"NOM_RUE":"rue Guy (MTL)",
|
||||
"MUNICIPALI":"50",
|
||||
"ETAGE_HORS":3,
|
||||
"NOMBRE_LOG":3,
|
||||
"ANNEE_CONS":2012,
|
||||
"CODE_UTILI":"6243",
|
||||
"LIBELLE_UT":"Mausolée",
|
||||
"CATEGORIE_":"Régulier",
|
||||
"MATRICULE8":"9839-72-8598-6-000-0000",
|
||||
"SUPERFICIE":511,
|
||||
"SUPERFIC_1":165,
|
||||
"NO_ARROND_":"REM19",
|
||||
"Shape_Le_1":0.0080267092725800002,
|
||||
"Shape_Ar_1":3.7307864896800001e-06,
|
||||
"Z_Min_1":null,
|
||||
"Z_Max_1":null,
|
||||
"Shape_Length":28.686961738422657,
|
||||
"Shape_Area":6.1056950551354507
|
||||
}
|
||||
}
|
||||
]}
|
257
hub/unittests/tests_data/concordia_80.geojson
Normal file
257
hub/unittests/tests_data/concordia_80.geojson
Normal file
|
@ -0,0 +1,257 @@
|
|||
{
|
||||
"type":"FeatureCollection",
|
||||
"features":[
|
||||
{
|
||||
"type":"Feature",
|
||||
"id":80,
|
||||
"geometry":{
|
||||
"type":"Polygon",
|
||||
"coordinates":[
|
||||
[
|
||||
[
|
||||
-73.577708862173409,
|
||||
45.496062468779222
|
||||
],
|
||||
[
|
||||
-73.578002412186507,
|
||||
45.495762215608373
|
||||
],
|
||||
[
|
||||
-73.578017041689648,
|
||||
45.495747250204211
|
||||
],
|
||||
[
|
||||
-73.578007567133241,
|
||||
45.495742667468747
|
||||
],
|
||||
[
|
||||
-73.578004398472899,
|
||||
45.49574590907234
|
||||
],
|
||||
[
|
||||
-73.577897155727669,
|
||||
45.495855628290393
|
||||
],
|
||||
[
|
||||
-73.577789912566104,
|
||||
45.4959653474059
|
||||
],
|
||||
[
|
||||
-73.577627737571262,
|
||||
45.49588695081647
|
||||
],
|
||||
[
|
||||
-73.577465563026294,
|
||||
45.495808553995417
|
||||
],
|
||||
[
|
||||
-73.577680024034251,
|
||||
45.495589134278653
|
||||
],
|
||||
[
|
||||
-73.577709868721371,
|
||||
45.495603565479428
|
||||
],
|
||||
[
|
||||
-73.577712104671733,
|
||||
45.495601273854334
|
||||
],
|
||||
[
|
||||
-73.577714340621938,
|
||||
45.495598982229176
|
||||
],
|
||||
[
|
||||
-73.57763021606263,
|
||||
45.495558325973803
|
||||
],
|
||||
[
|
||||
-73.577546091624328,
|
||||
45.495517669656074
|
||||
],
|
||||
[
|
||||
-73.57754291633033,
|
||||
45.49551608808553
|
||||
],
|
||||
[
|
||||
-73.577229611850498,
|
||||
45.49583656395032
|
||||
],
|
||||
[
|
||||
-73.577608042788611,
|
||||
45.496019551760313
|
||||
],
|
||||
[
|
||||
-73.577611901425541,
|
||||
45.496015589823621
|
||||
],
|
||||
[
|
||||
-73.577708862173409,
|
||||
45.496062468779222
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"properties":{
|
||||
"OBJECTID_12":80,
|
||||
"gml_id":"1066177",
|
||||
"gml_parent":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_ta":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_fe":"cityObjectMember",
|
||||
"citygml__1":" ",
|
||||
"citygml__2":" ",
|
||||
"gml_descri":" ",
|
||||
"gml_name":" ",
|
||||
"citygml_cr":" ",
|
||||
"citygml_te":" ",
|
||||
"externalRe":" ",
|
||||
"external_1":" ",
|
||||
"external_2":" ",
|
||||
"citygml_ge":" ",
|
||||
"citygml_re":" ",
|
||||
"citygml__3":" ",
|
||||
"citygml_ap":" ",
|
||||
"citygml_cl":" ",
|
||||
"citygml__4":" ",
|
||||
"citygml_fu":" ",
|
||||
"citygml__5":" ",
|
||||
"citygml_us":" ",
|
||||
"citygml__6":" ",
|
||||
"citygml_ye":" ",
|
||||
"citygml__7":" ",
|
||||
"citygml_ro":" ",
|
||||
"citygml__8":" ",
|
||||
"citygml_me":46.639000000000003,
|
||||
"citygml__9":"#m",
|
||||
"citygml_st":" ",
|
||||
"citygml_10":" ",
|
||||
"citygml_11":" ",
|
||||
"citygml_12":" ",
|
||||
"citygml_13":" ",
|
||||
"citygml_14":" ",
|
||||
"citygml_ou":" ",
|
||||
"citygml_in":" ",
|
||||
"citygml_bo":" ",
|
||||
"citygml_le":" ",
|
||||
"citygml_15":" ",
|
||||
"citygml_co":" ",
|
||||
"citygml_ad":" ",
|
||||
"Volume":"47396.897",
|
||||
"parcelle":" ",
|
||||
"OBJECTID":7117,
|
||||
"gml_id_1":"d2de57c7-c360-4f28-9695-dc1be766360b",
|
||||
"gml_pare_1":"1066177",
|
||||
"citygml_16":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_17":"boundedBy",
|
||||
"citygml_18":" ",
|
||||
"citygml_19":" ",
|
||||
"gml_desc_1":" ",
|
||||
"gml_name_1":" ",
|
||||
"citygml_20":" ",
|
||||
"citygml_21":" ",
|
||||
"external_3":" ",
|
||||
"external_4":" ",
|
||||
"external_5":" ",
|
||||
"citygml_22":" ",
|
||||
"citygml_23":" ",
|
||||
"citygml_24":" ",
|
||||
"citygml_25":" ",
|
||||
"citygml_26":" ",
|
||||
"citygml_op":" ",
|
||||
"Area":"1016.244",
|
||||
"FID_":0,
|
||||
"Join_Count":1,
|
||||
"TARGET_FID":7122,
|
||||
"gml_id_12":"1066177",
|
||||
"gml_pare_2":"fme-gen-57964590-baa9-48a7-99b0-fa11ca012d7c",
|
||||
"citygml_27":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_28":"cityObjectMember",
|
||||
"citygml_29":" ",
|
||||
"citygml_30":" ",
|
||||
"gml_desc_2":" ",
|
||||
"gml_name_2":" ",
|
||||
"citygml_31":" ",
|
||||
"citygml_32":" ",
|
||||
"external_6":" ",
|
||||
"external_7":" ",
|
||||
"external_8":" ",
|
||||
"citygml_33":" ",
|
||||
"citygml_34":" ",
|
||||
"citygml_35":" ",
|
||||
"citygml_36":" ",
|
||||
"citygml_37":" ",
|
||||
"citygml_38":" ",
|
||||
"citygml_39":" ",
|
||||
"citygml_40":" ",
|
||||
"citygml_41":" ",
|
||||
"citygml_42":" ",
|
||||
"citygml_43":" ",
|
||||
"citygml_44":" ",
|
||||
"citygml_45":" ",
|
||||
"citygml_46":" ",
|
||||
"citygml_47":46.639000000000003,
|
||||
"citygml_48":"#m",
|
||||
"citygml_49":" ",
|
||||
"citygml_50":" ",
|
||||
"citygml_51":" ",
|
||||
"citygml_52":" ",
|
||||
"citygml_53":" ",
|
||||
"citygml_54":" ",
|
||||
"citygml_55":" ",
|
||||
"citygml_56":" ",
|
||||
"citygml_57":" ",
|
||||
"citygml_58":" ",
|
||||
"citygml_59":" ",
|
||||
"citygml_60":" ",
|
||||
"citygml_61":" ",
|
||||
"Volume_1":"47396.897",
|
||||
"Field":0,
|
||||
"Field1":0,
|
||||
"OBJECTID_1":7117,
|
||||
"gml_id_12_":"d2de57c7-c360-4f28-9695-dc1be766360b",
|
||||
"gml_pare_3":"1066177",
|
||||
"citygml_62":"http://www.opengis.net/citygml/building/2.0",
|
||||
"citygml_63":"boundedBy",
|
||||
"citygml_64":" ",
|
||||
"citygml_65":" ",
|
||||
"gml_desc_3":" ",
|
||||
"gml_name_3":" ",
|
||||
"citygml_66":" ",
|
||||
"citygml_67":" ",
|
||||
"external_9":" ",
|
||||
"externa_10":" ",
|
||||
"externa_11":" ",
|
||||
"citygml_68":" ",
|
||||
"citygml_69":" ",
|
||||
"citygml_70":" ",
|
||||
"citygml_71":" ",
|
||||
"citygml_72":" ",
|
||||
"citygml_73":" ",
|
||||
"Area_1":"1016.244",
|
||||
"cityGML_hi":0,
|
||||
"Z_Min":41.489699999999999,
|
||||
"Z_Max":88.129000000000005,
|
||||
"Shape_Leng":242.34118937100001,
|
||||
"ID_UEV":"01111020",
|
||||
"CIVIQUE_DE":" 1515",
|
||||
"CIVIQUE_FI":" 1515",
|
||||
"NOM_RUE":"rue Sainte-Catherine Ouest (MTL+WMT)",
|
||||
"MUNICIPALI":"50",
|
||||
"ETAGE_HORS":17,
|
||||
"NOMBRE_LOG":1,
|
||||
"ANNEE_CONS":2005,
|
||||
"CODE_UTILI":"6821",
|
||||
"LIBELLE_UT":"Université",
|
||||
"CATEGORIE_":"Régulier",
|
||||
"MATRICULE8":"9839-75-0526-8-000-0000",
|
||||
"SUPERFICIE":5949,
|
||||
"SUPERFIC_1":259,
|
||||
"NO_ARROND_":"REM19",
|
||||
"Shape_Le_1":0.0037693215640499998,
|
||||
"Shape_Ar_1":6.8474298198599997e-07,
|
||||
"Z_Min_1":null,
|
||||
"Z_Max_1":null,
|
||||
"Shape_Length":242.34118937110796,
|
||||
"Shape_Area":1016.243978548841
|
||||
}
|
||||
}
|
||||
]}
|
24156
hub/unittests/tests_outputs/Montréal.obj
Normal file
24156
hub/unittests/tests_outputs/Montréal.obj
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user