Skip to content

Closes #133 - Added RegularGridSurface with tests and modified docs. #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
import sphinx_rtd_theme

html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
pass
except:
html_theme = "default"
Expand Down Expand Up @@ -313,10 +313,10 @@

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
"https://docs.python.org/": None,
"https://docs.python.org/": ("https://docs.python.org/", None),
# 'http://docs.scipy.org/doc/numpy/': None,
# 'http://docs.scipy.org/doc/scipy/reference/': None,
"http://propertiespy.readthedocs.io/en/latest/": None,
"http://propertiespy.readthedocs.io/en/latest/": ("http://propertiespy.readthedocs.io/en/latest/", None),
}
linkcheck_ignore = ["https://gmggroup.org"]
linkcheck_retries = 10
Expand Down
8 changes: 7 additions & 1 deletion docs/content/surface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ Elements

.. autoclass:: omf.surface.Surface

.. image:: /images/SurfaceGridGeometry.png
.. image:: /images/grid2_tensor.svg
:align: center

.. autoclass:: omf.surface.TensorGridSurface

.. image:: /images/grid2_regular.svg
:align: center

.. autoclass:: omf.surface.RegularGridSurface


Attributes
----------

Expand Down
Binary file removed docs/images/SurfaceGeometry.png
Binary file not shown.
431 changes: 431 additions & 0 deletions docs/images/grid2_regular.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
426 changes: 426 additions & 0 deletions docs/images/grid2_tensor.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion omf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)
from .lineset import LineSet
from .pointset import PointSet
from .surface import Surface, TensorGridSurface
from .surface import Surface, TensorGridSurface, RegularGridSurface
from .texture import ProjectedTexture, UVMappedTexture

from .fileio import load, save, __version__
Expand Down
2 changes: 1 addition & 1 deletion omf/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def deserialize(cls, value, trusted=False, strict=False, assert_valid=False, **k
array_dtype = DATA_TYPE_LOOKUP_TO_NUMPY[value["data_type"]]
if value["data_type"] == "BooleanArray":
int_arr = np.frombuffer(array_binary, dtype="uint8")
bit_arr = np.unpackbits(int_arr)[: np.product(value["shape"])]
bit_arr = np.unpackbits(int_arr)[: np.prod(value["shape"])]
arr = bit_arr.astype(array_dtype)
else:
arr = np.frombuffer(array_binary, dtype=array_dtype)
Expand Down
70 changes: 67 additions & 3 deletions omf/surface.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""surface.py: Surface element definitions"""

import numpy as np
import properties

EPSILON = np.finfo(float).eps

from .base import ProjectElement
from .attribute import ArrayInstanceProperty
from .texture import HasTexturesMixin
Expand Down Expand Up @@ -78,12 +81,12 @@ class TensorGridSurface(BaseSurfaceElement): # pylint: disable=R0901

tensor_u = properties.List(
"Grid cell widths, u-direction",
properties.Float("", min=0.0),
properties.Float("", min=EPSILON),
coerce=True,
)
tensor_v = properties.List(
"Grid cell widths, v-direction",
properties.Float("", min=0.0),
properties.Float("", min=EPSILON),
coerce=True,
)
axis_u = properties.Vector3(
Expand Down Expand Up @@ -116,7 +119,7 @@ def num_cells(self):
@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:
if not np.abs(self.axis_u.dot(self.axis_v)) < EPSILON:
raise properties.ValidationError("axis_u and axis_v must be orthogonal")
if self.offset_w is properties.undefined or self.offset_w is None:
return True
Expand All @@ -126,3 +129,64 @@ def _validate_mesh(self):
"{nnode}".format(zlen=len(self.offset_w.array), nnode=self.num_nodes)
)
return True


class RegularGridSurface(BaseSurfaceElement): # pylint: disable=R0901
"""Surface element with regular spacing in each dimension"""

schema = "org.omf.v2.element.surfaceregulargrid"

cell_count = properties.List(
"Number of cells along u, and v axes",
properties.Integer("", min=1),
min_length=2,
max_length=2,
)
cell_size = properties.List(
"Size of cells in the u and v dimensions",
properties.Float("", min=EPSILON),
min_length=2,
max_length=2,
)
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 = ArrayInstanceProperty(
"Node offset",
shape=("*",),
dtype=float,
required=False,
)

@property
def num_nodes(self):
"""Number of nodes (vertices)"""
cell_count = self.cell_count
return (cell_count[0] + 1) * (cell_count[1] + 1)

@property
def num_cells(self):
"""Number of cells (faces)"""
cell_count = self.cell_count
return cell_count[0] * cell_count[1]

@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:
raise properties.ValidationError("axis_u and axis_v must be orthogonal")
if self.offset_w is properties.undefined or self.offset_w is None:
return True
elif len(self.offset_w.array) != self.num_nodes:
raise properties.ValidationError(
"Length of offset_w, {zlen}, must equal number of nodes, "
"{nnode}".format(zlen=len(self.offset_w.array), nnode=self.num_nodes)
)
return True
25 changes: 23 additions & 2 deletions tests/test_surface.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tests for Surface validation"""

import numpy as np
import pytest

Expand All @@ -21,8 +22,8 @@ def test_surface():
elem.validate()


def test_surfacegrid():
"""Test surface grid geometry validation"""
def test_tensor_surface():
"""Test tensor surface grid geometry validation"""
elem = omf.surface.TensorGridSurface()
elem.tensor_u = [1.0, 1.0]
elem.tensor_v = [2.0, 2.0, 2.0]
Expand All @@ -38,3 +39,23 @@ def test_surfacegrid():
elem.offset_w = np.random.rand(6)
with pytest.raises(ValueError):
elem.validate()


def test_regular_surface():
"""Test regular surface geometry validation"""
elem = omf.surface.RegularGridSurface()
elem.origin = [0.0, 0.0, 0.0]
elem.cell_size = [1.0, 1.0]
elem.cell_count = [2, 2]
assert elem.validate()
assert elem.location_length("vertices") == 9
assert elem.location_length("faces") == 4
with pytest.raises(ValueError):
elem.cell_size = [0.0, 1.0]
with pytest.raises(ValueError):
elem.origin = [0.0, 0.0]
elem.offset_w = np.random.rand(9)
elem.validate()
elem.offset_w = np.random.rand(4)
with pytest.raises(ValueError):
elem.validate()