A Julia repository containing code for Free Form Deformation using B-splines.
You only need to clone the repository to use it. There is no need to build
anything. Please read the README.md
file to understand how to use the
repository. Within each of the files, there is detailed documentation of each
and every function.
The repository has the following structure
FFD.jl
src
bounding_box.jl
b-splines.jl
control_point.jl
evaluations.jl
extra.jl
knot.jl
mapping_functions.jl
mapping.jl
param_functions.jl
plot.jl
span.jl
startup.j
l
test
runtest.jl
test_b-splines.jl
test_linearFFD.jl
README.md
The code was developed from the following references
- Les Piegl and Wayne Tiller. 1997. The NURBS Book (2nd Ed.). Springer-Verlag New York, Inc., New York, NY, USA.
- Carl de Boor. 1978. A Prcatical Guide to Splines. Springer-Verlag New York, Inc., New York, NY, USA.
- Thomas W. Sederberg and Scott R. Parry. 1986. Free-form deformation of solid geometric models. In Proceedings of the 13th annual conference on Computer graphics and interactive techniques (SIGGRAPH '86), David C. Evans and Russell J. Athay (Eds.). ACM, New York, NY, USA, 151-160. DOI=http://dx.doi.org/10.1145/15922.15903
- Prof. Hicken's Mapping_Mod.f90
- University of Michigan Free-form Deformation Toolbox
The file startup.jl
provides a sample method to call the functions within the
repository. There are two major composite types within the repository that needed
for FFD, viz. Mapping
and BoundingBox
.
Mapping
type essentially constructs a mapping object which not only creates the
mapping between the physical and parametric coordinate systems, but also store
the knot vectors, control points and other variables that are necessary for
construction of splines and FFD in general. Those details can be found in the
documentation. An important thing to note here is the notation of the physical
and parametric spaces. While the physical spaces is denoted by (x,y,z), the
parametric spaces are represented as follows:
- within the functions that compute B-spline basis functions, knot span index, B-spline curve points and B-spline volume points, the parametric coordinates are represented as (u,v,w) taken from Ref[1].
- The parametric coordinates are represented as (ξ,η,ζ) within the Mapping object. The notation is taken from Ref[4].
- Within the functions that compute the linear and non-linear mapping, the parametric coordinates are referred to as (s,t,u)
The intention of doing this presently is to ensure easy comprehension of the code if modifications needed referencing the literature. They may be changed in the future.
BoundingBox
type contains certain geometric information about the FFD volume
in which the a geometry is embedded. Its capabilities are restricted presently
and will grow as complicated FFD volumes are considered in the future.
Two types of mapping can be constructed between the physical and the parametric space, viz. linear mapping and nonlinear mapping. A linear mapping will suffice if the FFD volume considered is a regular parallelepiped. However, if the FFD volume is an irregular shape, a nonlinear mapping is required which performs a Newton's solve to obtain the parametric coordinates.
A sample step by step procedure for using FFD would be
# Import geometry
# Create Mapping Object
ndim = 3
order = [2,2,2] # Order of B-splines in the 3 directions
nControlPts = [3,3,3]
map = Mapping(ndim, order, nControlPts, nnodes)
# Create BoundingBox object
offset = [0.5,0.5,0.5] # offset for the bounding box
geom_bounds = [1. 1. 1.;3. 3. 3.]
box = BoundingBox(ndim, geom_bounds, offset)
calcKnot(map) # Create knot vectors
controlPoint(map,box) # Create Control Points for FFD volume
# Create Linear or nonlinear mapping
if type_of_map == "linear"
calcParametricMappingLinear(map, box, embedded_geometry_node_coordinates)
else
calcParametricMappingNonlinear(map, box, embedded_geometry_node_coordinates)
end
# Array for storing the computed embedded geometry coordinates within the FFD volume
FFD_vol = zeros(embedded_geometry_node_coordinates)
# Manipulate Control points
# Function to evaluate the computed embedded geometry coordinates within the FFD volume
evalVolume(map, Vol)
## VOILA!!!
When using FFD with a Pumi mesh, an example usage is
mesh, sbp, opts = getTestMesh() # get mesh, sbp, options dictionary from somewhere
Tmsh = eltype(mesh.jac) # get the element type of the mesh arrays
# create the FFD around the specified surface
order = [3,3,3] # Order of B-splines in the 3 directions
nControlPts = [6,6,6]
offset = [0.25, 0.25, 0.25]
bc_nums = [1] # envelop the surface that boundary condition 1 is applied
# to in the FFD volume
map, box = initializeFFD(mesh, sbp, order, nControlPts, offset,
bc_nums)
# evaluate surface point locations
vertices_orig = zeros(Tmsh, mesh.dim, map.numFacePts)
evalSurface(map, vertices_orig)
cp_xyz = zeros(Float64, 3, map.nctl[1], map.nct[2], map.nctl[3])
# change control points locations
cp_xyz[1,:,:,:] += 0.1
cp_xyz[2,:,:,:] += 0.2
cp_xyz[3,:,:,:] += 0.3
setControlPoints(map, cp_xyz)
# get updated coordinates
vertices_new = zeros(Tmsh, mesh.dim, map.numFacePts)
evalSurface(map, vertices_new)
# get control point values
cp_xyz2 = zeros(cp_xyz)
getControlPoints(map, cp_xyz2)
# cp_xyz2 == cp_xyz
# compute the Jacobian-vector product with a random vector
Xcp_dot = rand(map.cp_xyz)
Xs_dot = zeros(vertices_new)
evaldXdControlPointProduct(map, Xcp_dot, Xs_dot)
# Xs_dot now contains the result
# evaluate the transposed Jacobian-vector product with a random vector
Xcp_bar = zeros(map.cp_xyz)
Xs_bar = rand(vertices_new)
evaldXdControlPointTransposeProduct(map, Xs_bar, Xcp_bar)
# Xcp_bar now has contains the results
See the docstrings of these functions for more details.
- v0.1: before upgrading Julia 0.4 to Julia 0.6
- v0.2: after upgrading Julia 0.4 to Julia 0.6
- v0.4: update to PumiInterface v0.9