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):
import viktor as vkt
class Parametrization(vkt.Parametrization):
selected_geometry = vkt.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):
import viktor as vkt
class Parametrization(vkt.Parametrization):
selected_geometries = vkt.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:
import viktor as vkt
class Parametrization(vkt.Parametrization):
load_cases = vkt.DynamicArray("Load Cases")
load_cases.geometry = vkt.GeometrySelectField("Geometry")
load_cases.load = vkt.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
import viktor as vkt
class Parametrization(vkt.Parametrization):
ifc = vkt.FileField("Please provide an IFC file")
selected_geometry = vkt.GeometrySelectField("Select a geometry")
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.IFCAndDataView("IFC", 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(vkt.DataItem(k, v))
data_items.append(vkt.DataItem(key, '', subgroup=vkt.DataGroup(*sub_data_items)))
data = vkt.DataGroup(*data_items)
else:
data = vkt.DataGroup(vkt.DataItem('No geometries selected', ''))
return vkt.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.
import viktor as vkt
class Parametrization(vkt.Parametrization):
selected_geometry = vkt.GeometrySelectField("Select a geometry")
selected_geometries = vkt.GeometryMultiSelectField("Select geometries")
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.GeometryAndDataView('Geometry', x_axis_to_right=True)
def get_geometry_and_data_view(self, params, **kwargs):
cubes = {
'cube1': vkt.SquareBeam(1, 1, 5, identifier="cube1"),
'cube2': vkt.SquareBeam(1, 4, 1, identifier="cube2"),
'cube3': vkt.SquareBeam(3, 1, 1, identifier="cube3")
}
# Calculate data
if selected_geometry := params.selected_geometry:
volume = cubes[selected_geometry].inner_volume
data_1 = vkt.DataItem('Volume of GeometrySelectField', volume, suffix="m3")
else:
data_1 = vkt.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 = vkt.DataItem('Volume of GeometryMultiSelectField', volume, suffix="m3")
else:
data_2 = vkt.DataItem('No geometries selected in GeometryMultiSelectField', '')
return vkt.GeometryAndDataResult(geometry=cubes.values(), data=vkt.DataGroup(data_1, data_2))