Additional changes, the db_control building info need to be changed

This commit is contained in:
Guille Gutierrez 2023-07-28 14:55:06 -04:00
parent f95c45660e
commit eb246a18e6
9 changed files with 46 additions and 197 deletions

View File

@ -1,144 +0,0 @@
"""
Rhino module parses rhino files and import the geometry into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.capip
"""
import numpy as np
from rhino3dm import *
from rhino3dm._rhino3dm import Extrusion, MeshType, File3dm
from hub.city_model_structure.attributes.point import Point
from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.building import Building
from hub.city_model_structure.building_demand.surface import Surface as HubSurface
from hub.city_model_structure.city import City
from hub.helpers.configuration_helper import ConfigurationHelper
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
class Rhino:
"""
Rhino class
"""
def __init__(self, path):
self._model = File3dm.Read(str(path))
max_float = float(ConfigurationHelper().max_coordinate)
min_float = float(ConfigurationHelper().min_coordinate)
self._min_x = self._min_y = self._min_z = max_float
self._max_x = self._max_y = self._max_z = min_float
@staticmethod
def _in_perimeter(wall, corner):
res = wall.contains_point(Point(corner))
return res
@staticmethod
def _add_hole(solid_polygon, hole):
first = solid_polygon.points[0]
points = first + hole.points + solid_polygon.points
return Polygon(points)
@staticmethod
def _solid_points(coordinates) -> np.ndarray:
solid_points = np.fromstring(coordinates, dtype=float, sep=' ')
solid_points = GeometryHelper.to_points_matrix(solid_points)
result = []
found = False
for row in solid_points:
for row2 in result:
if row[0] == row2[0] and row[1] == row2[1] and row[2] == row2[2]:
found = True
if not found:
result.append(row)
return solid_points
def _corners(self, point):
if point.X < self._min_x:
self._min_x = point.X
if point.Y < self._min_y:
self._min_y = point.Y
if point.Z < self._min_z:
self._min_z = point.Z
if point.X > self._max_x:
self._max_x = point.X
if point.Y > self._max_y:
self._max_y = point.Y
if point.Z > self._max_z:
self._max_z = point.Z
def _add_face(self, face):
hub_surfaces = []
_mesh = face.GetMesh(MeshType.Default)
for i in range(0, len(_mesh.Faces)):
mesh_faces = _mesh.Faces[i]
_points = ''
faces = []
for index in mesh_faces:
if index in faces:
continue
faces.append(index)
self._corners(_mesh.Vertices[index])
_points = _points + f'{_mesh.Vertices[index].X} {_mesh.Vertices[index].Y} {_mesh.Vertices[index].Z} '
polygon_points = Rhino._solid_points(_points.strip())
hub_surfaces.append(HubSurface(Polygon(polygon_points), Polygon(polygon_points)))
return hub_surfaces
@property
def city(self) -> City:
"""
Return a city based in the rhino file
:return: City
"""
buildings = []
city_objects = [] # building and "windows"
windows = []
_prev_name = ''
for obj in self._model.Objects:
name = obj.Attributes.Id
hub_surfaces = []
if isinstance(obj.Geometry, Extrusion):
surface = obj.Geometry
hub_surfaces = hub_surfaces + self._add_face(surface)
else:
for face in obj.Geometry.Faces:
if face is None:
break
hub_surfaces = hub_surfaces + self._add_face(face)
building = Building(name, hub_surfaces, 'unknown', 'unknown', [])
city_objects.append(building)
lower_corner = (self._min_x, self._min_y, self._min_z)
upper_corner = (self._max_x, self._max_y, self._max_z)
city = City(lower_corner, upper_corner, 'EPSG:26918')
for building in city_objects:
if len(building.surfaces) <= 2:
# is not a building but a window!
for surface in building.surfaces:
# add to windows the "hole" with the normal inverted
windows.append(Polygon(surface.perimeter_polygon.inverse))
else:
buildings.append(building)
# todo: this method will be pretty inefficient
for hole in windows:
corner = hole.coordinates[0]
for building in buildings:
for surface in building.surfaces:
plane = surface.perimeter_polygon.plane
# todo: this is a hack for dompark project it should not be done this way windows should be correctly modeled
# if the distance between the wall plane and the window is less than 2m
# and the window Z coordinate it's between the wall Z, it's a window of that wall
if plane.distance_to_point(corner) <= 2:
# check if the window is in the right high.
if surface.upper_corner[2] >= corner[2] >= surface.lower_corner[2]:
if surface.holes_polygons is None:
surface.holes_polygons = []
surface.holes_polygons.append(hole)
for building in buildings:
city.add_city_object(building)
building.level_of_detail.geometry = 3
city.level_of_detail.geometry = 3
return city

View File

@ -12,7 +12,6 @@ from hub.imports.geometry.citygml import CityGml
from hub.imports.geometry.geojson import Geojson
from hub.imports.geometry.gpandas import GPandas
from hub.imports.geometry.obj import Obj
from hub.imports.geometry.rhino import Rhino
class GeometryFactory:
@ -80,14 +79,6 @@ class GeometryFactory:
self._function_field,
self._function_to_hub).city
@property
def _rhino(self) -> City:
"""
Enrich the city by using Rhino information as data source
:return: City
"""
return Rhino(self._path).city
@property
def city(self) -> City:
"""

View File

@ -74,19 +74,31 @@ class DBControl:
"""
return self._city_object.get_by_name_or_alias_and_city(name, city_id)
def results(self, user_id, application_id, cities, result_names=None) -> Dict:
def buildings_info(self, request_values, city_id) -> [CityObject]:
"""
Retrieve the building info from the database
:param request_values: Building names
:param city_id: City ID
:return: [CityObject]
"""
buildings = []
for name in request_values['names']:
buildings.append(self._city_object.get_by_name_or_alias_and_city(name, city_id))
return buildings
def results(self, user_id, application_id, request_values, result_names=None) -> Dict:
"""
Retrieve the simulation results for the given cities from the database
:param user_id: the user id owning the results
:param application_id: the application id owning the results
:param cities: dictionary containing the city and building names for the results
:param request_values: dictionary containing the scenario and building names to grab the results
:param result_names: if given, filter the results to the selected names
"""
if result_names is None:
result_names = []
results = {}
for city in cities['cities']:
scenario_name = next(iter(city))
for scenario in request_values['scenarios']:
scenario_name = next(iter(scenario))
result_sets = self._city_repository.get_by_user_id_application_id_and_scenario(
user_id,
application_id,
@ -96,14 +108,13 @@ class DBControl:
continue
for result_set in result_sets:
city_id = result_set[0].id
print('city ids', city_id)
results[scenario_name] = []
for building_name in city[scenario_name]:
for building_name in scenario[scenario_name]:
_building = self._city_object.get_by_name_or_alias_and_city(building_name, city_id)
if _building is None:
continue
city_object_id = _building.id
print('city object ids', city_object_id)
_ = self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names(
city_id,
city_object_id,

View File

@ -104,15 +104,17 @@ class CityObject(Repository):
:return: [CityObject] with the provided name or alias belonging to the city with id city_id
"""
try:
_city_objects = self.session.execute(select(Model).where(
or_(Model.name == name, Model.aliases.contains(f'{name}')), Model.city_id == city_id
)).all()
for city_object in _city_objects:
if city_object[0].name == name:
return city_object[0]
# search by name first
city_object = self.session.execute(select(Model).where(Model.name == name, Model.city_id == city_id)).first()
if city_object is not None:
return city_object[0]
city_objects = self.session.execute(
select(Model).where(Model.aliases.contains(name), Model.city_id == city_id)
).all()
# name not found, so search by alias instead
for city_object in city_objects:
aliases = city_object[0].aliases.replace('{', '').replace('}', '').split(',')
for alias in aliases:
print(alias, name)
if alias == name:
# force the name as the alias
city_object[0].name = name

View File

@ -12,7 +12,6 @@ openpyxl
networkx
parseidf==1.0.0
ply
rhino3dm==7.7.0
scipy
PyYAML
pyecore==0.12.2

View File

@ -4,35 +4,34 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
import distutils.spawn
import glob
import json
import logging
import os
import subprocess
import unittest
from unittest import TestCase
from pathlib import Path
import sqlalchemy.exc
from unittest import TestCase
from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.results_factory import ResultFactory
from hub.imports.weather_factory import WeatherFactory
from hub.imports.energy_systems_factory import EnergySystemsFactory
import sqlalchemy.exc
from sqlalchemy import create_engine
from sqlalchemy.exc import ProgrammingError
import hub.helpers.constants as cte
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from hub.exports.exports_factory import ExportsFactory
from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.energy_systems_factory import EnergySystemsFactory
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.results_factory import ResultFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.persistence.db_control import DBControl
from hub.persistence.repository import Repository
from sqlalchemy import create_engine
from hub.persistence.models import City, Application, CityObject, SimulationResults
from hub.persistence.models import User, UserRoles
from hub.helpers.dictionaries import Dictionaries
from sqlalchemy.exc import ProgrammingError
import uuid
import hub.helpers.constants as cte
import distutils.spawn
from hub.persistence.repository import Repository
class Control:
@ -65,13 +64,13 @@ class Control:
self._skip_test = True
self._skip_reason = f'{operational_error}'
return
"""
Application.__table__.create(bind=repository.engine, checkfirst=True)
User.__table__.create(bind=repository.engine, checkfirst=True)
City.__table__.create(bind=repository.engine, checkfirst=True)
CityObject.__table__.create(bind=repository.engine, checkfirst=True)
SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
"""
city_file = Path('tests_data/test.geojson').resolve()
output_path = Path('tests_outputs/').resolve()
self._city = GeometryFactory('geojson',
@ -81,6 +80,7 @@ class Control:
aliases_field=['ID_UEV', 'CIVIQUE_DE', 'NOM_RUE'],
function_field='CODE_UTILI',
function_to_hub=MontrealFunctionToHubFunction().dictionary).city
ConstructionFactory('nrcan', self._city).enrich()
UsageFactory('nrcan', self._city).enrich()
WeatherFactory('epw', self._city).enrich()
@ -107,14 +107,13 @@ class Control:
self._application_id = 1
self._user_id = 1
"""
self._application_id = self._database.persist_application(
'City_layers',
'City layers test user',
self.application_uuid
)
self._user_id = self._database.create_user('city_layers', self._application_id, 'city_layers', UserRoles.Admin)
"""
self._pickle_path = 'tests_data/pickle_path.bz2'
@property

View File

@ -110,15 +110,6 @@ class TestGeometryFactory(TestCase):
self._check_surfaces(building)
city = ConstructionFactory('nrel', city).enrich()
def test_import_rhino(self):
"""
Test rhino import
"""
file = 'dompark.3dm'
city = self._get_city(file, 'rhino')
self.assertIsNotNone(city, 'city is none')
self.assertTrue(len(city.buildings) == 36)
def test_import_obj(self):
"""
Test obj import

Binary file not shown.

Binary file not shown.