Coverage for src/meshpy/mesh_creation_functions/nurbs_geometries.py: 99%
205 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 12:53 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 12:53 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2018-2025 MeshPy 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"""This file has functions to create NURBS geometries using Geomdl."""
24import numpy as _np
25from geomdl import NURBS as _NURBS
26from geomdl import compatibility as _compat
27from geomdl import operations as _operations
30def create_nurbs_hollow_cylinder_segment_2d(
31 radius_in, radius_out, angle, *, n_ele_u=1, n_ele_v=1
32):
33 """Creates a patch of a 2 dimensional segment of a hollow cylinder.
35 Args
36 ----
37 radius_in: double
38 inner cylinder radius
39 radius_out: double
40 outer cylinder radius
41 angle: double
42 angle of the hollow cylinder section (radians)
43 n_ele_u: int
44 number of elements in the parametric u-direction
45 n_ele_v: int
46 number of elements in the parametric v-direction
49 Return
50 ----
51 surf: geomdl object
52 geomdl object that contains the surface information
53 """
55 # Check the validity of the input values:
56 if radius_in >= radius_out:
57 raise ValueError(
58 "The external radius should be larger than the internal radius of a hollow cylinder."
59 )
60 if (angle > _np.pi) or (angle < 0):
61 raise ValueError(
62 "The following algorithm for creating a hollow cylinder section is only valid for 0 < angle <= pi."
63 )
65 # Create a NURBS surface instance
66 surf = _NURBS.Surface()
68 # Set degrees
69 surf.degree_u = 2
70 surf.degree_v = 2
72 # Control points and set them to the surface
73 p_size_u = 3
74 p_size_v = 3
76 # To calculate the internal control point cp_2 we have to calculate
77 # the intersection of the tangents of the points cp_1 and cp_3.
78 # As point cp_1 is always defined over the x axis, its tangent is simply x = radius
79 # The equation of the tangent to the circle at the cp_3 point is:
80 # y - cp_3y = -(cp_3x/cp_3y)*(x - cp_3x).
82 # Obtaining the control points that define the external arc of the hollow cylinder
83 cp_ext1 = [radius_out, 0.0, 0.0]
84 cp_ext3 = [radius_out * _np.cos(angle), radius_out * _np.sin(angle), 0.0]
85 cp_ext2 = [
86 radius_out,
87 -(cp_ext3[0] / cp_ext3[1]) * (radius_out - cp_ext3[0]) + cp_ext3[1],
88 0.0,
89 ]
91 # Obtaining the control points that define the internal arc of the hollow cylinder
92 cp_int1 = [radius_in, 0.0, 0.0]
93 cp_int3 = [radius_in * _np.cos(angle), radius_in * _np.sin(angle), 0.0]
94 cp_int2 = [
95 radius_in,
96 -(cp_int3[0] / cp_int3[1]) * (radius_in - cp_int3[0]) + cp_int3[1],
97 0.0,
98 ]
100 # Obtaining the control points positioned in the middle of the internal and external arches
101 cp_middle1 = [(cp_ext1[0] + cp_int1[0]) / 2, (cp_ext1[1] + cp_int1[1]) / 2, 0.0]
102 cp_middle2 = [(cp_ext2[0] + cp_int2[0]) / 2, (cp_ext2[1] + cp_int2[1]) / 2, 0.0]
103 cp_middle3 = [(cp_ext3[0] + cp_int3[0]) / 2, (cp_ext3[1] + cp_int3[1]) / 2, 0.0]
105 ctrlpts = [
106 cp_ext1,
107 cp_ext2,
108 cp_ext3,
109 cp_middle1,
110 cp_middle2,
111 cp_middle3,
112 cp_int1,
113 cp_int2,
114 cp_int3,
115 ]
117 weights = [
118 1.0,
119 _np.cos(angle / 2),
120 1.0,
121 1.0,
122 _np.cos(angle / 2),
123 1.0,
124 1.0,
125 _np.cos(angle / 2),
126 1.0,
127 ]
129 t_ctrlptsw = _compat.combine_ctrlpts_weights(ctrlpts, weights)
130 n_ctrlptsw = _compat.flip_ctrlpts_u(t_ctrlptsw, p_size_u, p_size_v)
132 surf.ctrlpts_size_u = p_size_u
133 surf.ctrlpts_size_v = p_size_v
134 surf.ctrlptsw = n_ctrlptsw
136 surf.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
137 surf.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
139 do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v)
141 return surf
144def create_nurbs_cylindrical_shell_sector(
145 radius: float, angle: float, length: float, *, n_ele_u: int = 1, n_ele_v: int = 1
146) -> _NURBS.Surface:
147 """Creates a NURBS surface representing a 3D sector of a cylindrical shell.
148 The center of the cylindrical shell sector is located at [0, 0, 0].
150 Args:
151 radius: Radius of the cylindrical shell.
152 angle: Angle of the cylindrical shell sector in radians.
153 The angle is only valid for 0 < angle <= pi according
154 to "Isogeometric Analysis: Toward Integration of CAD and FEA" by
155 J.Austin Cottrell, 2009
156 length: Length of the cylindrical shell.
157 n_ele_u: Number of elements in the parametric u-direction. Defaults to 1.
158 n_ele_v: Number of elements in the parametric v-direction. Defaults to 1.
160 Returns:
161 geomdl.NURBS.Surface: A geomdl object that contains the surface information.
162 """
164 # Check the validity of the input values:
165 if (angle >= _np.pi) or (angle < 0):
166 raise ValueError(
167 "The following algorithm for creating a cylindrical shell sector is only valid for 0 < angle <= pi."
168 )
170 # Create a NURBS surface instance
171 surf = _NURBS.Surface()
173 # Set degrees
174 surf.degree_u = 2
175 surf.degree_v = 2
177 # Control points and set them to the surface
178 p_size_u = 3
179 p_size_v = 3
181 # Obtaining the control points
182 cp_1 = [-radius * _np.sin(angle / 2), -length / 2, -radius * _np.cos(angle / 2)]
183 cp_3 = [radius * _np.sin(angle / 2), -length / 2, -radius * _np.cos(angle / 2)]
185 # Calculating position of middle points. This is done by
186 # obtaining the tangents on the points cp_1 and cp_3 and
187 # calculating the intersection point between the tangents.
188 m_1 = -_np.tan(-angle / 2)
189 m_3 = -_np.tan(angle / 2)
190 b_1 = cp_1[2] + m_1 * cp_1[0]
191 b_3 = cp_3[2] + m_3 * cp_3[0]
193 inter_point_x = (b_3 - b_1) / (m_3 - m_1)
194 inter_point_z = m_1 * inter_point_x + b_1
196 # The intersection point is assigned to the middle points cp_2, cp_5 and cp_8
197 cp_2 = [inter_point_x, -length / 2, inter_point_z]
199 cp_4 = [-radius * _np.sin(angle / 2), 0.0, -radius * _np.cos(angle / 2)]
200 cp_5 = [inter_point_x, 0.0, inter_point_z]
201 cp_6 = [radius * _np.sin(angle / 2), 0.0, -radius * _np.cos(angle / 2)]
203 cp_7 = [
204 -radius * _np.sin(angle / 2),
205 length / 2,
206 -radius * _np.cos(angle / 2),
207 ]
208 cp_8 = [inter_point_x, length / 2, inter_point_z]
209 cp_9 = [radius * _np.sin(angle / 2), length / 2, -radius * _np.cos(angle / 2)]
211 ctrlpts = [cp_1, cp_4, cp_7, cp_2, cp_5, cp_8, cp_3, cp_6, cp_9]
213 weights = [
214 1.0,
215 1.0,
216 1.0,
217 _np.cos(angle / 2),
218 _np.cos(angle / 2),
219 _np.cos(angle / 2),
220 1.0,
221 1.0,
222 1.0,
223 ]
225 t_ctrlptsw = _compat.combine_ctrlpts_weights(ctrlpts, weights)
227 surf.ctrlpts_size_u = p_size_u
228 surf.ctrlpts_size_v = p_size_v
229 surf.ctrlptsw = t_ctrlptsw
231 surf.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
232 surf.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
234 do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v)
236 return surf
239def create_nurbs_flat_plate_2d(width, length, *, n_ele_u=1, n_ele_v=1):
240 """Creates a patch of a 2 dimensional flat plate.
242 Args
243 ----
244 width: double
245 dimension of the plate in the x-direction
246 length: double
247 dimension of the plate in the y-direction
248 n_ele_u: int
249 number of elements in the parametric u-direction
250 n_ele_v: int
251 number of elements in the parametric v-direction
254 Return
255 ----
256 surf: geomdl object
257 geomdl object that contains the surface information
258 """
260 # Create a NURBS surface instance
261 surf = _NURBS.Surface()
263 # Set degrees
264 surf.degree_u = 2
265 surf.degree_v = 2
267 # Control points and set them to the surface
268 p_size_u = 3
269 p_size_v = 3
271 ctrlpts = [
272 [-width / 2, -length / 2, 0.0],
273 [0.0, -length / 2, 0.0],
274 [width / 2, -length / 2, 0.0],
275 [-width / 2, 0.0, 0.0],
276 [0.0, 0.0, 0.0],
277 [width / 2, 0.0, 0.0],
278 [-width / 2, length / 2, 0.0],
279 [0.0, length / 2, 0.0],
280 [width / 2, length / 2, 0.0],
281 ]
283 weights = [1.0] * 9
285 t_ctrlptsw = _compat.combine_ctrlpts_weights(ctrlpts, weights)
286 n_ctrlptsw = _compat.flip_ctrlpts_u(t_ctrlptsw, p_size_u, p_size_v)
288 surf.ctrlpts_size_u = p_size_u
289 surf.ctrlpts_size_v = p_size_v
290 surf.ctrlptsw = n_ctrlptsw
292 surf.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
293 surf.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
295 do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v)
297 return surf
300def create_nurbs_sphere_surface(radius, n_ele_u=1, n_ele_v=1):
301 """Generates a patch of a sphere as a NURBS surface. This function
302 constructs a segment of a spherical surface using Non-Uniform Rational
303 B-Splines (NURBS) based on the specified radius and the number of elements
304 in the parametric u and v directions.
306 Args
307 ---
308 radius: double
309 radius of the sphere
310 n_ele_u: int
311 number of elements in the parametric u-direction
312 n_ele_v: int
313 number of elements in the parametric v-direction
315 Return
316 ----
317 surf: geomdl object
318 geomdl object that contains the surface information
319 """
321 # Create a NURBS surface instance
322 surf = _NURBS.Surface()
324 # Set degrees
325 surf.degree_u = 2
326 surf.degree_v = 2
328 # Control points and set them to the surface
329 p_size_u = 3
330 p_size_v = 3
332 dummy = 6.0 * (
333 5.0 / 12.0
334 + 0.5 * _np.sqrt(2.0 / 3.0)
335 - 0.25 / _np.sqrt(3.0)
336 - 0.5 * _np.sqrt(2.0 / 3.0) * _np.sqrt(3.0) / 2.0
337 )
339 ctrlpts = [
340 [
341 2.0 * radius / _np.sqrt(6.0) * -_np.sin(1.0 / 4.0 * _np.pi),
342 -radius / _np.sqrt(3.0),
343 2.0 * radius / _np.sqrt(6.0) * _np.cos(1.0 / 4.0 * _np.pi),
344 ],
345 [
346 radius * _np.sqrt(3.0) / (_np.sqrt(2.0) * 2.0) * _np.cos(1.0 / 4.0 * _np.pi)
347 + radius
348 * _np.sqrt(3.0)
349 / (_np.sqrt(2.0) * 2.0)
350 * -_np.sin(1.0 / 4.0 * _np.pi),
351 -_np.sqrt(3.0) / 2 * radius,
352 radius * _np.sqrt(3.0) / (_np.sqrt(2.0) * 2.0) * _np.cos(1.0 / 4.0 * _np.pi)
353 + radius
354 * _np.sqrt(3.0)
355 / (_np.sqrt(2.0) * 2.0)
356 * _np.sin(1.0 / 4.0 * _np.pi),
357 ],
358 [
359 2.0 * radius / _np.sqrt(6.0) * _np.cos(1.0 / 4.0 * _np.pi),
360 -radius / _np.sqrt(3.0),
361 2.0 * radius / _np.sqrt(6.0) * _np.sin(1.0 / 4.0 * _np.pi),
362 ],
363 [
364 radius * _np.sqrt(6.0) / 2.0 * -_np.sin(1.0 / 4.0 * _np.pi),
365 0.0,
366 radius * _np.sqrt(6.0) / 2.0 * _np.cos(1.0 / 4.0 * _np.pi),
367 ],
368 [
369 radius * dummy * _np.sqrt(2.0) / 2.0 * _np.cos(1.0 / 4.0 * _np.pi)
370 + radius * dummy * _np.sqrt(2.0) / 2.0 * -_np.sin(1.0 / 4.0 * _np.pi),
371 0.0,
372 radius * dummy * _np.sqrt(2.0) / 2.0 * _np.cos(1.0 / 4.0 * _np.pi)
373 + radius * dummy * _np.sqrt(2.0) / 2.0 * _np.sin(1.0 / 4.0 * _np.pi),
374 ],
375 [
376 radius * _np.sqrt(6.0) / 2.0 * _np.cos(1.0 / 4.0 * _np.pi),
377 0.0,
378 radius * _np.sqrt(6.0) / 2.0 * _np.sin(1.0 / 4.0 * _np.pi),
379 ],
380 [
381 2.0 * radius / _np.sqrt(6.0) * -_np.sin(1.0 / 4.0 * _np.pi),
382 2.0 * radius / _np.sqrt(6.0) * _np.cos(1.0 / 4.0 * _np.pi),
383 radius / _np.sqrt(3.0),
384 ],
385 [
386 radius * _np.sqrt(3.0) / (_np.sqrt(2.0) * 2.0) * _np.cos(1.0 / 4.0 * _np.pi)
387 + radius
388 * _np.sqrt(3.0)
389 / (_np.sqrt(2.0) * 2.0)
390 * -_np.sin(1.0 / 4.0 * _np.pi),
391 _np.sqrt(3.0) / 2 * radius,
392 radius * _np.sqrt(3.0) / (_np.sqrt(2.0) * 2.0) * _np.cos(1.0 / 4.0 * _np.pi)
393 + radius
394 * _np.sqrt(3.0)
395 / (_np.sqrt(2.0) * 2.0)
396 * _np.sin(1.0 / 4.0 * _np.pi),
397 ],
398 [
399 2.0 * radius / _np.sqrt(6.0) * _np.cos(1.0 / 4.0 * _np.pi),
400 radius / _np.sqrt(3.0),
401 2.0 * radius / _np.sqrt(6.0) * _np.sin(1.0 / 4.0 * _np.pi),
402 ],
403 ]
405 weights = [
406 1.0,
407 2.0 / _np.sqrt(6.0),
408 1.0,
409 2.0 / _np.sqrt(6.0),
410 2.0 / 3.0,
411 2.0 / _np.sqrt(6.0),
412 1.0,
413 2.0 / _np.sqrt(6.0),
414 1.0,
415 ]
417 t_ctrlptsw = _compat.combine_ctrlpts_weights(ctrlpts, weights)
418 n_ctrlptsw = _compat.flip_ctrlpts_u(t_ctrlptsw, p_size_u, p_size_v)
420 surf.ctrlpts_size_u = p_size_u
421 surf.ctrlpts_size_v = p_size_v
422 surf.ctrlptsw = n_ctrlptsw
424 surf.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
425 surf.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
427 do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v)
429 return surf
432def create_nurbs_hemisphere_surface(radius, n_ele_uv=1):
433 """Generates a hemisphere as a NURBS surface. This function constructs five
434 segments that represent the surface of a hemisphere using Non-Uniform
435 Rational B-Splines (NURBS) based on the specified radius and the number of
436 elements in the parametric u and v directions. To secure the connectivity
437 between surfaces, all surfaces must have the same parametric representation
438 in any parametric direction. Therefore, the number of elements in u- and v-
439 directions must be the same.
441 This function generates a list of five NURBS geomdl objects.
443 Args
444 ---
445 radius: double
446 Radius of the hemisphere
447 n_ele_uv: int
448 Number of elements in the parametric u- and v- directions
450 Return
451 ----
452 list: list(geomdl object)
453 A list of geomdl objects that contains the surface information
454 """
456 # Create the first section of the hemisphere
457 hemisphere_1 = create_nurbs_sphere_surface(radius, n_ele_u=1, n_ele_v=1)
459 # Create a temporary section by rotating and translating the
460 # first section of the hemisphere
461 temp_hemisphere = _operations.rotate(hemisphere_1, 90, axis=1)
462 temp_hemisphere = _operations.translate(
463 temp_hemisphere,
464 (0, 0, -2.0 * radius / _np.sqrt(6.0) * _np.sin(1.0 / 4.0 * _np.pi) * 2),
465 )
467 # To create the hemisphere it is necessary to split the temporary
468 # sphere section in two pieces. This split is done in u = 0.5. After
469 # the split, the second surface is taken as it will be
470 # adjacent to the first section of the sphere
471 cut_section_sphere = _operations.split_surface_u(temp_hemisphere, param=0.5)
472 hemisphere_2 = cut_section_sphere[1]
474 translation_component = radius * _np.sin(1.0 / 4.0 * _np.pi) * 2
475 # Create the third section. Rotate and translate it accordingly
476 hemisphere_3 = _operations.rotate(hemisphere_2, 90, axis=2)
477 hemisphere_3 = _operations.translate(hemisphere_3, (translation_component, 0, 0))
479 # Create the forth section. Rotate and translate it accordingly
480 hemisphere_4 = _operations.rotate(hemisphere_3, 90, axis=2)
481 hemisphere_4 = _operations.translate(hemisphere_4, (0, translation_component, 0))
483 # Create the fifth section. Rotate and translate it accordingly
484 hemisphere_5 = _operations.rotate(hemisphere_4, 90, axis=2)
485 hemisphere_5 = _operations.translate(hemisphere_5, (-translation_component, 0, 0))
487 patches = [hemisphere_1, hemisphere_2, hemisphere_3, hemisphere_4, hemisphere_5]
488 for patch in patches:
489 do_uniform_knot_refinement_surface(patch, n_ele_uv, n_ele_uv)
490 return patches
493def create_nurbs_torus_surface(radius_torus, radius_circle, *, n_ele_u=1, n_ele_v=1):
494 """Creates a NURBS patch for the construction of a ring torus (outer
495 surface). A ring torus is a surface of revolution generated by revolving a
496 circle in a 3-dimensional space around an axis of revolution (axis z). The
497 center of the torus is located at the coordinates [0, 0, 0].
499 This function constructs the surface of a ring torus in the following manner:
500 - The quarter of the torus is made by 4 patches
501 - These patches are rotated three times around the z-axis by 90°, e.g. theta = 90°, 180°, 270°,
502 leading to a total of 16 NURBS patches.
504 The number of elements in this function are given for a single patch, where:
505 - n_ele_u is the number of elements in the "radius_torus" direction
506 - n_ele_v is the number of elements in the "radius_circle" direction
508 This function generates a list of 16 NURBS geomdl objects.
510 Args
511 ----
512 radius_torus: double
513 distance from the axis of revolution (axis z) to the center of the revolving circle
514 radius_circle: double
515 radius of the circle that revolves around the axis of revolution
516 n_ele_u: int
517 number of elements in the parametric u-direction
518 n_ele_v: int
519 number of elements in the parametric v-direction
520 """
522 # Create four NURBS surface instances. These are the base patches of the torus.
523 surf_1 = _NURBS.Surface()
524 surf_2 = _NURBS.Surface()
525 surf_3 = _NURBS.Surface()
526 surf_4 = _NURBS.Surface()
527 base_surfs = [surf_1, surf_2, surf_3, surf_4]
529 # Define control points and set them to the surfaces
530 p_size_u = 3
531 p_size_v = 3
533 dummy_surf1 = radius_torus + radius_circle
534 dummy_surf2 = radius_torus - radius_circle
536 ctrlpts_surf1 = [
537 [dummy_surf1, 0.0, 0.0],
538 [dummy_surf1, 0.0, radius_circle],
539 [radius_torus, 0.0, radius_circle],
540 [dummy_surf1, dummy_surf1, 0.0],
541 [dummy_surf1, dummy_surf1, radius_circle],
542 [radius_torus, radius_torus, radius_circle],
543 [0.0, dummy_surf1, 0.0],
544 [0.0, dummy_surf1, radius_circle],
545 [0.0, radius_torus, radius_circle],
546 ]
548 ctrlpts_surf2 = [
549 [dummy_surf1, 0.0, 0.0],
550 [dummy_surf1, 0.0, -radius_circle],
551 [radius_torus, 0.0, -radius_circle],
552 [dummy_surf1, dummy_surf1, 0.0],
553 [dummy_surf1, dummy_surf1, -radius_circle],
554 [radius_torus, radius_torus, -radius_circle],
555 [0.0, dummy_surf1, 0.0],
556 [0.0, dummy_surf1, -radius_circle],
557 [0.0, radius_torus, -radius_circle],
558 ]
560 ctrlpts_surf3 = [
561 [radius_torus, 0.0, -radius_circle],
562 [dummy_surf2, 0.0, -radius_circle],
563 [dummy_surf2, 0.0, 0.0],
564 [radius_torus, radius_torus, -radius_circle],
565 [dummy_surf2, dummy_surf2, -radius_circle],
566 [dummy_surf2, dummy_surf2, 0.0],
567 [0.0, radius_torus, -radius_circle],
568 [0.0, dummy_surf2, -radius_circle],
569 [0.0, dummy_surf2, 0.0],
570 ]
572 ctrlpts_surf4 = [
573 [0.0, dummy_surf2, 0.0],
574 [0.0, dummy_surf2, radius_circle],
575 [0.0, radius_torus, radius_circle],
576 [dummy_surf2, dummy_surf2, 0.0],
577 [dummy_surf2, dummy_surf2, radius_circle],
578 [radius_torus, radius_torus, radius_circle],
579 [dummy_surf2, 0.0, 0.0],
580 [dummy_surf2, 0.0, radius_circle],
581 [radius_torus, 0.0, radius_circle],
582 ]
584 weights = [
585 1.0,
586 _np.sqrt(2) / 2,
587 1.0,
588 _np.sqrt(2) / 2,
589 0.5,
590 _np.sqrt(2) / 2,
591 1.0,
592 _np.sqrt(2) / 2,
593 1.0,
594 ]
596 t_ctrlptsw1 = _compat.combine_ctrlpts_weights(ctrlpts_surf1, weights)
597 t_ctrlptsw2 = _compat.combine_ctrlpts_weights(ctrlpts_surf2, weights)
598 t_ctrlptsw3 = _compat.combine_ctrlpts_weights(ctrlpts_surf3, weights)
599 t_ctrlptsw4 = _compat.combine_ctrlpts_weights(ctrlpts_surf4, weights)
601 t_ctrlpts_surfs = [t_ctrlptsw1, t_ctrlptsw2, t_ctrlptsw3, t_ctrlptsw4]
603 for surf, t_ctrlpts in zip(base_surfs, t_ctrlpts_surfs):
604 # Set degrees
605 surf.degree_u = 2
606 surf.degree_v = 2
608 surf.ctrlpts_size_u = p_size_u
609 surf.ctrlpts_size_v = p_size_v
611 # Set control points
612 surf.ctrlptsw = t_ctrlpts
614 # Set knot vectors
615 surf.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
616 surf.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
618 do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v)
620 # Define the rotations and translations to rotate the base patches and form a complete torus
621 tmp_trans = [
622 radius_torus + radius_circle,
623 radius_torus + radius_circle,
624 radius_torus,
625 radius_torus - radius_circle,
626 ]
628 transform_surf1 = [
629 [(-tmp_trans[0], tmp_trans[0], 0), 90, 2],
630 [(-2 * tmp_trans[0], 0, 0), 180, 2],
631 [(-tmp_trans[0], -tmp_trans[0], 0), 270, 2],
632 ]
634 transform_surf2 = [
635 [(-tmp_trans[1], tmp_trans[1], 0), 90, 2],
636 [(-2 * tmp_trans[1], 0, 0), 180, 2],
637 [(-tmp_trans[1], -tmp_trans[1], 0), 270, 2],
638 ]
640 transform_surf3 = [
641 [(-tmp_trans[2], tmp_trans[2], 0), 90, 2],
642 [(-2 * tmp_trans[2], 0, 0), 180, 2],
643 [(-tmp_trans[2], -tmp_trans[2], 0), 270, 2],
644 ]
646 transform_surf4 = [
647 [(-tmp_trans[3], -tmp_trans[3], 0), 90, 2],
648 [(0, -2 * tmp_trans[3], 0), 180, 2],
649 [(tmp_trans[3], -tmp_trans[3], 0), 270, 2],
650 ]
652 # Rotate base patches and store them
653 surfaces_torus = [surf_1, surf_2, surf_3, surf_4]
654 for transform1, transform2, transform3, transform4 in zip(
655 transform_surf1, transform_surf2, transform_surf3, transform_surf4
656 ):
657 new_surf1 = _operations.translate(surf_1, transform1[0])
658 new_surf1 = _operations.rotate(new_surf1, transform1[1], axis=transform1[2])
659 surfaces_torus.append(new_surf1)
661 new_surf2 = _operations.translate(surf_2, transform2[0])
662 new_surf2 = _operations.rotate(new_surf2, transform2[1], axis=transform2[2])
663 surfaces_torus.append(new_surf2)
665 new_surf3 = _operations.translate(surf_3, transform3[0])
666 new_surf3 = _operations.rotate(new_surf3, transform3[1], axis=transform3[2])
667 surfaces_torus.append(new_surf3)
669 new_surf4 = _operations.translate(surf_4, transform4[0])
670 new_surf4 = _operations.rotate(new_surf4, transform4[1], axis=transform4[2])
671 surfaces_torus.append(new_surf4)
673 return surfaces_torus
676def create_nurbs_brick(width, length, height, *, n_ele_u=1, n_ele_v=1, n_ele_w=1):
677 """Creates a patch of a 3 dimensional brick.
679 Args
680 ----
681 width: double
682 dimension of the plate in the x-direction
683 length: double
684 dimension of the plate in the y-direction
685 height: double
686 dimension of the plate in the z-direction
687 n_ele_u: int
688 number of elements in the parametric u-direction
689 n_ele_v: int
690 number of elements in the parametric v-direction
691 n_ele_w: int
692 number of elements in the parametric w-direction
695 Return
696 ----
697 vol: geomdl object
698 geomdl object that contains the volume information
699 """
701 # Create a NURBS volume instance
702 vol = _NURBS.Volume()
704 # Set degrees
705 vol.degree_u = 2
706 vol.degree_v = 2
707 vol.degree_w = 2
709 # Create control points and set them to the volume
710 cp_size_u = 3
711 cp_size_v = 3
712 cp_size_w = 3
714 ctrlpts = [
715 [-width / 2, -length / 2, -height / 2],
716 [-width / 2, 0.0, -height / 2],
717 [-width / 2, length / 2, -height / 2],
718 [0.0, -length / 2, -height / 2],
719 [0.0, 0.0, -height / 2],
720 [0.0, length / 2, -height / 2],
721 [width / 2, -length / 2, -height / 2],
722 [width / 2, 0.0, -height / 2],
723 [width / 2, length / 2, -height / 2],
724 [-width / 2, -length / 2, 0.0],
725 [-width / 2, 0.0, 0.0],
726 [-width / 2, length / 2, 0.0],
727 [0.0, -length / 2, 0.0],
728 [0.0, 0.0, 0.0],
729 [0.0, length / 2, 0.0],
730 [width / 2, -length / 2, 0.0],
731 [width / 2, 0.0, 0.0],
732 [width / 2, length / 2, 0.0],
733 [-width / 2, -length / 2, height / 2],
734 [-width / 2, 0.0, height / 2],
735 [-width / 2, length / 2, height / 2],
736 [0.0, -length / 2, height / 2],
737 [0.0, 0.0, height / 2],
738 [0.0, length / 2, height / 2],
739 [width / 2, -length / 2, height / 2],
740 [width / 2, 0.0, height / 2],
741 [width / 2, length / 2, height / 2],
742 ]
744 weights = [1.0] * 27
746 vol.ctrlpts_size_u = cp_size_u
747 vol.ctrlpts_size_v = cp_size_v
748 vol.ctrlpts_size_w = cp_size_w
750 t_ctrlptsw = _compat.combine_ctrlpts_weights(ctrlpts, weights)
752 vol.set_ctrlpts(t_ctrlptsw, cp_size_u, cp_size_v, cp_size_w)
754 vol.knotvector_u = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
755 vol.knotvector_v = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
756 vol.knotvector_w = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
758 do_uniform_knot_refinement_volume(vol, n_ele_u, n_ele_v, n_ele_w)
760 return vol
763def do_uniform_knot_refinement_surface(surf, n_ele_u, n_ele_v):
764 """This function does an uniform knot refinement in the u- and v-
765 direction.
767 Args
768 ----
769 surf: geomdl object
770 geomdl object that contains the surface information
771 n_ele_u: int
772 number of elements in the parametric u-direction
773 n_ele_v: int
774 number of elements in the parametric v-direction
776 Return
777 ----
778 surf: geomdl object
779 """
781 size_of_knotvector_u = 1 / n_ele_u
782 size_of_knotvector_v = 1 / n_ele_v
784 for i in range(1, n_ele_u):
785 _operations.insert_knot(surf, [size_of_knotvector_u * i, None], [1, 0])
786 for j in range(1, n_ele_v):
787 _operations.insert_knot(surf, [None, size_of_knotvector_v * j], [0, 1])
790def do_uniform_knot_refinement_volume(vol, n_ele_u, n_ele_v, n_ele_w):
791 """This function does an uniform knot refinement in the u-, v- and w-
792 direction.
794 Args
795 ----
796 vol: geomdl object
797 geomdl object that contains the volume information
798 n_ele_u: int
799 number of elements in the parametric u-direction
800 n_ele_v: int
801 number of elements in the parametric v-direction
802 n_ele_w: int
803 number of elements in the parametric w-direction
805 Return
806 ----
807 vol: geomdl object
808 """
810 size_of_knotvector_u = 1 / n_ele_u
811 size_of_knotvector_v = 1 / n_ele_v
812 size_of_knotvector_w = 1 / n_ele_w
814 for i in range(1, n_ele_u):
815 _operations.insert_knot(vol, [size_of_knotvector_u * i, None, None], [1, 0, 0])
816 for j in range(1, n_ele_v):
817 _operations.insert_knot(vol, [None, size_of_knotvector_v * j, None], [0, 1, 0])
818 for k in range(1, n_ele_w):
819 _operations.insert_knot(vol, [None, None, size_of_knotvector_w * k], [0, 0, 1])