Coverage for src/beamme/mesh_creation_functions/nurbs_generic.py: 96%
193 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-30 18:48 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-30 18:48 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2018-2025 BeamMe Authors
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21# THE SOFTWARE.
22"""Generic function used to create NURBS meshes."""
24from typing import Type as _Type
26from beamme.core.conf import mpy as _mpy
27from beamme.core.geometry_set import GeometryName as _GeometryName
28from beamme.core.geometry_set import GeometrySetNodes as _GeometrySetNodes
29from beamme.core.mesh import Mesh as _Mesh
30from beamme.core.node import ControlPoint as _ControlPoint
31from beamme.core.nurbs_patch import NURBSSurface as _NURBSSurface
32from beamme.core.nurbs_patch import NURBSVolume as _NURBSVolume
35def add_splinepy_nurbs_to_mesh(
36 mesh: _Mesh,
37 splinepy_obj,
38 *,
39 material=None,
40 data: dict | None = None,
41) -> _GeometryName:
42 """Add a splinepy NURBS to the mesh.
44 Args:
45 mesh: Mesh that the created NURBS geometry will be added to.
46 splinepy_obj (splinepy object): NURBS geometry created using splinepy.
47 material (Material): Material for this geometry.
48 data: General element data, e.g., material, formulation, ...
50 Returns:
51 GeometryName:
52 Set with the control points that form the topology of the mesh.
54 For a surface, the following information is stored:
55 Vertices: 'vertex_u_min_v_min', 'vertex_u_max_v_min', 'vertex_u_min_v_max', 'vertex_u_max_v_max'
56 Edges: 'line_v_min', 'line_u_max', 'line_v_max', 'line_u_min'
57 Surface: 'surf'
59 For a volume, the following information is stored:
60 Vertices: 'vertex_u_min_v_min_w_min', 'vertex_u_max_v_min_w_min', 'vertex_u_min_v_max_w_min', 'vertex_u_max_v_max_w_min',
61 'vertex_u_min_v_min_w_max', 'vertex_u_max_v_min_w_max', 'vertex_u_min_v_max_w_max', 'vertex_u_max_v_max_w_max'
62 Edges: 'line_v_min_w_min', 'line_u_max_w_min', 'line_v_max_w_min', 'line_u_min_w_min',
63 'line_u_min_v_min', 'line_u_max_v_min', 'line_u_min_v_max', 'line_u_max_v_max'
64 'line_v_min_w_max', 'line_u_max_w_max', 'line_v_max_w_max', 'line_u_min_w_max'
65 Surfaces: 'surf_w_min', 'surf_w_max', 'surf_v_min', 'surf_v_max', 'surf_v_max', 'surf_u_min'
66 Volume: 'vol'
67 """
69 # Make sure the material is in the mesh
70 mesh.add_material(material)
72 # Fill control points
73 control_points = [
74 _ControlPoint(coord, weight[0])
75 for coord, weight in zip(splinepy_obj.control_points, splinepy_obj.weights)
76 ]
78 # Fill element
79 manifold_dim = len(splinepy_obj.knot_vectors)
80 nurbs_object: _Type[_NURBSSurface] | _Type[_NURBSVolume]
81 if manifold_dim == 2:
82 nurbs_object = _NURBSSurface
83 elif manifold_dim == 3:
84 nurbs_object = _NURBSVolume
85 else:
86 raise NotImplementedError(
87 "Error, not implemented for a NURBS {}!".format(type(splinepy_obj))
88 )
90 element = nurbs_object(
91 splinepy_obj.knot_vectors,
92 splinepy_obj.degrees,
93 nodes=control_points,
94 material=material,
95 data=data,
96 )
98 # Add element and control points to the mesh
99 mesh.elements.append(element)
100 mesh.nodes.extend(control_points)
102 # Create geometry sets that will be returned
103 return_set = create_geometry_sets(element)
105 return return_set
108def add_geomdl_nurbs_to_mesh(
109 mesh: _Mesh,
110 geomdl_obj,
111 *,
112 material=None,
113 data: dict | None = None,
114) -> _GeometryName:
115 """Add a geomdl NURBS to the mesh.
117 Args:
118 mesh: Mesh that the created NURBS geometry will be added to.
119 geomdl_obj (geomdl object): NURBS geometry created using geomdl.
120 material (Material): Material for this geometry.
121 data: General element data, e.g., material, formulation, ...
123 Returns:
124 GeometryName:
125 Set with the control points that form the topology of the mesh.
127 For a surface, the following information is stored:
128 Vertices: 'vertex_u_min_v_min', 'vertex_u_max_v_min', 'vertex_u_min_v_max', 'vertex_u_max_v_max'
129 Edges: 'line_v_min', 'line_u_max', 'line_v_max', 'line_u_min'
130 Surface: 'surf'
132 For a volume, the following information is stored:
133 Vertices: 'vertex_u_min_v_min_w_min', 'vertex_u_max_v_min_w_min', 'vertex_u_min_v_max_w_min', 'vertex_u_max_v_max_w_min',
134 'vertex_u_min_v_min_w_max', 'vertex_u_max_v_min_w_max', 'vertex_u_min_v_max_w_max', 'vertex_u_max_v_max_w_max'
135 Edges: 'line_v_min_w_min', 'line_u_max_w_min', 'line_v_max_w_min', 'line_u_min_w_min',
136 'line_u_min_v_min', 'line_u_max_v_min', 'line_u_min_v_max', 'line_u_max_v_max'
137 'line_v_min_w_max', 'line_u_max_w_max', 'line_v_max_w_max', 'line_u_min_w_max'
138 Surfaces: 'surf_w_min', 'surf_w_max', 'surf_v_min', 'surf_v_max', 'surf_v_max', 'surf_u_min'
139 Volume: 'vol'
140 """
142 # Make sure the material is in the mesh
143 mesh.add_material(material)
145 # Fill control points
146 control_points = []
147 nurbs_dimension = len(geomdl_obj.knotvector)
148 if nurbs_dimension == 2:
149 control_points = create_control_points_surface(geomdl_obj)
150 elif nurbs_dimension == 3:
151 control_points = create_control_points_volume(geomdl_obj)
152 else:
153 raise NotImplementedError(
154 "Error, not implemented for NURBS with dimension {}!".format(
155 nurbs_dimension
156 )
157 )
159 # Fill element
160 manifold_dim = len(geomdl_obj.knotvector)
161 nurbs_object: _Type[_NURBSSurface] | _Type[_NURBSVolume]
162 if manifold_dim == 2:
163 nurbs_object = _NURBSSurface
164 elif manifold_dim == 3:
165 nurbs_object = _NURBSVolume
166 else:
167 raise NotImplementedError(
168 "Error, not implemented for a NURBS {}!".format(type(geomdl_obj))
169 )
171 element = nurbs_object(
172 geomdl_obj.knotvector,
173 geomdl_obj.degree,
174 nodes=control_points,
175 material=material,
176 data=data,
177 )
179 # Add element and control points to the mesh
180 mesh.elements.append(element)
181 mesh.nodes.extend(control_points)
183 # Create geometry sets that will be returned
184 return_set = create_geometry_sets(element)
186 return return_set
189def create_control_points_surface(geomdl_obj):
190 """Creates a list with the ControlPoint objects of a surface created with
191 geomdl."""
192 control_points = []
193 for dir_v in range(geomdl_obj.ctrlpts_size_v):
194 for dir_u in range(geomdl_obj.ctrlpts_size_u):
195 weight = geomdl_obj.ctrlpts2d[dir_u][dir_v][3]
197 # As the control points are scaled with their weight, divide them to get
198 # their coordinates
199 coord = [
200 geomdl_obj.ctrlpts2d[dir_u][dir_v][0] / weight,
201 geomdl_obj.ctrlpts2d[dir_u][dir_v][1] / weight,
202 geomdl_obj.ctrlpts2d[dir_u][dir_v][2] / weight,
203 ]
205 control_points.append(_ControlPoint(coord, weight))
207 return control_points
210def create_control_points_volume(geomdl_obj):
211 """Creates a list with the ControlPoint objects of a volume created with
212 geomdl."""
213 control_points = []
214 for dir_w in range(geomdl_obj.ctrlpts_size_w):
215 for dir_v in range(geomdl_obj.ctrlpts_size_v):
216 for dir_u in range(geomdl_obj.ctrlpts_size_u):
217 # Obtain the id of the control point
218 cp_id = (
219 dir_v
220 + geomdl_obj.ctrlpts_size_v * dir_u
221 + geomdl_obj.ctrlpts_size_u * geomdl_obj.ctrlpts_size_v * dir_w
222 )
224 weight = geomdl_obj.ctrlptsw[cp_id][3]
226 # As the control points are scaled with their weight, divide them to get
227 # their coordinates
228 coord = [
229 geomdl_obj.ctrlptsw[cp_id][0] / weight,
230 geomdl_obj.ctrlptsw[cp_id][1] / weight,
231 geomdl_obj.ctrlptsw[cp_id][2] / weight,
232 ]
234 control_points.append(_ControlPoint(coord, weight))
236 return control_points
239def create_geometry_sets(element: _NURBSSurface | _NURBSVolume) -> _GeometryName:
240 """Function that returns a GeometryName object.
242 For more information of the return item, look into
243 `add_splinepy_nurbs_to_mesh` and `add_geomdl_nurbs_to_mesh`.
244 """
246 def get_patch_vertices(return_set, num_cps_uvw, nurbs_dimension, element):
247 """Get the control points positioned over the vertices of a patch."""
249 if nurbs_dimension == 2:
250 # Vertex 1 is positioned on u = 0, v = 0
251 return_set["vertex_u_min_v_min"] = _GeometrySetNodes(
252 _mpy.geo.point, nodes=element.nodes[0]
253 )
255 # Vertex 2 is positioned on u = 1, v = 0
256 return_set["vertex_u_max_v_min"] = _GeometrySetNodes(
257 _mpy.geo.point, nodes=element.nodes[num_cps_uvw[0] - 1]
258 )
260 # Vertex 3 is positioned on u = 0, v = 1
261 return_set["vertex_u_min_v_max"] = _GeometrySetNodes(
262 _mpy.geo.point,
263 nodes=element.nodes[num_cps_uvw[0] * (num_cps_uvw[1] - 1)],
264 )
266 # Vertex 4 is positioned on u = 1, v = 1
267 return_set["vertex_u_max_v_max"] = _GeometrySetNodes(
268 _mpy.geo.point, nodes=element.nodes[num_cps_uvw[0] * num_cps_uvw[1] - 1]
269 )
271 elif nurbs_dimension == 3:
272 # Vertex 1 is positioned on u = 0, v = 0, w =
273 return_set["vertex_u_min_v_min_w_min"] = _GeometrySetNodes(
274 _mpy.geo.point, nodes=element.nodes[0]
275 )
277 # Vertex 2 is positioned on u = 1, v = 0, w = 0
278 return_set["vertex_u_max_v_min_w_min"] = _GeometrySetNodes(
279 _mpy.geo.point, nodes=element.nodes[num_cps_uvw[0] - 1]
280 )
282 # Vertex 3 is positioned on u = 0, v = 1, w = 0
283 return_set["vertex_u_min_v_max_w_min"] = _GeometrySetNodes(
284 _mpy.geo.point,
285 nodes=element.nodes[num_cps_uvw[0] * (num_cps_uvw[1] - 1)],
286 )
288 # Vertex 4 is positioned on u = 1, v = 1, w = 0
289 return_set["vertex_u_max_v_max_w_min"] = _GeometrySetNodes(
290 _mpy.geo.point, nodes=element.nodes[num_cps_uvw[0] * num_cps_uvw[1] - 1]
291 )
293 # Vertex 5 is positioned on u = 0, v = 0, w = 1
294 return_set["vertex_u_min_v_min_w_max"] = _GeometrySetNodes(
295 _mpy.geo.point,
296 nodes=element.nodes[
297 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
298 ],
299 )
301 # Vertex 6 is positioned on u = 1, v = 0, w = 1
302 return_set["vertex_u_max_v_min_w_max"] = _GeometrySetNodes(
303 _mpy.geo.point,
304 nodes=element.nodes[
305 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
306 + (num_cps_uvw[0] - 1)
307 ],
308 )
310 # Vertex 7 is positioned on u = 0, v = 1, w = 1
311 return_set["vertex_u_min_v_max_w_max"] = _GeometrySetNodes(
312 _mpy.geo.point,
313 nodes=element.nodes[
314 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
315 + num_cps_uvw[0] * (num_cps_uvw[1] - 1)
316 ],
317 )
319 # Vertex 8 is positioned on u = 1, v = 1, w = 1
320 return_set["vertex_u_max_v_max_w_max"] = _GeometrySetNodes(
321 _mpy.geo.point,
322 nodes=element.nodes[
323 num_cps_uvw[0] * num_cps_uvw[1] * num_cps_uvw[2] - 1
324 ],
325 )
327 else:
328 raise NotImplementedError(
329 "Error, not implemented for NURBS with dimension {}!".format(
330 nurbs_dimension
331 )
332 )
334 def get_patch_lines(return_set, num_cps_uvw, nurbs_dimension, element):
335 """Get the control points positioned over the lines of a patch."""
337 if nurbs_dimension == 2:
338 name_dir = ["v", "u"]
339 name_other_dir = ["min", "min_next", "max_next", "max"]
341 for i_dir, i_other_dir in ((0, 1), (1, 0)):
342 n_cp_dir = num_cps_uvw[i_dir]
343 n_cp_other_dir = num_cps_uvw[i_other_dir]
344 factor_dir = 1 if i_dir == 0 else n_cp_other_dir
345 factor_other_dir = n_cp_dir if i_dir == 0 else 1
347 for index, i_along_other_dir in enumerate(
348 (
349 0,
350 1,
351 n_cp_other_dir - 2,
352 n_cp_other_dir - 1,
353 )
354 ):
355 cp_indices = []
356 for i_along_dir in range(n_cp_dir):
357 cp_indices.append(
358 i_along_other_dir * factor_other_dir
359 + i_along_dir * factor_dir
360 )
361 set_name = f"line_{name_dir[i_dir]}_{name_other_dir[index]}"
362 return_set[set_name] = _GeometrySetNodes(
363 _mpy.geo.line,
364 nodes=[element.nodes[i_node] for i_node in cp_indices],
365 )
367 elif nurbs_dimension == 3:
368 # Define the rest of the lines to define a volume
369 control_points_line_1 = []
370 control_points_line_2 = []
371 control_points_line_3 = []
372 control_points_line_4 = []
373 control_points_line_5 = []
374 control_points_line_6 = []
375 control_points_line_7 = []
376 control_points_line_8 = []
377 control_points_line_9 = []
378 control_points_line_10 = []
379 control_points_line_11 = []
380 control_points_line_12 = []
382 # Fill line 1, 3, 9 and 11 with their control points
383 for i in range(num_cps_uvw[0]):
384 # Line 1 has the control points on u = [0,1], v = 0, w = 0
385 cpgid_l1 = num_cps_uvw[0] * 0 + i
386 control_points_line_1.append(element.nodes[cpgid_l1])
388 # Line 3 has the control points on u = [0,1], v = 1, w = 0
389 cpgid_l3 = num_cps_uvw[0] * (num_cps_uvw[1] - 1) + i
390 control_points_line_3.append(element.nodes[cpgid_l3])
392 # Line 9 has the control points on u = [0,1], v = 0, w = 1
393 cpgid_l9 = num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1) + i
394 control_points_line_9.append(element.nodes[cpgid_l9])
396 # Line 11 has the control points on u = [0,1], v = 1, w = 1
397 cpgid_l11 = (
398 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
399 + num_cps_uvw[0] * (num_cps_uvw[1] - 1)
400 + i
401 )
402 control_points_line_11.append(element.nodes[cpgid_l11])
404 # Fill line 2, 4, 10 and 12 with their control points
405 for j in range(num_cps_uvw[1]):
406 # Line 2 has the control points on u = 1, v = [0,1] , w = 0
407 cpgid_l2 = num_cps_uvw[0] * j + (num_cps_uvw[0] - 1)
408 control_points_line_2.append(element.nodes[cpgid_l2])
410 # Line 4 has the control points on u = 0, v = [0,1] , w = 0
411 cpgid_l4 = num_cps_uvw[0] * j + 0
412 control_points_line_4.append(element.nodes[cpgid_l4])
414 # Line 10 has the control points on u = 1, v = [0,1] , w = 1
415 cpgid_l10 = (
416 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
417 + num_cps_uvw[0] * j
418 + (num_cps_uvw[0] - 1)
419 )
420 control_points_line_10.append(element.nodes[cpgid_l10])
422 # Line 12 has the control points on u = 0, v = [0,1] , w = 1
423 cpgid_l12 = (
424 num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)
425 + num_cps_uvw[0] * j
426 )
427 control_points_line_12.append(element.nodes[cpgid_l12])
429 # Fill line 5, 6, 7 and 8 with their control points
430 for k in range(num_cps_uvw[2]):
431 # Line 5 has the control points on u = 0, v = 0 , w = [0,1]
432 cpgid_l5 = num_cps_uvw[0] * num_cps_uvw[1] * k
433 control_points_line_5.append(element.nodes[cpgid_l5])
435 # Line 6 has the control points on u = 1, v = 0 , w = [0,1]
436 cpgid_l6 = num_cps_uvw[0] * num_cps_uvw[1] * k + num_cps_uvw[0] - 1
437 control_points_line_6.append(element.nodes[cpgid_l6])
439 # Line 7 has the control points on u = 0, v = 1 , w = [0,1]
440 cpgid_l7 = num_cps_uvw[0] * num_cps_uvw[1] * k + num_cps_uvw[0] * (
441 num_cps_uvw[1] - 1
442 )
443 control_points_line_7.append(element.nodes[cpgid_l7])
445 # Line 8 has the control points on u = 1, v = 1 , w = [0,1]
446 cpgid_l8 = (
447 num_cps_uvw[0] * num_cps_uvw[1] * k
448 + num_cps_uvw[0] * num_cps_uvw[1]
449 - 1
450 )
451 control_points_line_8.append(element.nodes[cpgid_l8])
453 # Create geometric sets for lines
454 return_set["line_v_min_w_min"] = _GeometrySetNodes(
455 _mpy.geo.line, nodes=control_points_line_1
456 )
457 return_set["line_u_max_w_min"] = _GeometrySetNodes(
458 _mpy.geo.line, nodes=control_points_line_2
459 )
460 return_set["line_v_max_w_min"] = _GeometrySetNodes(
461 _mpy.geo.line, nodes=control_points_line_3
462 )
463 return_set["line_u_min_w_min"] = _GeometrySetNodes(
464 _mpy.geo.line, nodes=control_points_line_4
465 )
466 return_set["line_u_min_v_min"] = _GeometrySetNodes(
467 _mpy.geo.line, nodes=control_points_line_5
468 )
469 return_set["line_u_max_v_min"] = _GeometrySetNodes(
470 _mpy.geo.line, nodes=control_points_line_6
471 )
472 return_set["line_u_min_v_max"] = _GeometrySetNodes(
473 _mpy.geo.line, nodes=control_points_line_7
474 )
475 return_set["line_u_max_v_max"] = _GeometrySetNodes(
476 _mpy.geo.line, nodes=control_points_line_8
477 )
478 return_set["line_v_min_w_max"] = _GeometrySetNodes(
479 _mpy.geo.line, nodes=control_points_line_9
480 )
481 return_set["line_u_max_w_max"] = _GeometrySetNodes(
482 _mpy.geo.line, nodes=control_points_line_10
483 )
484 return_set["line_v_max_w_max"] = _GeometrySetNodes(
485 _mpy.geo.line, nodes=control_points_line_11
486 )
487 return_set["line_u_min_w_max"] = _GeometrySetNodes(
488 _mpy.geo.line, nodes=control_points_line_12
489 )
491 else:
492 raise NotImplementedError(
493 "Error, not implemented for NURBS with dimension {}!".format(
494 nurbs_dimension
495 )
496 )
498 def get_patch_surfaces(return_set, num_cps_uvw, nurbs_dimension, element):
499 """Get the control points positioned over the surfaces of a patch."""
501 control_points_surface_1 = []
503 if nurbs_dimension == 2:
504 # As there is only one surface, it collects all the control points
505 control_points_surface_1.extend(
506 element.nodes[: (num_cps_uvw[0] * num_cps_uvw[1])]
507 )
509 # Create geometric sets for surfaces
510 return_set["surf"] = _GeometrySetNodes(
511 _mpy.geo.surface, nodes=control_points_surface_1
512 )
514 elif nurbs_dimension == 3:
515 control_points_surface_2 = []
516 control_points_surface_3 = []
517 control_points_surface_4 = []
518 control_points_surface_5 = []
519 control_points_surface_6 = []
521 # Surface defined on w = 0
522 control_points_surface_1.extend(
523 element.nodes[: (num_cps_uvw[0] * num_cps_uvw[1])]
524 )
526 # Surface defined on w = 1
527 control_points_surface_2.extend(
528 element.nodes[
529 (num_cps_uvw[0] * num_cps_uvw[1] * (num_cps_uvw[2] - 1)) : (
530 num_cps_uvw[0] * num_cps_uvw[1] * num_cps_uvw[2]
531 )
532 ]
533 )
535 for layers_w_dir in range(num_cps_uvw[2]):
536 # Calculate the number of control points on the w-plane
537 num_cps_plane_w = num_cps_uvw[0] * num_cps_uvw[1]
539 for layers_u_dir in range(num_cps_uvw[0]):
540 # Surface defined on v = 0
541 cpgid_l1 = num_cps_uvw[0] * 0 + layers_u_dir
542 control_points_surface_3.append(
543 element.nodes[cpgid_l1 + num_cps_plane_w * layers_w_dir]
544 )
546 # Surface defined on v = 1
547 cpgid_l3 = num_cps_uvw[0] * (num_cps_uvw[1] - 1) + layers_u_dir
548 control_points_surface_5.append(
549 element.nodes[cpgid_l3 + num_cps_plane_w * layers_w_dir]
550 )
552 for layers_v_dir in range(num_cps_uvw[1]):
553 # Surface defined on u = 1
554 cpgid_l2 = num_cps_uvw[0] * layers_v_dir + (num_cps_uvw[0] - 1)
555 control_points_surface_4.append(
556 element.nodes[cpgid_l2 + num_cps_plane_w * layers_w_dir]
557 )
559 # Surface defined on u = 0
560 cpgid_l4 = num_cps_uvw[0] * layers_v_dir + 0
561 control_points_surface_6.append(
562 element.nodes[cpgid_l4 + num_cps_plane_w * layers_w_dir]
563 )
565 # Create geometric sets for surfaces
566 return_set["surf_w_min"] = _GeometrySetNodes(
567 _mpy.geo.surface, nodes=control_points_surface_1
568 )
569 return_set["surf_w_max"] = _GeometrySetNodes(
570 _mpy.geo.surface, nodes=control_points_surface_2
571 )
572 return_set["surf_v_min"] = _GeometrySetNodes(
573 _mpy.geo.surface, nodes=control_points_surface_3
574 )
575 return_set["surf_u_max"] = _GeometrySetNodes(
576 _mpy.geo.surface, nodes=control_points_surface_4
577 )
578 return_set["surf_v_max"] = _GeometrySetNodes(
579 _mpy.geo.surface, nodes=control_points_surface_5
580 )
581 return_set["surf_u_min"] = _GeometrySetNodes(
582 _mpy.geo.surface, nodes=control_points_surface_6
583 )
585 else:
586 raise NotImplementedError(
587 "Error, not implemented for NURBS with dimension {}!".format(
588 nurbs_dimension
589 )
590 )
592 def get_patch_volume(return_set, num_cps_uvw, nurbs_dimension, element):
593 """Get the control points positioned in the volume of a patch."""
595 control_points_volume_1 = []
597 if nurbs_dimension == 2:
598 # As this is a surface, it's not necessary to get a volume GeometrySet
599 pass
601 elif nurbs_dimension == 3:
602 # As there is only one volume, it collects all the control points
603 control_points_volume_1.extend(
604 element.nodes[: (num_cps_uvw[0] * num_cps_uvw[1] * num_cps_uvw[2])]
605 )
607 # Create geometric sets for surfaces
608 return_set["vol"] = _GeometrySetNodes(
609 _mpy.geo.volume, nodes=control_points_volume_1
610 )
612 else:
613 raise NotImplementedError(
614 "Error, not implemented for NURBS with dimension {}".format(
615 nurbs_dimension
616 )
617 )
619 # Create return set
620 return_set = _GeometryName()
622 # Get the number of control points on each parametric direction that define the patch
623 num_cps_uvw = element.get_number_of_control_points_per_dir()
625 # Get the NURBS dimension
626 nurbs_dimension = len(element.knot_vectors)
628 # Obtain the vertices of the patch
629 get_patch_vertices(return_set, num_cps_uvw, nurbs_dimension, element)
631 # Obtain the lines of the patch
632 get_patch_lines(return_set, num_cps_uvw, nurbs_dimension, element)
634 # Obtain the surfaces of the patch
635 get_patch_surfaces(return_set, num_cps_uvw, nurbs_dimension, element)
637 # Obtain the volume of the patch
638 get_patch_volume(return_set, num_cps_uvw, nurbs_dimension, element)
640 return return_set