Creating bodies

The most basic functions of this package create an object of type Body. There are a variety of such functions, a few of which we will demonstrate here. Generally speaking, we are interesting in creating the object and placing it in a certain position and orientation. We do this in two steps: we create the basic shape, centered at the origin with a default orientation, and then we transform the shape to a desired location and orientation. We will discuss the shapes in this notebook, and the transforms in the following notebook.

It is useful to stress that each body stores two types of points internally: the endpoints of the segments that comprise the body surface, and the midpoints of these segments. The midpoints are intended for use in downstream calculations, e.g. as forcing points in the calculations on immersed layers. The midpoints are simply the geometric averages of the endpoints, so endpoints are the ones that are transformed first, and midpoints are updated next.

using RigidBodyTools
using Plots

Creating a shape

Let's first create a shape. For any shape, we have to make a choice of the geometric dimensions (e.g, radius of the circle, side lengths of a rectangle), as well as the points that we use to discretely represent the surface. For this latter choice, there are two constructor types: we can specify the number of points (as an integer), or we can specify the nominal spacing between points (as a floating-point number).

The second approach is usually preferable when we use these tools for constructing immersed bodies. It is important to stress that the algorithms for placing points attempt to make the spacing as uniform as possible.

Let's create the most basic shape, a circle of radius 1. We will discretize it with 100 points first:

b = Circle(1.0,100)
Circular body with 100 points and radius 1.0
   Current position: (0.0,0.0)
   Current angle (rad): 0.0

Now we will create the same body with a spacing of 0.02

b = Circle(1.0,0.02)
Circular body with 312 points and radius 1.0
   Current position: (0.0,0.0)
   Current angle (rad): 0.0

This choice led to 312 points along the circumference. Quick math will tell you that the point spacing is probably not exactly 0.02. In fact, you can find out the actual spacing with dlengthmid. This function calculates the spacing associated with each point. (It does so by first calculating the spacing between midpoints between each point and its two adjacent points.)

dlengthmid(b)
312-element Vector{Float64}:
 0.020139095077842645
 0.02013909465345664
 0.020139095926384347
 0.020139093805429224
 0.020139096773551215
 0.02013909295946801
 0.020139097617965406
 0.020139092116941246
 0.020139098458258977
 0.020139091279220516
 ⋮
 0.020139098876402556
 0.02013909169742879
 0.020139098038677593
 0.020139092537724373
 0.02013909719615391
 0.020139093382138724
 0.020139096350192693
 0.020139094229301876
 0.020139095502170006

It is just a bit larger than 0.02.

A few other useful functions on the shape. To simply know the number of points,

length(b)
312

To find the outward normal vectors (based on the perpendicular to the line joining the adjacent midpoints):

nx, ny = normalmid(b)
([0.9999999999994525, 0.9997972500513201, 0.9991889560711664, 0.9981756172871938, 0.9967572242069879, 0.9949349397149403, 0.9927087488883317, 0.9900804735231573, 0.9870500969577222, 0.9836200924747993  …  0.9797908571175543, 0.9836197214184416, 0.9870504283171553, 0.9900801823981242, 0.9927089993067586, 0.9949347304092867, 0.9967573920603647, 0.9981754911583587, 0.9991890402708846, 0.9997972079172882], [1.0463939213204075e-6, 0.02013600729582963, 0.04026698480657073, 0.06037745484309014, 0.08046760833515793, 0.10052097161502202, 0.12053771144568437, 0.14050144464794798, 0.16041230032560236, 0.1802540254193159  …  -0.20002468924822323, -0.18025605020832927, -0.16041026138910267, -0.14050349612197227, -0.1205356490643909, -0.10052304325576243, -0.0804655290979954, -0.060379540001306534, -0.04026489541211434, -0.020138099234901622])

We can also plot the shape

plot(b)
Example block output

Sometimes we don't want to fill in the shape (and maybe change the line color). In that case, we can use

plot(b,fill=:false,linecolor=:black)
Example block output

Other shapes

Let's see some other shapes in action, like a square and an ellipse

b1, b2 = Square(1.0,0.02), Ellipse(0.6,0.1,0.02)
plot(plot(b1), plot(b2))
Example block output

A NACA 4412 airfoil, with chord length 1, and 0.02 spacing between points.

b = NACA4(0.04,0.4,0.12,0.02)
plot(b)
Example block output

A flat plate with no thickness

b = Plate(1.0,0.02)
plot(b)
Example block output

and a flat plate with a 5 percent thickness (and rounded ends)

b = ThickPlate(1.0,0.05,0.01)
plot(b)
Example block output

There are also some generic tools for creating shapes. A BasicBody simply consists of points that describe the vertices. The interface for this is very simple.

x = [1.0, 1.2, 0.7, 0.6, 0.2, -0.1, 0.1, 0.4]
y = [0.1, 0.5, 0.8, 1.2, 0.8, 0.6, 0.2, 0.3]
b = BasicBody(x,y)
Basic pointwise-specified body with 8 points
   Current position: (0.0,0.0)
   Current angle (rad): 0.0
plot(b)
scatter!(b,markersize=3,markercolor=:black)
Example block output

However, this function does not insert any points along the sides between vertices. We have to do the work of specifying these points in the original call. For this reason, there are a few functions that are more directly useful. For example, we can create a polygon from these vertices, with a specified spacing between points distributed along the polygon sides

b = Polygon(x,y,0.02)
Closed polygon with 8 vertices and 188 points
   Current position: (0.0,0.0)
   Current angle (rad): 0.0
plot(b)
scatter!(b,markersize=3,markercolor=:black)
Example block output

Alternatively, we can interpret those original points as control points for splines, with a spacing between points along the splines provided:

b = SplinedBody(x,y,0.02)
Basic pointwise-specified body with 198 points
   Current position: (0.0,0.0)
   Current angle (rad): 0.0
plot(b)
scatter!(b,markersize=3,markercolor=:black)
Example block output

Body functions

RigidBodyTools.BasicBodyType
BasicBody(x,y[,closuretype=ClosedBody]) <: Body

Construct a body by simply passing in the x and y coordinate vectors. The last point will be automatically connected to the first point. The coordinate vectors are assumed to be expressed in the body-fixed coordinate system. The optional closuretype specifies whether the body is closed (ClosedBody) or open (OpenBody). If closed, then the first and last points are assumed joined in operations that require neighbor points.

source
RigidBodyTools.PolygonType
Polygon(x::Vector,y::Vector,n[,closuretype=ClosedBody])

Create a polygon shape with vertices x and y, with approximately n points distributed along the perimeter.

source
RigidBodyTools.CircleFunction
Circle(a,n) <: Body

Construct a circular body with radius a and with n points distributed on the body perimeter.

source
Circle(a,targetsize::Float64) <: Body

Construct a circular body with radius a with spacing between points set approximately to targetsize.

source
RigidBodyTools.EllipseType
Ellipse(a,b,n[,endpointson=false],[shifted=false]) <: Body

Construct an elliptical body with semi-major axis a and semi-minor axis b, with n points distributed on the body perimeter. Can also call this with Ellipse(a,b,ds) where ds is the desired spacing between points. If endpointson=true, then the endpoints will be placed on the surface and the midpoints will lie inside the nominal ellipse. By default, the midpoints lie on the ellipse. If shifted=true, then the first endpoint lies on an axis of symmetry. By default the first midpoint lies on the axis symmetry.

source
RigidBodyTools.NACA4Type
NACA4(cam,pos,thick,ds::Float64,[len=1.0]) <: Body{N}

Generates points in the shape of a NACA 4-digit airfoil. The relative camber is specified by cam, the position of maximum camber (as fraction of chord) by pos, and the relative thickness by thick. The parameter ds specifies the distance between points. The optional parameter len specifies the chord length, which defaults to 1.0.

Example

julia> b = NACA4(0.0,0.0,0.12,0.02);
source
RigidBodyTools.PlateFunction
Plate(a,n) <: Body

Construct a flat plate of zero thickness with length a, divided into n equal segments.

source
Plate(a,ds) <: Body

Construct a flat plate of zero thickness with length a, with approximate spacing ds between points.

source
RigidBodyTools.RectangleFunction
Rectangle(a,b,n) <: Body

Construct a rectangular body with x̃ side half-length a and ỹ side half-length b, with approximately n points distributed along the perimeter. The centroid of the rectangle is placed at the origin (so that the lower left corner is at (-a,-b)).

Points are not placed at the corners, but rather, are shifted by half a segment. This ensures that all normals are perpendicular to the sides.

source
Rectangle(a,b,ds) <: Body

Construct a rectangular body with x̃ side half-length a and ỹ side half-length b, with approximate spacing ds between points.

source
RigidBodyTools.SplinedBodyFunction
SplinedBody(X,Δx[,closuretype=ClosedBody]) -> BasicBody

Using control points in X (assumed to be N x 2, where N is the number of points), create a set of points that are uniformly spaced (with spacing Δx) on a curve that passes through the control points. A cubic parametric spline algorithm is used. If the optional parameter closuretype is set to OpenBody, then the end points are not joined together.

source
SplinedBody(x,y,Δx[,closuretype=ClosedBody]) -> BasicBody

Using control points in x and y, create a set of points that are uniformly spaced (with spacing Δx) on a curve that passes through the control points. A cubic parametric spline algorithm is used. If the optional parameter closuretype is set to OpenBody, then the end points are not joined together.

source
RigidBodyTools.SquareFunction
Square(a,n) <: Body

Construct a square body with side half-length a and with approximately n points distributed along the perimeter.

source
Square(a,ds) <: Body

Construct a square body with side half-length a, with approximate spacing ds between points.

source

Shape utilities

RigidBodyTools.centraldiffFunction
centraldiff(body::Body[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the circular central differences of coordinates on body body (or on each body in list body). If axes=:body, uses the reference coordinates in body-fixed space.

source
centraldiff(bl::BodyList[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the centraldiff on each constituent body in bl. If axes=:body, uses the reference coordinates in body-fixed space.

source
Base.diffMethod
diff(body::Body[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the x and y differences of the faces on the perimeter of body body, whose ends are at the current x and y coordinates (in inertial space) of the body (if axes=:inertial), or at the reference and coordinates (body-fixed space) if axes=:body. Face 1 corresponds to the face between points 1 and 2, for example.

If body is a BodyList, then it computes the differences separately on each constituent body.

source
Base.diffMethod
diff(bl::BodyList[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the diff on each constituent body in bl.

source
RigidBodyTools.dlengthFunction
dlength(body::Body/BodyList[;axes=:inertial]) -> Vector{Float64}

Compute the lengths of the faces on the perimeter of body body, whose ends are at the current xend and yend coordinates (in inertial space) of the body. Face 1 corresponds to the face between endpoints 1 and 2, for example. If axes=:body, uses the reference coordinates in body-fixed space.

source
Base.lengthMethod
length(body::Body)

Return the number of points on the body perimeter

source
RigidBodyTools.midpointsMethod
midpoints(body::Body[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the x and y midpoints of the faces on the perimeter of body body, whose ends are at the current x and y coordinates (in inertial space) of the body (if axes=:inertial), or at the reference and coordinates (body-fixed space) if axes=:body. Face 1 corresponds to the face between points 1 and 2, for example.

If body is a BodyList, then it computes the differences separately on each constituent body.

source
RigidBodyTools.midpointsMethod
midpoints(bl::BodyList[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the midpoints on each constituent body in bl.

source
RigidBodyTools.normalFunction
normal(body::Body/BodyList[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the current normals in inertial components (if axes=:inertial) or body- fixed components (if axes=:body) of the faces on the perimeter of body body, whose ends are at the current xend and yend coordinates (in inertial space) of the body. Face 1 corresponds to the face between points 1 and 2, for example. For an OpenBody, this provides a vector that is one element shorter than the number of points.

source
RigidBodyTools.normalmidFunction
normalmid(body::Body/BodyList[;axes=:inertial]) -> Tuple{Vector{Float64},Vector{Float64}}

Compute the current normals in inertial components (if axes=:inertial) or body- fixed components (if axes=:body) of the faces formed between endpoints on the perimeter of body body (or each body in list body).

source
RigidBodyTools.arccoordFunction
arccoord(body::Body/BodyList[;axes=:inertial]) -> Vector{Float64}

Returns a vector containing the arclength coordinate along the surface of body, evaluated at the second endpoint of each face. So, e.g., the first coordinate would be the length of face 1, the second the length of face 2, and the last would be total length of all of the faces. Use inertial components (if axes=:inertial) or body-fixed components (if axes=:body). If this is a body list, restart the origin of the coordinates on each body in the list.

source
RigidBodyTools.arccoordmidFunction
arccoordmid(body::Body/BodyList[;axes=:inertial]) -> Vector{Float64}

Returns a vector containing the arclength coordinate along the surface of body, evaluated at the midpoints between the ends of faces. So, e.g., the first coordinate would be half of the length of face 1, the second would be half of face 2 plus all of face 1, etc. Use inertial components (if axes=:inertial) or body- fixed components (if axes=:body). If this is a body list, restart the origin of the coordinates on each body in the list.

source
RigidBodyTools.arclengthMethod
arclength(body::Body[;axes=:inertial])

Compute the total arclength of body, from the sum of the lengths of the faces. If axes=:body, use the body-fixed coordinates.

source
RigidBodyTools.arclengthMethod
arclength(bl::BodyList[;axes=:inertial]) -> Vector{Float64}

Compute the total arclength of each body in bl and assemble the results into a vector. If axes=:body, use the body-fixed coordinates.

source

This page was generated using Literate.jl.