NURBS Topology#

../../../../_images/nurbs_topology.png

Modelling a doubly curved NURBS surface bounded by four NURBS lines and reshaping it through its control points:

  • Create the material and the thickness assigned to the surface

  • Define the four corner nodes of the surface boundary

  • Create four NURBS boundary lines, each with three control points whose end points are given by the nodes

  • Assemble the 3 x 3 control-point matrix of the surface, addressing every row by its u and v position

  • Create the NURBS surface from the boundary lines and the control-point matrix, with order 3 in both directions

  • Update a single inner control point by lifting it and increasing its weight to pull the surface towards it

Keywords:
nurbs surface nurbs line control points control point weight surface geometry
import dlubal.api.rfem as rfem
from dlubal.api.common import Vector3d

with rfem.Application() as client:

    client.close_all_models(save_changes=False)
    client.create_model(name="nurbs_surfaces")
    client.delete_all_objects()

    # Material and thickness of the surface.
    client.create_object_list([
        rfem.structure_core.Material(no=1, name="S235"),
        rfem.structure_core.Thickness(no=1, material=1, uniform_thickness=0.020)
    ])

    # Corner nodes of the surface.
    client.create_object_list([
        rfem.structure_core.Node(no=1, global_coordinates=Vector3d(x=11.000, y=0.000, z=0.000)),
        rfem.structure_core.Node(no=2, global_coordinates=Vector3d(x=9.000, y=0.000, z=0.000)),
        rfem.structure_core.Node(no=3, global_coordinates=Vector3d(x=9.000, y=0.000, z=-2.000)),
        rfem.structure_core.Node(no=4, global_coordinates=Vector3d(x=11.000, y=0.000, z=-2.000))
    ])

    # Boundary of a NURBS surface is formed by four NURBS lines.
    # Each of them has three control points, the first and the last one correspond
    # to the end nodes of the line, so we don't need to set any data for them.
    client.create_object_list([
        rfem.structure_core.Line(
            no=1,
            type=rfem.structure_core.Line.TYPE_NURBS,
            definition_nodes=[2, 1],
            nurbs_order=3,
            nurbs_control_points=rfem.structure_core.Line.NurbsControlPointsTable(
                rows=[
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                    rfem.structure_core.Line.NurbsControlPointsRow(global_coordinates=Vector3d(x=10.000, y=0.200, z=0.000), weight=1.000),
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                ]
            )),
        rfem.structure_core.Line(
            no=2,
            type=rfem.structure_core.Line.TYPE_NURBS,
            definition_nodes=[1, 4],
            nurbs_order=3,
            nurbs_control_points=rfem.structure_core.Line.NurbsControlPointsTable(
                rows=[
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                    rfem.structure_core.Line.NurbsControlPointsRow(global_coordinates=Vector3d(x=11.000, y=0.000, z=-1.000), weight=1.000),
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                ]
            )),
        rfem.structure_core.Line(
            no=3,
            type=rfem.structure_core.Line.TYPE_NURBS,
            definition_nodes=[2, 3],
            nurbs_order=3,
            nurbs_control_points=rfem.structure_core.Line.NurbsControlPointsTable(
                rows=[
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                    rfem.structure_core.Line.NurbsControlPointsRow(global_coordinates=Vector3d(x=9.000, y=0.300, z=-1.000), weight=1.000),
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                ]
            )),
        rfem.structure_core.Line(
            no=4,
            type=rfem.structure_core.Line.TYPE_NURBS,
            definition_nodes=[3, 4],
            nurbs_order=3,
            nurbs_control_points=rfem.structure_core.Line.NurbsControlPointsTable(
                rows=[
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                    rfem.structure_core.Line.NurbsControlPointsRow(global_coordinates=Vector3d(x=10.000, y=0.100, z=-2.000), weight=1.000),
                    rfem.structure_core.Line.NurbsControlPointsRow(),
                ]
            ))
    ])

    # Prepare NURBS control points table of the surface.
    # In contrast to the control points of a NURBS line, the control points of a NURBS surface
    # form a 2D matrix, so each row must be addressed by its position in the matrix
    # via the 'u' and 'v' attributes (the 'no' attribute is not used here).
    # The size of the matrix is given by the number of control points in both directions.
    # The rows lying on the boundary of the matrix are defined by the boundary lines,
    # therefore only the inner control point (u=2, v=2) is a new information here.
    # The rows may be listed in any order and rows that are left out keep their current values.
    control_points = rfem.structure_core.Surface.NurbsControlPointsTable(
        rows=[
            rfem.structure_core.Surface.NurbsControlPointsRow(u=1, v=1, global_coordinates=Vector3d(x=11.000, y=0.000, z=-2.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=1, v=2, global_coordinates=Vector3d(x=11.000, y=0.000, z=-1.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=1, v=3, global_coordinates=Vector3d(x=11.000, y=0.000, z=0.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=2, v=1, global_coordinates=Vector3d(x=10.000, y=0.100, z=-2.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=2, v=2, global_coordinates=Vector3d(x=10.000, y=0.100, z=-1.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=2, v=3, global_coordinates=Vector3d(x=10.000, y=0.200, z=0.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=3, v=1, global_coordinates=Vector3d(x=9.000, y=0.000, z=-2.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=3, v=2, global_coordinates=Vector3d(x=9.000, y=0.300, z=-1.000), weight=1.000),
            rfem.structure_core.Surface.NurbsControlPointsRow(u=3, v=3, global_coordinates=Vector3d(x=9.000, y=0.000, z=0.000), weight=1.000),
        ]
    )

    surface = rfem.structure_core.Surface(
        no=1,
        geometry=rfem.structure_core.Surface.GEOMETRY_NURBS,
        boundary_lines=[4, 3, 1, 2],
        thickness=1,
        nurbs_control_point_count_in_direction_u=3,
        nurbs_control_point_count_in_direction_v=3,
        nurbs_order_in_direction_u=3,
        nurbs_order_in_direction_v=3,
        nurbs_control_points=control_points)

    client.create_object(surface)

    # Since every row is addressed by its 'u' and 'v' attributes, a single control point
    # can be modified without repeating the whole matrix.
    # Here we lift the inner control point and increase its weight,
    # which pulls the surface closer to that point.
    client.update_object(
        rfem.structure_core.Surface(
            no=1,
            nurbs_control_points=rfem.structure_core.Surface.NurbsControlPointsTable(
                rows=[
                    rfem.structure_core.Surface.NurbsControlPointsRow(u=2, v=2, global_coordinates=Vector3d(x=10.000, y=0.500, z=-1.000), weight=2.000),
                ]
            )))