Source code for omf.surface

"""surface.py: Surface element and geometry"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import numpy as np
import properties

from .base import ProjectElement, ProjectElementGeometry
from .data import Int3Array, ScalarArray, Vector3Array
from .texture import ImageTexture


[docs]class SurfaceGeometry(ProjectElementGeometry): """Contains spatial information about a triangulated surface""" vertices = properties.Instance( 'Spatial coordinates of vertices relative to surface origin', Vector3Array ) triangles = properties.Instance( 'Vertex indices of surface triangles', Int3Array ) _valid_locations = ('vertices', 'faces') def location_length(self, location): """Return correct data length based on location""" if location == 'faces': return self.num_cells return self.num_nodes @property def num_nodes(self): """get number of nodes""" return len(self.vertices) @property def num_cells(self): """get number of cells""" return len(self.triangles) @properties.validator def _validate_mesh(self): if np.min(self.triangles.array) < 0: raise ValueError('Triangles may only have positive integers') if np.max(self.triangles.array) >= len(self.vertices.array): raise ValueError('Triangles expects more vertices than provided') return True
[docs]class SurfaceGridGeometry(ProjectElementGeometry): """Contains spatial information of a 2D grid""" tensor_u = properties.Array( 'Grid cell widths, u-direction', shape=('*',), dtype=float ) tensor_v = properties.Array( 'Grid cell widths, v-direction', shape=('*',), dtype=float ) axis_u = properties.Vector3( 'Vector orientation of u-direction', default='X', length=1 ) axis_v = properties.Vector3( 'Vector orientation of v-direction', default='Y', length=1 ) offset_w = properties.Instance( 'Node offset', ScalarArray, required=False ) _valid_locations = ('vertices', 'faces') def location_length(self, location): """Return correct data length based on location""" if location == 'faces': return self.num_cells return self.num_nodes @property def num_nodes(self): """Number of nodes (vertices)""" return (len(self.tensor_u)+1) * (len(self.tensor_v)+1) @property def num_cells(self): """Number of cells (faces)""" return len(self.tensor_u) * len(self.tensor_v) @properties.validator def _validate_mesh(self): """Check if mesh content is built correctly""" if not np.abs(self.axis_u.dot(self.axis_v)) < 1e-6: #pylint: disable=no-member raise ValueError('axis_u and axis_v must be orthogonal') if self.offset_w is properties.undefined or self.offset_w is None: return True if len(self.offset_w.array) != self.num_nodes: raise ValueError( 'Length of offset_w, {zlen}, must equal number of nodes, ' '{nnode}'.format( zlen=len(self.offset_w), nnode=self.num_nodes ) ) return True
[docs]class SurfaceElement(ProjectElement): """Contains mesh, data, textures, and options of a surface""" geometry = properties.Union( 'Structure of the surface element', props=(SurfaceGeometry, SurfaceGridGeometry) ) textures = properties.List( 'Images mapped on the surface element', prop=ImageTexture, required=False, default=list, ) subtype = properties.StringChoice( 'Category of Surface', choices=('surface',), default='surface' )