NURBS Topology#
|
Modelling a doubly curved NURBS surface bounded by four NURBS lines and reshaping it through its control points:
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),
]
)))
using Common = Dlubal.Api.Common;
using Rfem = Dlubal.Api.Rfem;
using Google.Protobuf;
ApplicationRfem? rfemApp = null;
try
{
rfemApp = new ApplicationRfem();
rfemApp.close_all_models(saveChanges: false);
rfemApp.create_model(name: "nurbs_surfaces");
rfemApp.delete_all_objects();
// Material and thickness of the surface.
rfemApp.create_object_list(new List<IMessage>
{
new Rfem.StructureCore.Material { No = 1, Name = "S235" },
new Rfem.StructureCore.Thickness { No = 1, Material = 1, UniformThickness = 0.020 },
});
// Corner nodes of the surface.
rfemApp.create_object_list(new List<IMessage>
{
new Rfem.StructureCore.Node { No = 1, GlobalCoordinates = new Common.Vector3d { X = 11.000, Y = 0.000, Z = 0.000 } },
new Rfem.StructureCore.Node { No = 2, GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.000, Z = 0.000 } },
new Rfem.StructureCore.Node { No = 3, GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.000, Z = -2.000 } },
new Rfem.StructureCore.Node { No = 4, GlobalCoordinates = new Common.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.
rfemApp.create_object_list(new List<IMessage>
{
new Rfem.StructureCore.Line
{
No = 1,
Type = Rfem.StructureCore.Line.Types.Type.Nurbs,
DefinitionNodes = { 2, 1 },
NurbsOrder = 3,
NurbsControlPoints = new Rfem.StructureCore.Line.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow { GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.200, Z = 0.000 }, Weight = 1.000 },
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
}
},
},
new Rfem.StructureCore.Line
{
No = 2,
Type = Rfem.StructureCore.Line.Types.Type.Nurbs,
DefinitionNodes = { 1, 4 },
NurbsOrder = 3,
NurbsControlPoints = new Rfem.StructureCore.Line.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow { GlobalCoordinates = new Common.Vector3d { X = 11.000, Y = 0.000, Z = -1.000 }, Weight = 1.000 },
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
}
},
},
new Rfem.StructureCore.Line
{
No = 3,
Type = Rfem.StructureCore.Line.Types.Type.Nurbs,
DefinitionNodes = { 2, 3 },
NurbsOrder = 3,
NurbsControlPoints = new Rfem.StructureCore.Line.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow { GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.300, Z = -1.000 }, Weight = 1.000 },
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
}
},
},
new Rfem.StructureCore.Line
{
No = 4,
Type = Rfem.StructureCore.Line.Types.Type.Nurbs,
DefinitionNodes = { 3, 4 },
NurbsOrder = 3,
NurbsControlPoints = new Rfem.StructureCore.Line.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow(),
new Rfem.StructureCore.Line.Types.NurbsControlPointsRow { GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.100, Z = -2.000 }, Weight = 1.000 },
new Rfem.StructureCore.Line.Types.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.
var controlPoints = new Rfem.StructureCore.Surface.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 1, V = 1, GlobalCoordinates = new Common.Vector3d { X = 11.000, Y = 0.000, Z = -2.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 1, V = 2, GlobalCoordinates = new Common.Vector3d { X = 11.000, Y = 0.000, Z = -1.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 1, V = 3, GlobalCoordinates = new Common.Vector3d { X = 11.000, Y = 0.000, Z = 0.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 2, V = 1, GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.100, Z = -2.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 2, V = 2, GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.100, Z = -1.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 2, V = 3, GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.200, Z = 0.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 3, V = 1, GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.000, Z = -2.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 3, V = 2, GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.300, Z = -1.000 }, Weight = 1.000 },
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 3, V = 3, GlobalCoordinates = new Common.Vector3d { X = 9.000, Y = 0.000, Z = 0.000 }, Weight = 1.000 },
}
};
var surface = new Rfem.StructureCore.Surface
{
No = 1,
Geometry = Rfem.StructureCore.Surface.Types.Geometry.Nurbs,
BoundaryLines = { 4, 3, 1, 2 },
Thickness = 1,
NurbsControlPointCountInDirectionU = 3,
NurbsControlPointCountInDirectionV = 3,
NurbsOrderInDirectionU = 3,
NurbsOrderInDirectionV = 3,
NurbsControlPoints = controlPoints,
};
rfemApp.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.
rfemApp.update_object(new Rfem.StructureCore.Surface
{
No = 1,
NurbsControlPoints = new Rfem.StructureCore.Surface.Types.NurbsControlPointsTable
{
Rows =
{
new Rfem.StructureCore.Surface.Types.NurbsControlPointsRow { U = 2, V = 2, GlobalCoordinates = new Common.Vector3d { X = 10.000, Y = 0.500, Z = -1.000 }, Weight = 2.000 },
}
},
});
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (rfemApp != null) rfemApp.close_connection();
}