https://mooseframework.inl.gov
Functions
SplineUtils Namespace Reference

Utilities useful for splines in general Reference for B-Spline implementation: https://mat.fsv.cvut.cz/gcg/sbornik/prochazkova.pdf. More...

Functions

std::vector< Point > circularControlPoints (const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &parallel_direction, const unsigned int num_cps)
 Creates control points for the special case of parallel lines using an interpolating circle. More...
 
std::vector< Point > bSplineControlPoints (const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &start_direction, const libMesh::RealVectorValue &end_direction, const unsigned int cps_per_half, const libMesh::Real sharpness)
 Creates control points for an open uniform BSpline. More...
 
std::vector< Point > controlPointsAlongLine (const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &direction_vector, const libMesh::Real sharpness, const unsigned int num_cps, const bool reverse_order=false)
 Creates control points along an extrapolated line up to a certain intercept. More...
 
libMesh::Point makeControlPoint (const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &direction_vector, const libMesh::Real sharpness)
 Creates a control point. More...
 
std::pair< Point, Point > closestPoints (const libMesh::Point &point_1, const libMesh::Point &point_2, const libMesh::RealVectorValue &direction_1, const libMesh::RealVectorValue &direction_2)
 Determines the two points defining the shortest line segment between two lines in space. More...
 

Detailed Description

Utilities useful for splines in general Reference for B-Spline implementation: https://mat.fsv.cvut.cz/gcg/sbornik/prochazkova.pdf.

Function Documentation

◆ bSplineControlPoints()

std::vector< Point > SplineUtils::bSplineControlPoints ( const libMesh::Point start_point,
const libMesh::Point end_point,
const libMesh::RealVectorValue start_direction,
const libMesh::RealVectorValue end_direction,
const unsigned int  cps_per_half,
const libMesh::Real  sharpness 
)

Creates control points for an open uniform BSpline.

Parameters
start_pointstart point for spline
end_pointend point for spline
start_directionincoming direction (derivative)
end_directionoutgoing direction (derivative)
cps_per_halfnumber of control points per half of the spline – will be along extrapolated line from the point and its direction
sharpnessnumber in [0,1] that determines the sharpness of the curve

Definition at line 67 of file SplineUtils.C.

Referenced by Moose::BSpline::createControlPoints(), and BSplineCurveGenerator::generate().

73 {
74  // check that start_point is different from end_point
75  if ((start_point - end_point).norm_sq() < libMesh::TOLERANCE * libMesh::TOLERANCE)
76  mooseError("Start and end points must be different.");
77  // check that neither direction is the zero vector
78  if (start_direction.norm_sq() < libMesh::TOLERANCE * libMesh::TOLERANCE ||
79  end_direction.norm_sq() < libMesh::TOLERANCE * libMesh::TOLERANCE)
80  mooseError("Direction vectors must have a nonzero magnitude.");
81  mooseAssert(sharpness <= 1.0 && sharpness >= 0, "Sharpness must be in [0,1]!");
82 
83  // check if directions are parallel, use a special case if so
84  const bool parallel = ((start_direction.cross(end_direction)).norm() < libMesh::TOLERANCE);
85  if (parallel)
86  {
87  // We should not revert to a circle for this case
88  if (MooseUtils::absoluteFuzzyEqual(start_direction.unit(), -end_direction.unit()))
89  mooseError("Start and end directions are opposite, this is not currently supported");
90  mooseWarning("Directions are parallel! Attempting to use circular control points...");
91  unsigned int num_cps = 2 * cps_per_half + 1;
92  if (num_cps < 30)
93  mooseWarning("Number of control points required for circular control points is much greater "
94  "than for BSplines. Current num_cps: " +
95  std::to_string(num_cps));
96  return SplineUtils::circularControlPoints(start_point, end_point, start_direction, num_cps);
97  }
98 
99  // find closest points --> these will be identical if the extrapolated lines intersect
100  const auto closest_points_vector =
101  SplineUtils::closestPoints(start_point, end_point, start_direction, end_direction);
102  const auto & closest_point_1 = closest_points_vector.first;
103  const auto & closest_point_2 = closest_points_vector.second;
104 
105  std::vector<Point> first_half = SplineUtils::controlPointsAlongLine(
106  start_point, closest_point_1, start_direction, sharpness, cps_per_half);
107  std::vector<Point> second_half = SplineUtils::controlPointsAlongLine(
108  end_point, closest_point_2, end_direction, sharpness, cps_per_half, true);
109 
110  std::vector<Point> control_points;
111 
112  // put it all together
113  for (const auto i : index_range(first_half))
114  control_points.push_back(first_half[i]);
115  for (const auto i : index_range(second_half))
116  control_points.push_back(second_half[i]);
117 
118  return control_points;
119 }
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
auto norm_sq(const T &a)
static constexpr Real TOLERANCE
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:345
std::vector< Point > controlPointsAlongLine(const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &direction_vector, const libMesh::Real sharpness, const unsigned int num_cps, const bool reverse_order=false)
Creates control points along an extrapolated line up to a certain intercept.
Definition: SplineUtils.C:122
TypeVector< Real > unit() const
auto norm_sq() const
std::pair< Point, Point > closestPoints(const libMesh::Point &point_1, const libMesh::Point &point_2, const libMesh::RealVectorValue &direction_1, const libMesh::RealVectorValue &direction_2)
Determines the two points defining the shortest line segment between two lines in space...
Definition: SplineUtils.C:184
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
auto norm(const T &a)
std::vector< Point > circularControlPoints(const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &parallel_direction, const unsigned int num_cps)
Creates control points for the special case of parallel lines using an interpolating circle...
Definition: SplineUtils.C:19
auto index_range(const T &sizable)

◆ circularControlPoints()

std::vector< Point > SplineUtils::circularControlPoints ( const libMesh::Point start_point,
const libMesh::Point end_point,
const libMesh::RealVectorValue parallel_direction,
const unsigned int  num_cps 
)

Creates control points for the special case of parallel lines using an interpolating circle.

Parameters
start_pointstart point for spline
end_pointend point for spline
parallel_directiondirection of both curves to be connected. must be the same for both
num_cpstotal number of control points to be created

Definition at line 19 of file SplineUtils.C.

Referenced by bSplineControlPoints().

23 {
24  // establish the direction vector between the two points
25  const auto orthogonal_direction = start_point - end_point;
26 
27  // circular control points will only honor the derivatives if the points are colinear along the
28  // orthogonal direction
29  if (!(MooseUtils::absoluteFuzzyEqual(parallel_direction.unit() * orthogonal_direction.unit(), 0)))
30  mooseError("Parallel lines cannot be interpolated using points along a circle! Direction "
31  "vectors are incompatible with point locations.\nStart point: ",
32  start_point,
33  "\nEnd point: ",
34  end_point,
35  "\nDirection: ",
36  parallel_direction);
37 
38  // define the distance between the two points
39  const auto distance_between = orthogonal_direction.norm();
40 
41  // connecting circle is assumed to be between each point along the orthogonal_direction vector
42  const auto radius = distance_between / 2.0;
43 
44  // normalize vectors
45  const auto unit_normal = orthogonal_direction / distance_between;
46  const auto unit_parallel = parallel_direction / parallel_direction.norm();
47 
48  // calculate circle center
49  const auto center_point = end_point + radius * unit_normal;
50 
51  // initialize vector of control points
52  std::vector<Point> control_points;
53 
54  // loop over the number of control points to generate the control points
55  mooseAssert(num_cps > 1, "This routine does not support a single control point");
56  for (const auto i : make_range(num_cps))
57  {
58  const auto t = (Real)i / (Real)(num_cps - 1);
59  control_points.push_back(center_point + radius * (std::cos(t * M_PI) * unit_normal +
60  std::sin(t * M_PI) * unit_parallel));
61  }
62 
63  return control_points;
64 }
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
const Real radius
auto norm() const
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
TypeVector< Real > unit() const
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)

◆ closestPoints()

std::pair< Point, Point > SplineUtils::closestPoints ( const libMesh::Point point_1,
const libMesh::Point point_2,
const libMesh::RealVectorValue direction_1,
const libMesh::RealVectorValue direction_2 
)

Determines the two points defining the shortest line segment between two lines in space.

If the lines intersect, the two points returned will be identical.

Parameters
point_1starting point of the first line
point_2starting point of the second line
direction_1direction of the first line
direction_2direction of the second line

Definition at line 184 of file SplineUtils.C.

Referenced by bSplineControlPoints().

188 {
189  const auto n_vec = direction_1.cross(direction_2);
190 
191  // check if n_vec is the zero vector (indicates parallel lines)
192  if (n_vec.norm_sq() < libMesh::TOLERANCE * libMesh::TOLERANCE)
193  mooseError("Lines are parallel! Infinitely many closest points exist.");
194 
195  const auto n1_vec = direction_1.cross(n_vec);
196  const auto n2_vec = direction_2.cross(n_vec);
197 
198  // calculate closest points
199  // take absolute value to ensure specified directions are honored
200  libMesh::Real point_a_dir_scalar =
201  std::abs((point_2 - point_1) * n2_vec / (direction_1 * n2_vec));
202  libMesh::Real point_b_dir_scalar =
203  std::abs((point_1 - point_2) * n1_vec / (direction_2 * n1_vec));
204  libMesh::Point point_a = point_1 + point_a_dir_scalar * direction_1;
205  libMesh::Point point_b = point_2 + point_b_dir_scalar * direction_2;
206 
207  // points will be returned as a vector containing two points
208  const auto closest_points = std::make_pair(point_a, point_b);
209 
210  return closest_points;
211 }
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Definition: EigenADReal.h:50
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
static constexpr Real TOLERANCE
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ controlPointsAlongLine()

std::vector< Point > SplineUtils::controlPointsAlongLine ( const libMesh::Point start_point,
const libMesh::Point end_point,
const libMesh::RealVectorValue direction_vector,
const libMesh::Real  sharpness,
const unsigned int  num_cps,
const bool  reverse_order = false 
)

Creates control points along an extrapolated line up to a certain intercept.

Parameters
start_pointstart point for the line
end_pointend point of the line
direction_vectordirection of the line
sharpnessnumber in [0,1] that determines the sharpness of the future curve. In this context, it will determine how close to the end point the control points are placed.
reverse_orderboolean to return the vector of control points in the reverse order

Definition at line 122 of file SplineUtils.C.

Referenced by bSplineControlPoints().

128 {
129  // initialize a vector of control points with the starting point inserted
130  std::vector<Point> control_points;
131 
132  mooseAssert(num_cps != 0, "Number of control points cannot be zero!");
133  if (num_cps == 1)
134  control_points.push_back(start_point);
135 
136  // create the control points by varying the sharpness linearly
137  else
138  {
139  for (const auto i : libMesh::make_range(num_cps))
140  {
141  const auto point_sharpness = (Real)i / (Real)(num_cps - 1) * sharpness;
142  control_points.push_back(
143  SplineUtils::makeControlPoint(start_point, end_point, direction_vector, point_sharpness));
144  }
145 
146  // reverse_order parameter only set to true when required
147  if (reverse_order)
148  std::reverse(control_points.begin(), control_points.end());
149  }
150  return control_points;
151 }
libMesh::Point makeControlPoint(const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &direction_vector, const libMesh::Real sharpness)
Creates a control point.
Definition: SplineUtils.C:154
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)

◆ makeControlPoint()

libMesh::Point SplineUtils::makeControlPoint ( const libMesh::Point start_point,
const libMesh::Point end_point,
const libMesh::RealVectorValue direction_vector,
const libMesh::Real  sharpness 
)

Creates a control point.

Subroutine of controlPointsAlongLine

Parameters
start_pointstart point for the line
end_pointend point of the line
direction_vectordirection of the line
sharpnessnumber in [0,1] that determines the sharpness of the future curve. In this context, it will determine how close to the end point the control point is placed.

Definition at line 154 of file SplineUtils.C.

Referenced by controlPointsAlongLine().

158 {
159  // check that sharpness value is ok
160  mooseAssert(sharpness <= 1.0 && sharpness >= 0, "Sharpness must be in [0,1]!");
161 
162  // normalize direction vector
163  const auto unit_direction = direction_vector.unit();
164 
165  // calculate the distance between points
166  const auto distance = (end_point - start_point).norm();
167  const auto distance_sq = distance * distance;
168 
169  // initialize return quantity and attempt to calculate control vector
170  libMesh::Point control_point = start_point + sharpness * distance * unit_direction;
171 
172  // check if we went the wrong way, further from the end_point
173  if ((end_point - control_point).norm_sq() > distance_sq)
174  {
175  control_point = start_point - sharpness * distance * unit_direction;
176  mooseAssert((end_point - control_point).norm_sq() <= distance_sq,
177  "Also going further from end point");
178  }
179 
180  return control_point;
181 }
auto norm_sq(const T &a)
Real distance(const Point &p)
TypeVector< Real > unit() const
auto norm(const T &a)