Geometry selection
The geometry selection fields, enable the user to select geometries in an
IFCView
or a
GeometryView
.
Select a geometry
The GeometrySelectField
enables the user to select a single
(sub-)geometry in a geometric view, which is returned in the params
as an identifier (string):
from viktor.parametrization import ViktorParametrization, GeometrySelectField
class Parametrization(ViktorParametrization):
selected_geometry = GeometrySelectField("Select a geometry")
Select multiple geometries
The GeometryMultiSelectField
enables the user to select
multiple (sub-)geometries in a geometric view, which is returned in the params
as a list of identifiers (list of
strings):
from viktor.parametrization import ViktorParametrization, GeometryMultiSelectField
class Parametrization(ViktorParametrization):
selected_geometries = GeometryMultiSelectField("Select geometries")
Select a geometry in a DynamicArray
The GeometrySelectField
and
GeometryMultiSelectField
can be used in combination with a
DynamicArray
to allow an arbitrary number of geometries or group of
geometries to be selected and assign or group these with additional parameters:
from viktor.parametrization import ViktorParametrization, GeometrySelectField, DynamicArray, NumberField
class Parametrization(ViktorParametrization):
load_cases = DynamicArray("Load Cases")
load_cases.geometry = GeometrySelectField("Geometry")
load_cases.load = NumberField("Load", suffix="N")
Example
To support geometry selection, the following parts need to be implemented in the app:
- IFCView
- GeometryView
- Create an IFCView in the controller
- Create a GeometrySelectField or GeometryMultiSelectField in the parametrization
- Use the
identifier
retrieved from the params in subsequent calculations
An IFC-file contains unique identifiers per geometry feature.
import ifcopenshell
import ifcopenshell.util.element
from pathlib import Path
from tempfile import NamedTemporaryFile
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization, GeometrySelectField, FileField
from viktor.views import IFCAndDataView, IFCAndDataResult, DataGroup, DataItem
class Parametrization(ViktorParametrization):
ifc = FileField("Please provide an IFC file")
selected_geometry = GeometrySelectField("Select a geometry")
class MyController(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization
@IFCAndDataView("IFC", duration_guess=1, x_axis_to_right=True)
def get_ifc_and_data_view(self, params, **kwargs):
ifc_file = params.ifc.file
if params.selected_geometry: # If user has made a selection, add its properties to `data`
# parse your ifc file (e.g. with ifcopenshell as below)
with NamedTemporaryFile(suffix=".ifc", delete=False, mode="w") as temp_f:
temp_f.write(ifc_file.getvalue())
model = ifcopenshell.open(Path(temp_f.name))
elem = model.by_id(int(params.selected_geometry))
# See https://wiki.osarch.org/index.php?title=IFC_attributes_and_properties
# for a list of available IFC attributes and properties
data_items = []
for key, val in ifcopenshell.util.element.get_psets(elem).items():
sub_data_items = []
for k,v in val.items():
sub_data_items.append(DataItem(k, v))
data_items.append(DataItem(key, '', subgroup=DataGroup(*sub_data_items)))
data = DataGroup(*data_items)
else:
data = DataGroup(DataItem('No geometries selected', ''))
return IFCAndDataResult(ifc=ifc_file, data=data)
- Create a GeometryView in the controller
- Create a GeometrySelectField or GeometryMultiSelectField in the parametrization
- Use the
identifier
retrieved from the params in subsequent calculations
Identifiers can be assigned to the VIKTOR geometry objects, to make them selectable in the view.
- If several objects have an identifier assigned, then only these objects will be selectable in the View.
- If none of the objects in the GeometryResult have an identifier assigned, default identifiers are assigned to all of them (enabling them for selection).
- If there are multiple objects with the same name, a number will automatically be appended to enforce uniqueness.
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization, GeometrySelectField
from viktor.views import GeometryAndDataView, GeometryAndDataResult, DataGroup, DataItem
...
class Parametrization(ViktorParametrization):
selected_geometry = GeometrySelectField("Select a geometry")
selected_geometries = GeometryMultiSelectField("Select geometries")
class MyController(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization
...
@GeometryAndDataView('Geometry', duration_guess=1, x_axis_to_right=True)
def get_geometry_and_data_view(self, params, **kwargs):
...
cubes = {
'cube1': SquareBeam(1, 1, 5, identifier="cube1"),
'cube2': SquareBeam(1, 4, 1, identifier="cube2"),
'cube3': SquareBeam(3, 1, 1, identifier="cube3")
}
# Calculate data
if selected_geometry := params.selected_geometry:
volume = cubes[selected_geometry].inner_volume
data_1 = DataItem('Volume of GeometrySelectField', volume, suffix="m3")
else:
data_1 = DataItem('No geometry selected in GeometrySelectField', '')
if selected_geometries := params.selected_geometries:
volume = sum(cubes[selected_geometry].inner_volume for selected_geometry in selected_geometries)
data_2 = DataItem('Volume of GeometryMultiSelectField', volume, suffix="m3")
else:
data_2 = DataItem('No geometries selected in GeometryMultiSelectField', '')
return GeometryAndDataResult(geometry=cubes.values(), data=DataGroup(data_1, data_2))