Back

LineProjectiveConstraint

sofa::component::constraint::projective::LineProjectiveConstraint
ProjectiveConstraintSet
Doc (from source)

Attach given particles to their initial positions. Project particles to an affine straight line. @author Francois Faure, 2012 @todo Optimized versions for lines parallel to the main directions

Abstract (AI generated)

The `LineProjectiveConstraint` projects specified particles onto an affine straight line defined by its origin point and direction vector, ensuring their positions remain on the line throughout simulation.

Metadata
module
Sofa.Component.Constraint.Projective
namespace
sofa::component::constraint::projective
include
sofa/component/constraint/projective/LineProjectiveConstraint.h
inherits
  • ProjectiveConstraintSet
templates
  • sofa::defaulttype::Vec3Types
description

The LineProjectiveConstraint component in the SOFA framework projects specified particles onto an affine straight line defined by its origin point $\bar{o}$ and direction vector $\vec{n}$. The constraint is designed to enforce that each particle lies on this line. The projection process involves finding the closest point on the line from a given particle position $x_i$.

Mathematical Formulation

Projection of Particle Position

The position of a particle $i$ originally at $\mathbf{x}_i$ is projected onto the affine straight line defined by:
egin{equation}
L: \; \mathbf{x} = \bar{o} + t \vec{n},
\end{equation}
where $t$ is a scalar parameter.
The projection of $\mathbf{x}_i$ onto the line can be formulated as:
egin{equation}
\hat{ extbf{x}}_i = \bar{o} + (( extbf{x}_i - ar{o}) ullet rac{ extbf{n}}{
orm{ extbf{n}}} ) rac{ extbf{n}}{
orm{ extbf{n}}}.
ag{1}

d_i = ( extbf{x}_i - ar{o}) ullet rac{ extbf{n}}{
orm{ extbf{n}}} \
\hat{ extbf{x}}_i = \bar{o} + d_i rac{ extbf{n}}{
orm{ extbf{n}}}
ag{2}

d_i = ( extbf{x}_i - ar{o}) ullet extbf{n} \
\hat{ extbf{x}}_i = \bar{o} + d_i extbf{n}
ag{3}

d_i = (\mathbf{x}_i - ar{o}) ullet extbf{n} \
\hat{ extbf{x}}_i = ar{o} + d_i extbf{n},
ag{4}

d_i = ( extbf{x}_i - ar{o}) ullet rac{ extbf{n}}{
orm{ extbf{n}}} \
\hat{ extbf{x}}_i = \bar{o} + d_i rac{ extbf{n}}{
orm{ extbf{n}}},
ag{5}

d_i = ( extbf{x}_i - ar{o}) ullet rac{ extbf{n}}{
orm{ extbf{n}}} \
\hat{ extbf{x}}_i = \bar{o} + d_i rac{ extbf{n}}{
orm{ extbf{n}}}.
ag{6}

d_i = ( extbf{x}_i - ar{o}) ullet extbf{n}, \
\hat{ extbf{x}}_i = ar{o} + d_i extbf{n}.
ag{7}

d_i = (\mathbf{x}_i - \bar{o}) \cdot rac{ extbf{n}}{
orm{ extbf{n}}} \
\hat{ extbf{x}}_i = \bar{o} + d_i rac{ extbf{n}}{
orm{ extbf{n}}}.
ag{8}

In summary, the projection is done by finding the scalar parameter $d_i$ which gives the distance along the direction vector $ extbf{n}$ from the origin point $ar{o}$ to the closest point on the line. The projected position $ extbf{x}_i$ is then given by Equation (8).

Jacobian Matrix Construction

The constraint matrix encodes how the constrained variables are modified during projection. Specifically, for each particle that needs to be projected onto the line, a block of the matrix corresponding to that particle's degrees of freedom (DOFs) is set to the projection matrix $\mathbf{P} = extbf{n} extbf{n}^T$. This ensures that only motion along the direction vector $ extbf{n}$ remains unconstrained. For particles not constrained by this component, an identity block matrix is used.

The Jacobian matrix $J$ is constructed as follows:
egin{equation}
J = \left[egin{array}{ccccc}
P & 0 & \cdots & 0 \
0 & I & \ddots & \vdots \
\vdots & \ddots & \ddots & 0 \
0 & \cdots & 0 & I
\end{array}\right]
ag{9}
\end{equation}
where $P = \textbf{n} \textbf{n}^T$ for particles along the line and $I$ is the identity matrix for unconstrained particles.

Role in FEM Pipeline

  • Assembly: During assembly, this component modifies the global Jacobian of the system by inserting projection matrices or identity blocks as described above. The projectMatrix method ensures that the assembled system matrix is correctly updated with these constraints.
  • Time Integration: This constraint affects the dynamics during time integration by enforcing positions and velocities to remain on the line. Methods such as projectPosition, projectVelocity, and projectResponse ensure this enforcement for position, velocity, and force responses respectively.
  • Nonlinear Solution: Although the projection process is linear in nature due to the affine line constraint, it must be considered during nonlinear solves if other constraints or forces are present. The Jacobian matrix $J$ participates in these solves by constraining specific degrees of freedom.
  • Linear Solve: During each iteration of the Newton-Raphson method for solving nonlinear systems, this component ensures that the constrained particles maintain their projection onto the line through modification of the residual and linear system matrices.

Numerical Methods

The LineProjectiveConstraint uses a sparse matrix representation to efficiently store and manipulate the Jacobian. The updateJacobian method normalizes the direction vector $ extbf{n}$, computes the projection blocks $\mathbf{P} = extbf{n} extbf{n}^T$, and inserts them into the sparse Jacobian matrix at appropriate indices corresponding to constrained particles.

Variational / Lagrangian Mechanics Framework

In the broader variational mechanics framework, this component enforces holonomic constraints (position-based constraints) on specific degrees of freedom. By projecting particles onto a line, it ensures that their motion remains consistent with the specified affine constraint while allowing unconstrained motions along the direction vector $ extbf{n}$. The projection process can be viewed as minimizing the squared distance between each particle and its closest point on the line, which is a form of constrained optimization.

Data Fields
NameTypeDefaultHelp
d_drawSize SReal Size of the rendered particles (0 -> point based rendering, >0 -> radius of spheres)
d_origin CPos A point in the line
d_direction CPos Direction of the line
Links
NameTypeHelp
l_topology link to the topology container
Methods
void clearConstraints ()
void addConstraint (int index)
void removeConstraint (int index)
void init ()
void reinit ()
void projectResponse (const core::MechanicalParams * mparams, DataVecDeriv & resData)
void projectVelocity (const core::MechanicalParams * mparams, DataVecDeriv & vData)
void projectPosition (const core::MechanicalParams * mparams, DataVecCoord & xData)
void projectJacobianMatrix (const core::MechanicalParams * mparams, DataMatrixDeriv & cData)
void applyConstraint (const core::MechanicalParams * mparams, const sofa::core::behavior::MultiMatrixAccessor * matrix)
void applyConstraint (const core::MechanicalParams * mparams, linearalgebra::BaseVector * vector, const sofa::core::behavior::MultiMatrixAccessor * matrix)
void projectMatrix (sofa::linearalgebra::BaseMatrix * , unsigned int )
void draw (const core::visual::VisualParams * vparams)
void updateJacobian ()
{
  "name": "LineProjectiveConstraint",
  "namespace": "sofa::component::constraint::projective",
  "module": "Sofa.Component.Constraint.Projective",
  "include": "sofa/component/constraint/projective/LineProjectiveConstraint.h",
  "doc": "Attach given particles to their initial positions.\n\nProject particles to an affine straight line.\n  @author Francois Faure, 2012\n  @todo Optimized versions for lines parallel to the main directions",
  "inherits": [
    "ProjectiveConstraintSet"
  ],
  "templates": [
    "sofa::defaulttype::Vec3Types"
  ],
  "data_fields": [
    {
      "name": "d_drawSize",
      "type": "SReal",
      "xmlname": "drawSize",
      "help": "Size of the rendered particles (0 -> point based rendering, >0 -> radius of spheres)"
    },
    {
      "name": "d_origin",
      "type": "CPos",
      "xmlname": "origin",
      "help": "A point in the line"
    },
    {
      "name": "d_direction",
      "type": "CPos",
      "xmlname": "direction",
      "help": "Direction of the line"
    }
  ],
  "links": [
    {
      "name": "l_topology",
      "target": "BaseMeshTopology",
      "kind": "single",
      "xmlname": "topology",
      "help": "link to the topology container"
    }
  ],
  "methods": [
    {
      "name": "clearConstraints",
      "return_type": "void",
      "params": [],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "addConstraint",
      "return_type": "void",
      "params": [
        {
          "name": "index",
          "type": "int"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "removeConstraint",
      "return_type": "void",
      "params": [
        {
          "name": "index",
          "type": "int"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "init",
      "return_type": "void",
      "params": [],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "reinit",
      "return_type": "void",
      "params": [],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "projectResponse",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "resData",
          "type": "DataVecDeriv &"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "projectVelocity",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "vData",
          "type": "DataVecDeriv &"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "projectPosition",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "xData",
          "type": "DataVecCoord &"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "projectJacobianMatrix",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "cData",
          "type": "DataMatrixDeriv &"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "applyConstraint",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "matrix",
          "type": "const sofa::core::behavior::MultiMatrixAccessor *"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "applyConstraint",
      "return_type": "void",
      "params": [
        {
          "name": "mparams",
          "type": "const core::MechanicalParams *"
        },
        {
          "name": "vector",
          "type": "linearalgebra::BaseVector *"
        },
        {
          "name": "matrix",
          "type": "const sofa::core::behavior::MultiMatrixAccessor *"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "projectMatrix",
      "return_type": "void",
      "params": [
        {
          "name": "",
          "type": "sofa::linearalgebra::BaseMatrix *"
        },
        {
          "name": "",
          "type": "unsigned int"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "draw",
      "return_type": "void",
      "params": [
        {
          "name": "vparams",
          "type": "const core::visual::VisualParams *"
        }
      ],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "public"
    },
    {
      "name": "updateJacobian",
      "return_type": "void",
      "params": [],
      "is_virtual": false,
      "is_pure_virtual": false,
      "is_static": false,
      "access": "protected"
    }
  ],
  "description": "This component projects specified particles onto a line defined by an origin point and direction vector.",
  "parameters": [
    {
      "name": "drawSize",
      "type": "float",
      "description": "Size used for drawing the constrained points as spheres. If set to 0, points are drawn instead of spheres."
    },
    {
      "name": "indices",
      "type": "list of indices",
      "description": "List of particle indices that will be projected onto the line."
    },
    {
      "name": "direction",
      "type": "3D vector",
      "description": "Direction vector defining the orientation of the line. This vector is normalized internally to ensure it represents a unit direction."
    },
    {
      "name": "origin",
      "type": "3D point",
      "description": "Origin point on the line."
    }
  ],
  "inputSlots": [
    {
      "name": "indices",
      "type": "list of indices",
      "description": "Indices of particles that will be projected onto the specified line. These indices must correspond to valid particle IDs within the mechanical state they are applied to."
    },
    {
      "name": "direction",
      "type": "3D vector",
      "description": "Directional vector for the line onto which the particles will be projected. The component normalizes this vector internally, so it can accept any non-zero length vector."
    },
    {
      "name": "origin",
      "type": "3D point",
      "description": "The origin point on the line. Together with the direction vector, this fully defines the line in 3D space onto which particles will be projected."
    }
  ],
  "outputSlots": [
    {
      "name": "projectedPositions",
      "type": "list of positions",
      "description": "List of new positions for each particle after projection to the line defined by origin and direction. This is an internal state and not directly exposed as a slot output, but it affects the mechanical behavior of the particles in the simulation."
    }
  ],
  "notes": [
    {
      "text": "The LineProjectiveConstraint component supports topological changes by linking with a topology container, ensuring that its indices are updated accordingly if the underlying mesh topology is modified (e.g., through remeshing)."
    },
    {
      "text": "This constraint does not apply any force to keep particles on the line; instead, it directly modifies their positions at each simulation step. This makes it more of a projection tool than a traditional constraint that enforces behavior via forces."
    }
  ],
  "examples": [
    {
      "description": "Project particles with indices 0 and 1 onto a vertical line passing through the point (0,5,0).",
      "example": "LineProjectiveConstraint {\n    indices='0 1'\n    origin='0 5 0'\n    direction='0 1 0'\n}"
    }
  ],
  "maths": "The `LineProjectiveConstraint` component in the SOFA framework projects specified particles onto an affine straight line defined by its origin point $\\bar{o}$ and direction vector $\\vec{n}$. The constraint is designed to enforce that each particle lies on this line. The projection process involves finding the closest point on the line from a given particle position $x_i$.\n\n### Mathematical Formulation\n\n#### Projection of Particle Position\nThe position of a particle $i$ originally at $\\mathbf{x}_i$ is projected onto the affine straight line defined by:\n\begin{equation}\nL: \\; \\mathbf{x} = \\bar{o} + t \\vec{n}, \n\\end{equation}\nwhere $t$ is a scalar parameter.\nThe projection of $\\mathbf{x}_i$ onto the line can be formulated as:\n\begin{equation}\n\\hat{\textbf{x}}_i = \\bar{o} + ((\textbf{x}_i - \bar{o}) \bullet \frac{\textbf{n}}{\norm{\textbf{n}}} ) \frac{\textbf{n}}{\norm{\textbf{n}}}.\n\tag{1}\n\nd_i = (\textbf{x}_i - \bar{o}) \bullet \frac{\textbf{n}}{\norm{\textbf{n}}} \\\n\\hat{\textbf{x}}_i = \\bar{o} + d_i \frac{\textbf{n}}{\norm{\textbf{n}}}\n\tag{2}\n\nd_i = (\textbf{x}_i - \bar{o}) \bullet \textbf{n} \\\n\\hat{\textbf{x}}_i = \\bar{o} + d_i \textbf{n}\n\tag{3}\n\nd_i = (\\mathbf{x}_i - \bar{o}) \bullet \textbf{n} \\\n\\hat{\textbf{x}}_i = \bar{o} + d_i \textbf{n},\n\tag{4}\n\nd_i = (\textbf{x}_i - \bar{o}) \bullet \frac{\textbf{n}}{\norm{\textbf{n}}} \\\n\\hat{\textbf{x}}_i = \\bar{o} + d_i \frac{\textbf{n}}{\norm{\textbf{n}}},\n\tag{5}\n\nd_i = (\textbf{x}_i - \bar{o}) \bullet \frac{\textbf{n}}{\norm{\textbf{n}}} \\\n\\hat{\textbf{x}}_i = \\bar{o} + d_i \frac{\textbf{n}}{\norm{\textbf{n}}}.\n\tag{6}\n\nd_i = (\textbf{x}_i - \bar{o}) \bullet \textbf{n}, \\\n\\hat{\textbf{x}}_i = \bar{o} + d_i \textbf{n}.\n\tag{7}\n\nd_i = (\\mathbf{x}_i - \\bar{o}) \\cdot \frac{\textbf{n}}{\norm{\textbf{n}}} \\\n\\hat{\textbf{x}}_i = \\bar{o} + d_i \frac{\textbf{n}}{\norm{\textbf{n}}}.\n\tag{8}\n\nIn summary, the projection is done by finding the scalar parameter $d_i$ which gives the distance along the direction vector $\textbf{n}$ from the origin point $\bar{o}$ to the closest point on the line. The projected position $\textbf{x}_i$ is then given by Equation (8).\n\n#### Jacobian Matrix Construction\nThe constraint matrix encodes how the constrained variables are modified during projection. Specifically, for each particle that needs to be projected onto the line, a block of the matrix corresponding to that particle's degrees of freedom (DOFs) is set to the projection matrix $\\mathbf{P} = \textbf{n}\textbf{n}^T$. This ensures that only motion along the direction vector $\textbf{n}$ remains unconstrained. For particles not constrained by this component, an identity block matrix is used.\n\nThe Jacobian matrix $J$ is constructed as follows:\n\begin{equation}\n    J = \\left[\begin{array}{ccccc}\n      P & 0 & \\cdots & 0 \\\\\n      0 & I & \\ddots & \\vdots \\\\\n      \\vdots & \\ddots & \\ddots & 0 \\\\\n      0 & \\cdots & 0 & I\n    \\end{array}\\right]\n\tag{9}\n\\end{equation}\nwhere $P = \\textbf{n} \\textbf{n}^T$ for particles along the line and $I$ is the identity matrix for unconstrained particles.\n\n### Role in FEM Pipeline\n- **Assembly**: During assembly, this component modifies the global Jacobian of the system by inserting projection matrices or identity blocks as described above. The `projectMatrix` method ensures that the assembled system matrix is correctly updated with these constraints.\n- **Time Integration**: This constraint affects the dynamics during time integration by enforcing positions and velocities to remain on the line. Methods such as `projectPosition`, `projectVelocity`, and `projectResponse` ensure this enforcement for position, velocity, and force responses respectively.\n- **Nonlinear Solution**: Although the projection process is linear in nature due to the affine line constraint, it must be considered during nonlinear solves if other constraints or forces are present. The Jacobian matrix $J$ participates in these solves by constraining specific degrees of freedom.\n- **Linear Solve**: During each iteration of the Newton-Raphson method for solving nonlinear systems, this component ensures that the constrained particles maintain their projection onto the line through modification of the residual and linear system matrices.\n\n### Numerical Methods\nThe `LineProjectiveConstraint` uses a sparse matrix representation to efficiently store and manipulate the Jacobian. The `updateJacobian` method normalizes the direction vector $\textbf{n}$, computes the projection blocks $\\mathbf{P} = \textbf{n}\textbf{n}^T$, and inserts them into the sparse Jacobian matrix at appropriate indices corresponding to constrained particles.\n\n### Variational / Lagrangian Mechanics Framework\nIn the broader variational mechanics framework, this component enforces holonomic constraints (position-based constraints) on specific degrees of freedom. By projecting particles onto a line, it ensures that their motion remains consistent with the specified affine constraint while allowing unconstrained motions along the direction vector $\textbf{n}$. The projection process can be viewed as minimizing the squared distance between each particle and its closest point on the line, which is a form of constrained optimization.",
  "abstract": "The `LineProjectiveConstraint` projects specified particles onto an affine straight line defined by its origin point and direction vector, ensuring their positions remain on the line throughout simulation.",
  "sheet": "# LineProjectiveConstraint\n\n**Overview**\n\nThe `LineProjectiveConstraint` component in SOFA projects specified particles onto an affine straight line defined by its origin point $\\bar{o}$ and direction vector $\\vec{n}$. It inherits from `ProjectiveConstraintSet`, indicating it is part of a larger constraint system. This component ensures that each particle's position remains on the line throughout simulation.\n\n**Mathematical Model**\n\nThe projection process involves finding the closest point on the line from a given particle position $\\mathbf{x}_i$. The affine straight line is defined by:\n\n\\[ L: \\; \\mathbf{x} = \\bar{o} + t \\vec{n}, \\]\nwhere $t$ is a scalar parameter. The projection of $\\mathbf{x}_i$ onto the line can be formulated as:\n\n\\begin{align*}\nd_i &= (\\mathbf{x}_i - \\bar{o}) \\cdot \\frac{\\vec{n}}{\\|\\vec{n}\\|} \\\\\n\\hat{\\mathbf{x}}_i &= \\bar{o} + d_i \\frac{\\vec{n}}{\\|\\vec{n}\\|},\n\\end{align*}\nwhere $d_i$ is the distance along the direction vector from the origin point to the closest point on the line.\n\n**Parameters and Data**\n\n- **drawSize**: Size of the rendered particles (0 -> point based rendering, >0 -> radius of spheres).\n- **origin**: A point in the line $\\bar{o}$.\n- **direction**: Direction of the line $\\vec{n}$.\n\n**Dependencies and Connections**\n\nThis component requires a link to the topology container (`BaseMeshTopology`) for accessing particle positions. It fits into the scene graph as part of the constraint system, ensuring that particles remain on the specified affine straight line throughout simulation.\n\n**Practical Notes**\n\nThe direction vector $\\vec{n}$ should be normalized before use in projection calculations to ensure accurate results. The `updateJacobian` method normalizes the direction vector and computes the projection blocks for insertion into the sparse Jacobian matrix."
}