### ===================================================================================================================
### FUNCTION: Get shapes for the result picture
### ===================================================================================================================
# Copyright ©VIIA 2024
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
from copy import deepcopy
from typing import TYPE_CHECKING, List, Union, Dict
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.shapes import Shapes, Reinforcements
from rhdhv_fem.connections import Connections, Interface
from rhdhv_fem.materials import Timber, ReinforcementSteel
from rhdhv_fem.fem_math import fem_parallel_vectors, fem_horizontal_vector_in_plane
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
### ===================================================================================================================
### 2. Function to get the shapes for the result picture based on the scope
### ===================================================================================================================
#
[docs]def viia_update_plot_config(project: ViiaProject, current_config: dict, component: str):
""" Helper function to update the result plot config with the correct dnb file name."""
result_plot_config = deepcopy(current_config)
result_plot_config.update({
'component': component,
'output_filename':
current_config['output_filename'].replace('SXXX', f'{project.name}_v{project.version}') + '.dnb',
'output_block_name': current_config['output_filename'].replace('SXXX_', '')})
return result_plot_config
[docs]def viia_get_scope_shape_sets(project: ViiaProject, scope: str, pic_type: str) \
-> Union[Dict[str, List[Shapes]], Dict[str, Dict[str, List[Union[Shapes, Connections]]]]]:
"""
This function collects the required shape-sets for the result pictures based on the scope definition. For example
the 'NoRoof' scope will hide the roof shapes for the result pictures.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- scope (str): The scope that defines the selection of shapes to be visible on the result picture. Select from
'building', 'noroof', 'floors-interstorey', 'walls-storey', 'beams-material-storey',
'columns-material-storey', 'floors-material-storey', 'interfaces-storey', 'floors-timber-storey',
'roofs-timber' or 'reinforcements-storey'.
Output:
- Returns list of shapes, or dictionary with subdivisions for different sets of shapes or connections. In the
last case multiple pictures are to be generated based on scope.
"""
def lines_material_storey(lines_layer: Dict[str, List[Shapes]]):
shapes = {}
for layer, lines in lines_layer.items():
shapes_material = {}
for line in lines:
line_mat = line.material.name.split('-DENSIT')[0]
if line_mat not in shapes_material:
shapes_material[line_mat] = []
shapes_material[line_mat].append(line)
shapes[layer] = shapes_material
return shapes
def surfaces_material_storey(surfaces_layer: Dict[str, List[Shapes]]):
shapes = {}
for layer, surfaces in surfaces_layer.items():
# Group shapes by material
shapes_material = {}
for surface in surfaces:
# For timber floor, make a distinction of plate or others, since plate has a higher capacity
if isinstance(surface.material, Timber) and 'PLATEN' not in surface.material.name:
material_key = 'LIN-HOUT'
elif isinstance(surface.material, Timber) and 'PLATEN' in surface.material.name:
material_key = 'PLATEN'
# Additional line for reinforcement
elif isinstance(surface.material, ReinforcementSteel):
material_key = 'WAPENING'
else:
material_key = surface.material.name.split('-DENSIT')[0]
# Check if key already present in shapes[layer]. If not, make new key in shapes[layer]
if material_key not in shapes_material:
shapes_material[material_key] = []
shapes_material[material_key].append(surface)
# For loop to split shape sets by geometry if required
shapes_material_geometry = {}
for original_key, shape_set in shapes_material.items():
shape_geometries = set([shape.geometry.name for shape in shape_set])
# Check if only one shape geometry is present
if len(shape_geometries) == 1:
shapes_material_geometry[original_key] = shape_set
continue
# Check if this shape set has timber shapes
if isinstance(shape_set[0].material, Timber):
shapes_material_geometry[original_key] = shape_set
continue
# If multiple shape geometries, and no timber floors, split up shape set by geometry
# Make a unique key per shape geometry
for shape_geometry in shape_geometries:
material_geometry_key = original_key + '-' + shape_geometry
shapes_material_geometry[material_geometry_key] = []
# Add shape in original shape set to the right new key
for shape in shape_set:
shapes_material_geometry[original_key + '-' + shape.geometry.name].append(shape)
shapes[layer] = shapes_material_geometry
return shapes
# Check input
if not isinstance(scope, str):
raise ValueError("ERROR: Scope to select the shapes for the result picture should be a string.")
scope = scope.lower()
if scope == 'building':
# All shapes in the building
return {'building': [shape for shape in project.collections.shapes if not isinstance(shape, Reinforcements)]}
elif 'reinforcements-storey' in scope:
# All shapes and reinforcements in the building per layer
reinforcement_layer = {layer.name: layer.reinforcements for layer in project.viia_get_layers() if layer.name[0] == 'N'}
return surfaces_material_storey(surfaces_layer=reinforcement_layer)
elif 'noroof' in scope:
# All shapes excluding the roof shapes (instances of Roof class)
return {'no_roof': [
shape for shape in project.collections.shapes
if shape not in project.collections.roofs and not isinstance(shape, Reinforcements)]}
elif 'noroof' not in scope and 'mode' in scope:
# All shapes excluding the roof shapes (instances of Roof class)
return {scope: [shape for shape in project.collections.shapes if not isinstance(shape, Reinforcements)]}
elif 'floors-interstorey' in scope:
# Collect the floors per layer, excluding foundation and basements
return {layer.name: layer.floors for layer in project.viia_get_layers() if layer.name[0] == 'N'}
elif 'walls-storey' in scope and 'CrackWidth' in pic_type or 'Static' in pic_type:
# Collect the walls per layer, excluding foundation and basements
return {layer.name: layer.walls for layer in project.viia_get_layers() if layer.name[0] == 'N'}
elif 'walls-storey' in scope and 'Dynamic' in pic_type:
# Collect the walls per layer, excluding foundation and basements
shape_sets = {}
for layer in project.viia_get_layers():
if layer.name[0] == 'N':
shape_sets[layer.name] = {}
shape_x = [
wall for wall in layer.walls if fem_parallel_vectors(
vector_1=fem_horizontal_vector_in_plane(
surface=[node.coordinates for node in wall.get_nodes()], precision=project.check_precision),
vector_2=[1.0, 0, 0], precision=project.check_precision)]
shape_y = [
wall for wall in layer.walls
if fem_parallel_vectors(
vector_1=fem_horizontal_vector_in_plane(
surface=[node.coordinates for node in wall.get_nodes()], precision=project.check_precision),
vector_2=[0, 1.0, 0], precision=project.check_precision)]
shape_sets[layer.name][f'{layer.name}_x'] = shape_x
shape_sets[layer.name][f'{layer.name}_y'] = shape_y
return shape_sets
elif 'beams-material-storey' in scope:
# Collect the beams per layer, excluding foundation and basements
# Sub-divide for different beam materials
beams_layer = {layer.name: layer.beams for layer in project.viia_get_layers() if layer.name[0] == 'N'}
return lines_material_storey(lines_layer=beams_layer)
elif 'columns-material-storey' in scope:
# Collect the columns per layer, excluding foundation and basements
# Sub-divide for different column materials
columns_layer = {layer.name: layer.columns for layer in project.viia_get_layers() if layer.name[0] == 'N'}
return lines_material_storey(lines_layer=columns_layer)
elif 'floors-material-storey' in scope:
# Collect the floors per layer, excluding foundation and basements
# Sub-divide for different floor materials
floors_layer = {layer.name: layer.floors for layer in project.viia_get_layers() if layer.name[0] == 'N'}
return surfaces_material_storey(surfaces_layer=floors_layer)
elif 'floors-timber-storey' in scope:
# Collect the timber floors per layer, excluding foundation and basements
# Sub-divide per timber material
floors_layer = {layer.name: layer.floors for layer in project.viia_get_layers() if layer.name[0] == 'N'}
timber_floors = {}
for layer, floors in floors_layer.items():
timber_floors[layer] = {}
for floor in floors:
if isinstance(floor.material, Timber):
# For timber floors, make a distinction of plate or others, since plate has a higher capacity
key = 'PLATEN' if 'PLATEN' in floor.name else 'LIN-HOUT'
if key not in timber_floors[layer]:
timber_floors[layer][key] = []
timber_floors[layer][key].append(floor)
return timber_floors
elif 'roofs-timber' in scope:
# Collect the roofs per timber material
timber_roofs = {'roof': {}}
for roof in project.collections.roofs:
if isinstance(roof.material, Timber):
# For timber roofs, make a distinction of plate or others, since plate has a higher capacity
key = 'PLATEN' if 'PLATEN' in roof.name else 'LIN-HOUT'
if key not in timber_roofs['roof']:
timber_roofs['roof'][key] = []
timber_roofs['roof'][key].append(roof)
return timber_roofs
elif 'roofs-material-storey' in scope:
# Collect the roofs per layer, excluding foundation and basements
# Sub-divide for different floor materials
roofs_layer = {layer.name: layer.roofs for layer in project.viia_get_layers() if layer.name[0] == 'N'}
return surfaces_material_storey(surfaces_layer=roofs_layer)
elif 'interfaces-storey' in scope:
connections_layer = {
layer.name: layer.get_connections() for layer in project.viia_get_layers()}
# Filter for interfaces only
for layer, connections in connections_layer.items():
for connection in reversed(connections):
if not isinstance(connection, Interface):
connections.remove(connection)
# Filter connections only in this layer or connecting to lower layer
ordered_layers = [layer for layer, connections in connections_layer.items()]
for enum, connection_layer in enumerate(connections_layer.items()):
if enum == len(connections_layer) - 1:
break
for connection in reversed(connection_layer[1]):
# Check if there are any connection between basement/foundation with the N0 level.
if enum + 1 < len(ordered_layers):
if ordered_layers[enum + 1] != 'N0' and connection_layer[0] in ['F', 'B']:
if connection.connecting_shapes['source_connecting_shape'].layer.name == 'N0' or \
connection.connecting_shapes['target_connecting_shape'].layer.name == 'N0':
connection_layer[1].remove(connection)
# Check if the layer of the connecting shapes is at a higher level or not.
if connection.connecting_shapes['source_connecting_shape'].layer.name == \
ordered_layers[enum + 1] or \
connection.connecting_shapes['target_connecting_shape'].layer.name == \
ordered_layers[enum + 1]:
connection_layer[1].remove(connection)
# Filter line and point interfaces
connection_sets_line = {}
connection_sets_point = {}
for layer, connections in connections_layer.items():
for connection in connections:
# Collect only line interfaces
if 'LIJN' in connection.name:
if f'{layer}_LIJN' not in connection_sets_line:
connection_sets_line[f'{layer}_LIJN'] = []
connection_sets_line[f'{layer}_LIJN'].append(connection)
elif 'PUNT' in connection.name:
if f'{layer}_PUNT' not in connection_sets_point:
connection_sets_point[f'{layer}_PUNT'] = []
connection_sets_point[f'{layer}_PUNT'].append(connection)
if 'line' in scope.lower():
return connection_sets_line
elif 'point' in scope.lower():
return connection_sets_point
else:
raise ValueError(f"ERROR: You need to specify if {scope} is a point interface or line interface.")
raise NotImplementedError(f"ERROR: '{scope}' is not a recognised result scope definition.")
### ===================================================================================================================
### 3. End of script
### ===================================================================================================================