diff --git a/catalogs/catalog.py b/catalogs/catalog.py
new file mode 100644
index 00000000..ed272383
--- /dev/null
+++ b/catalogs/catalog.py
@@ -0,0 +1,33 @@
+"""
+Catalog base class
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+
+class Catalog:
+ """
+ Catalog name
+ """
+
+ @property
+ def names(self):
+ """
+ Base property to return the catalog entries names
+ :return: not implemented error
+ """
+ raise NotImplementedError
+
+ @property
+ def entries(self):
+ """
+ Base property to return the catalog entries
+ :return: not implemented error
+ """
+ raise NotImplementedError
+
+ def get_entry(self, name):
+ """
+ Base property to return the catalog entry matching the given name
+ :return: not implemented error
+ """
+ raise NotImplementedError
diff --git a/catalogs/greenery/ecore_greenery/greenerycatalog.ecore b/catalogs/greenery/ecore_greenery/greenerycatalog.ecore
new file mode 100644
index 00000000..5c3bb85d
--- /dev/null
+++ b/catalogs/greenery/ecore_greenery/greenerycatalog.ecore
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/catalogs/greenery/ecore_greenery/greenerycatalog.py b/catalogs/greenery/ecore_greenery/greenerycatalog.py
new file mode 100644
index 00000000..30ac116c
--- /dev/null
+++ b/catalogs/greenery/ecore_greenery/greenerycatalog.py
@@ -0,0 +1,318 @@
+"""Definition of meta model 'greenerycatalog'."""
+from functools import partial
+import pyecore.ecore as Ecore
+from pyecore.ecore import *
+
+
+name = 'greenerycatalog'
+nsURI = 'http://ca.concordia/greenerycatalog'
+nsPrefix = 'greenery'
+
+eClass = EPackage(name=name, nsURI=nsURI, nsPrefix=nsPrefix)
+
+eClassifiers = {}
+getEClassifier = partial(Ecore.getEClassifier, searchspace=eClassifiers)
+Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA'])
+
+Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough',
+ 'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'])
+
+
+class Soil(EObject, metaclass=MetaEClass):
+
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ roughness = EAttribute(eType=Roughness, unique=True, derived=False,
+ changeable=True, default_value=Roughness.MediumRough)
+ conductivityOfDrySoil = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)')
+ densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='1100 kg/m³')
+ specificHeatOfDrySoil = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)')
+ thermalAbsorptance = EAttribute(eType=EString, unique=True,
+ derived=False, changeable=True, default_value='0.9')
+ solarAbsorptance = EAttribute(eType=EString, unique=True,
+ derived=False, changeable=True, default_value='0.7')
+ visibleAbsorptance = EAttribute(eType=EString, unique=True,
+ derived=False, changeable=True, default_value='0.75')
+ saturationVolumetricMoistureContent = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='0.0')
+ residualVolumetricMoistureContent = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='0.05')
+ initialVolumetricMoistureContent = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='0.1')
+
+ def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if roughness is not None:
+ self.roughness = roughness
+
+ if conductivityOfDrySoil is not None:
+ self.conductivityOfDrySoil = conductivityOfDrySoil
+
+ if densityOfDrySoil is not None:
+ self.densityOfDrySoil = densityOfDrySoil
+
+ if specificHeatOfDrySoil is not None:
+ self.specificHeatOfDrySoil = specificHeatOfDrySoil
+
+ if thermalAbsorptance is not None:
+ self.thermalAbsorptance = thermalAbsorptance
+
+ if solarAbsorptance is not None:
+ self.solarAbsorptance = solarAbsorptance
+
+ if visibleAbsorptance is not None:
+ self.visibleAbsorptance = visibleAbsorptance
+
+ if saturationVolumetricMoistureContent is not None:
+ self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent
+
+ if residualVolumetricMoistureContent is not None:
+ self.residualVolumetricMoistureContent = residualVolumetricMoistureContent
+
+ if initialVolumetricMoistureContent is not None:
+ self.initialVolumetricMoistureContent = initialVolumetricMoistureContent
+
+
+class Plant(EObject, metaclass=MetaEClass):
+
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ height = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='0.1 m')
+ leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='2.5')
+ leafReflectivity = EAttribute(eType=EString, unique=True,
+ derived=False, changeable=True, default_value='0.1')
+ leafEmissivity = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='0.9')
+ minimalStomatalResistance = EAttribute(
+ eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m')
+ co2Sequestration = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='kgCO₂eq')
+ growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1)
+
+ def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if height is not None:
+ self.height = height
+
+ if leafAreaIndex is not None:
+ self.leafAreaIndex = leafAreaIndex
+
+ if leafReflectivity is not None:
+ self.leafReflectivity = leafReflectivity
+
+ if leafEmissivity is not None:
+ self.leafEmissivity = leafEmissivity
+
+ if minimalStomatalResistance is not None:
+ self.minimalStomatalResistance = minimalStomatalResistance
+
+ if co2Sequestration is not None:
+ self.co2Sequestration = co2Sequestration
+
+ if growsOn:
+ self.growsOn.extend(growsOn)
+
+
+class SupportEnvelope(EObject, metaclass=MetaEClass):
+
+ roughness = EAttribute(eType=Roughness, unique=True, derived=False,
+ changeable=True, default_value=Roughness.MediumRough)
+ solarAbsorptance = EAttribute(eType=EDouble, unique=True,
+ derived=False, changeable=True, default_value=0.0)
+ conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
+ changeable=True, default_value=0.0)
+ visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
+ derived=False, changeable=True, default_value=0.0)
+ specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
+ changeable=True, default_value=0.0)
+ density = EAttribute(eType=EDouble, unique=True, derived=False,
+ changeable=True, default_value=0.0)
+ thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
+ derived=False, changeable=True, default_value=0.0)
+
+ def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if roughness is not None:
+ self.roughness = roughness
+
+ if solarAbsorptance is not None:
+ self.solarAbsorptance = solarAbsorptance
+
+ if conductivity is not None:
+ self.conductivity = conductivity
+
+ if visibleAbsorptance is not None:
+ self.visibleAbsorptance = visibleAbsorptance
+
+ if specificHeat is not None:
+ self.specificHeat = specificHeat
+
+ if density is not None:
+ self.density = density
+
+ if thermalAbsorptance is not None:
+ self.thermalAbsorptance = thermalAbsorptance
+
+
+class GreeneryCatalog(EObject, metaclass=MetaEClass):
+
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ description = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ source = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ plantCategories = EReference(ordered=True, unique=True,
+ containment=True, derived=False, upper=-1)
+ vegetationCategories = EReference(ordered=True, unique=True,
+ containment=True, derived=False, upper=-1)
+ soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
+
+ def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if description is not None:
+ self.description = description
+
+ if source is not None:
+ self.source = source
+
+ if plantCategories:
+ self.plantCategories.extend(plantCategories)
+
+ if vegetationCategories:
+ self.vegetationCategories.extend(vegetationCategories)
+
+ if soils:
+ self.soils.extend(soils)
+
+
+class PlantCategory(EObject, metaclass=MetaEClass):
+ """Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."""
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
+
+ def __init__(self, *, name=None, plants=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if plants:
+ self.plants.extend(plants)
+
+
+class IrrigationSchedule(EObject, metaclass=MetaEClass):
+
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+
+ def __init__(self, *, name=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+
+class Vegetation(EObject, metaclass=MetaEClass):
+ """Plant life or total plant cover (as of an area)"""
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='20 cm')
+ management = EAttribute(eType=Management, unique=True, derived=False,
+ changeable=True, default_value=Management.NA)
+ airGap = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='0.0 cm')
+ soil = EReference(ordered=True, unique=True, containment=False, derived=False)
+ plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
+
+ def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if thicknessOfSoil is not None:
+ self.thicknessOfSoil = thicknessOfSoil
+
+ if management is not None:
+ self.management = management
+
+ if airGap is not None:
+ self.airGap = airGap
+
+ if soil is not None:
+ self.soil = soil
+
+ if plants:
+ self.plants.extend(plants)
+
+
+class VegetationCategory(EObject, metaclass=MetaEClass):
+ """Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."""
+ name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
+ vegetationTemplates = EReference(ordered=True, unique=True,
+ containment=True, derived=False, upper=-1)
+
+ def __init__(self, *, vegetationTemplates=None, name=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if name is not None:
+ self.name = name
+
+ if vegetationTemplates:
+ self.vegetationTemplates.extend(vegetationTemplates)
+
+
+class PlantPercentage(EObject, metaclass=MetaEClass):
+
+ percentage = EAttribute(eType=EString, unique=True, derived=False,
+ changeable=True, default_value='100')
+ plant = EReference(ordered=True, unique=True, containment=False, derived=False)
+
+ def __init__(self, *, percentage=None, plant=None):
+ # if kwargs:
+ # raise AttributeError('unexpected arguments: {}'.format(kwargs))
+
+ super().__init__()
+
+ if percentage is not None:
+ self.percentage = percentage
+
+ if plant is not None:
+ self.plant = plant
diff --git a/catalogs/greenery/ecore_greenery/greenerycatalog_no_quantities.ecore b/catalogs/greenery/ecore_greenery/greenerycatalog_no_quantities.ecore
new file mode 100644
index 00000000..db58a9c0
--- /dev/null
+++ b/catalogs/greenery/ecore_greenery/greenerycatalog_no_quantities.ecore
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/catalogs/greenery/greenery_catalog.py b/catalogs/greenery/greenery_catalog.py
new file mode 100644
index 00000000..3ede5ab9
--- /dev/null
+++ b/catalogs/greenery/greenery_catalog.py
@@ -0,0 +1,41 @@
+"""
+Greenery catalog
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+
+from pyecore.resources import ResourceSet, URI
+from catalogs.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as gc
+from catalogs.catalog import Catalog
+from pathlib import Path
+
+
+class GreeneryCatalog(Catalog):
+
+ def __init__(self, path):
+ base_path = Path(Path(__file__).parent / 'ecore_greenery' / 'greenerycatalog_no_quantities.ecore')
+ resource_set = ResourceSet()
+ data_model = resource_set.get_resource(URI(str(base_path)))
+ data_model_root = data_model.contents[0]
+ resource_set.metamodel_registry[data_model_root.nsURI] = data_model_root
+ resource = resource_set.get_resource(URI(str(path)))
+ catalog_data: gc = resource.contents[0]
+ self._data = {'vegetation': []}
+ vegetation = []
+ for vegetation_category in catalog_data.vegetationCategories:
+ vegetation.append({vegetation_category.name: []})
+ self._data['vegetation'] = vegetation
+
+ @property
+ def names(self):
+ """
+ :parm:
+ """
+ _names = []
+ for category in self._data:
+ for value in self._data[category]:
+ for key in value.keys():
+ _names.append(key)
+ return _names
+
+
diff --git a/catalogs/greenery_catalog_factory.py b/catalogs/greenery_catalog_factory.py
new file mode 100644
index 00000000..8e7dfe29
--- /dev/null
+++ b/catalogs/greenery_catalog_factory.py
@@ -0,0 +1,44 @@
+"""
+Greenery catalog publish the greenery information
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+
+from pathlib import Path
+from catalogs.greenery.greenery_catalog import GreeneryCatalog
+
+
+class GreeneryCatalogFactory:
+ """
+ GeometryFactory class
+ """
+ def __init__(self, file_type, base_path=None):
+ if base_path is None:
+ base_path = Path(Path(__file__).parent.parent / 'data/greenery')
+ self._file_type = '_' + file_type.lower()
+ self._path = base_path
+
+ @property
+ def _nrel(self) -> GreeneryCatalog:
+ """
+ Return a greenery catalog using ecore as datasource
+ :return: GreeneryCatalog
+ """
+ print('greenery')
+ return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())
+
+ @property
+ def catalog(self) -> GreeneryCatalog:
+ """
+ Enrich the city given to the class using the class given handler
+ :return: City
+ """
+ return getattr(self, self._file_type, lambda: None)
+
+ @property
+ def catalog_debug(self) -> GreeneryCatalog:
+ """
+ Enrich the city given to the class using the class given handler
+ :return: City
+ """
+ return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())
\ No newline at end of file
diff --git a/data/greenery/ecore_greenery_catalog.xml b/data/greenery/ecore_greenery_catalog.xml
new file mode 100644
index 00000000..41b7801c
--- /dev/null
+++ b/data/greenery/ecore_greenery_catalog.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imports/geometry/rhino.py b/imports/geometry/rhino.py
index 23df7202..38c350f0 100644
--- a/imports/geometry/rhino.py
+++ b/imports/geometry/rhino.py
@@ -3,6 +3,7 @@ Rhino module parses rhino files and import the geometry into the city model stru
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
+import numpy as np
from numpy import inf
from rhino3dm import *
from rhino3dm._rhino3dm import MeshType