Back

BilateralLagrangianConstraint

This component represents a bilateral holonomic constraint that defines an equality relationship between two points or rigid bodies in the simulation.

abstract
The `BilateralLagrangianConstraint` enforces an equality relationship between two points or rigid bodies, ensuring that their relative positions and orientations remain constant throughout the simulation.
sheet
# BilateralLagrangianConstraint ## Overview The `BilateralLagrangianConstraint` is a component in the SOFA framework that defines an equality constraint (attachment) between two points or rigid bodies. It inherits from `PairInteractionConstraint`, and it requires links to two topology containers (`topology1` and `topology2`). ## Mathematical Model The bilateral holonomic constraint enforces an equality relationship between the positions and orientations of two points or rigid bodies. The constraint function is defined as: \[ \mathbf{h}(\mathbf{q}) = \mathbf{p}_1(\mathbf{q}) - \mathbf{p}_2(\mathbf{q}) = 0, \] where $\mathbf{p}_i$ are the positions of the points or rigid bodies, and $\mathbf{q}$ represents the generalized coordinates. The constraint Jacobian matrix is given by: \[ \mathbf{J} = \frac{\partial \mathbf{h}}{\partial \mathbf{q}}, \] which relates changes in the generalized coordinates to changes in the constraints. The constraint violation $\mathbf{v}$ is calculated as: \[ \mathbf{v} = \mathbf{p}_2 - \mathbf{p}_1, \] and the constraint force $\boldsymbol{\lambda}$, introduced as a Lagrange multiplier, enforces the equality constraints through the equation: \[ \mathbf{J}^T \boldsymbol{\lambda} = -\mathbf{M}^{-1} (\mathbf{h}(\mathbf{q}) + \dot{\mathbf{h}}(\mathbf{q})), \] where $\mathbf{M}$ is the mass matrix of the system. ## Parameters and Data - **rest_vector**: Relative position to maintain between attached points (optional). - Type: `VecDeriv` - XML Name: `rest_vector` - **activate**: Control constraint activation (true by default). - Type: `bool` - XML Name: `activate` - **keepOrientationDifference**: Keep the initial difference in orientation (only for rigids). - Type: `bool` - XML Name: `keepOrientationDifference` - **load**: Apply this factor to the constraint force to enable incremental loading. This value should be in the interval [0.0, 1.0]. - Type: `SReal` - XML Name: `load` ## Dependencies and Connections The component requires links to two topology containers (`topology1` and `topology2`). It fits into the scene graph by enforcing constraints between these topologies, ensuring that their relative positions and orientations remain constant throughout the simulation.
name
BilateralLagrangianConstraint
description
This component represents a bilateral holonomic constraint that defines an equality relationship between two points or rigid bodies in the simulation.
parameters
  • {'name': 'keepOrientDiff', 'type': 'bool', 'default_value': '', 'description': 'If true, keeps the orientation difference between connected objects.'}
  • {'name': 'm1', 'type': 'vector<int>', 'default_value': '', 'description': 'Indices of points/rigid bodies in the first set to constrain.'}
  • {'name': 'm2', 'type': 'vector<int>', 'default_value': '', 'description': 'Indices of points/rigid bodies in the second set to constrain.'}
  • {'name': 'restVector', 'type': 'vector<Deriv>', 'default_value': '', 'description': 'Rest positions or orientations for constrained points/rigid bodies.'}
methods
  • {'name': 'init()', 'description': 'Initializes the constraint component and its parameters.'}
  • {'name': 'bwdInit()', 'description': 'Performs any necessary backward initialization, particularly handling orientation differences if specified by keepOrientDiff.'}
  • {'name': 'getConstraintResolution(ConstraintParams* cParams, std::vector<ConstraintResolution*>& resTab, unsigned int& offset)', 'description': 'Gets the constraint resolution strategy for bilateral constraints.'}
  • {'name': 'buildConstraintMatrix(const ConstraintParams* cParams, DataMatrixDeriv &c1_d, DataMatrixDeriv &c2_d, unsigned int &constraintId, const DataVecCoord &x1, const DataVecCoord &x2)', 'description': 'Builds the constraint matrix for bilateral constraints between two sets of points or rigid bodies.'}
  • {'name': 'getConstraintViolation(const ConstraintParams* cParams, BaseVector *v, const DataVecCoord &d_x1, const DataVecCoord &d_x2, const DataVecDeriv &v1, const DataVecDeriv &v2)', 'description': 'Computes the current constraint violation for each constrained point or rigid body.'}
  • {'name': 'addContact(Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id, PersistentID localid)', 'description': 'Adds a new contact constraint between two points or rigid bodies and updates the rest positions/orientations accordingly.'}
example_use_case
This component can be used to create attachments or constraints between different parts of a deformable object simulation. For example, it could be used to ensure that certain vertices on a cloth model remain attached to specific points on a rigid body, maintaining their relative positions and orientations throughout the simulation.
notes
The BilateralLagrangianConstraint component is designed to work with both Vec3 (vector) types for point-based constraints as well as Rigid3Types for constraints involving rigid bodies. It can enforce equality relationships in position or orientation between specified points or rigid bodies within a simulation, making it useful for creating complex mechanical systems where certain components must remain connected.
maths
## Bilateral Holonomic Constraint The `BilateralLagrangianConstraint` in the SOFA framework defines an equality constraint between two points or rigid bodies. This type of constraint ensures that certain physical quantities remain equal over time, thus creating a direct relationship between the degrees of freedom (DOFs) of the connected entities. ### Mathematical Formulation For simplicity, let's denote the positions of two points as $\mathbf{p}_1$ and $\mathbf{p}_2$, where $\mathbf{p}_i \in \mathbb{R}^3$. The equality constraint can be expressed in the following form: $$ \mathbf{h}(\mathbf{q}) = \mathbf{p}_1(\mathbf{q}) - \mathbf{p}_2(\mathbf{q}) = 0, $$ where $\mathbf{q}$ represents the generalized coordinates of the system, and $\mathbf{h}(\cdot)$ is a constraint function that enforces the equality between the two points. This can be extended to rigid bodies where $\mathbf{p}_1$ and $\mathbf{p}_2$ are not just positions but also orientations represented by quaternions. ### Constraint Jacobian The constraint Jacobian matrix, denoted as $\mathbf{J}$, is used to express the relationship between changes in the generalized coordinates ($\Delta \mathbf{q}$) and changes in the constraints ($\Delta \mathbf{h}(\mathbf{q})$): $$ \mathbf{J} = \frac{\partial \mathbf{h}}{\partial \mathbf{q}}, $$ The constraint Jacobian matrix can be derived as follows: For points in 3D space, the Jacobian is a $6 \times N$ matrix where each row represents one of the 6 constraints (three for position and three for orientation). For example, if we have two rigid bodies connected by this constraint, the Jacobian would look like: $$ \mathbf{J} = \begin{bmatrix} \frac{\partial h_x}{\partial q_1} & \cdots & \frac{\partial h_x}{\partial q_N} \\ \vdots & \ddots & \vdots \\ \frac{\partial h_z}{\partial q_1} & \cdots & \frac{\partial h_z}{\partial q_N} \end{bmatrix}, $$ where $h_x, h_y, h_z$ are the position components of the constraint function. ### Constraint Violation The constraint violation $\mathbf{v}$ is calculated as: $$ \mathbf{v} = \mathbf{p}_2 - \mathbf{p}_1, $$ For rigid bodies, the position and orientation components need to be considered separately. The orientation difference can be computed using a quaternion representation of rotation. ### Constraint Force The constraint force $\boldsymbol{\lambda}$ is introduced as a Lagrange multiplier that enforces the equality constraints: $$ \mathbf{J}^T \boldsymbol{\lambda} = -\mathbf{M}^{-1} (\mathbf{h}(\mathbf{q}) + \dot{\mathbf{h}}(\mathbf{q})), $$ where $\mathbf{M}$ is the mass matrix of the system and $\boldsymbol{\lambda}$ is a vector of Lagrange multipliers. The constraint force ensures that the constraints are satisfied at each time step. ### Constraint Resolution In practice, to enforce these constraints, the constraint resolution typically involves solving the following linear system: $$ (\mathbf{J}^T \mathbf{M}^{-1} \mathbf{J}) \boldsymbol{\lambda} = -\mathbf{h}(\mathbf{q}), $$ This equation is solved to determine the Lagrange multipliers $\boldsymbol{\lambda}$ which are then used to compute the constraint forces that are applied to enforce the constraints. ### Implementation Details - **Rigid Bodies**: The `BilateralLagrangianConstraint` can be defined for rigid bodies, where each body has six degrees of freedom (three translational and three rotational). In this case, the constraint enforces both position and orientation equality between two points on different rigid bodies. - **Position & Orientation Violation Calculation**: The violation calculation accounts for both positional differences ($\mathbf{p}_2 - \mathbf{p}_1$) and orientation differences (computed using quaternion algebra). - **Contact Handling**: The component can handle contacts where the initial positions are recorded and used to enforce constraints based on these initial relative configurations. This bilateral holonomic constraint is particularly useful in scenarios involving attachments or fixed connections between bodies, ensuring that they maintain a predefined relationship throughout the simulation.
{
  "name": "BilateralLagrangianConstraint",
  "main": {
    "name": "BilateralLagrangianConstraint",
    "namespace": "sofa::component::constraint::lagrangian::model",
    "module": "Sofa.Component.Constraint.Lagrangian.Model",
    "include": "sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h",
    "doc": "BilateralLagrangianConstraint defining an holonomic equality constraint (attachment).",
    "inherits": [
      "PairInteractionConstraint"
    ],
    "templates": [
      "sofa::defaulttype::Rigid3Types",
      "sofa::defaulttype::Vec3Types"
    ],
    "data_fields": [
      {
        "name": "d_restVector",
        "type": "VecDeriv",
        "xmlname": "rest_vector",
        "help": "Relative position to maintain between attached points (optional)"
      },
      {
        "name": "d_activate",
        "type": "bool",
        "xmlname": "activate",
        "help": "control constraint activation (true by default)"
      },
      {
        "name": "d_keepOrientDiff",
        "type": "bool",
        "xmlname": "keepOrientationDifference",
        "help": "keep the initial difference in orientation (only for rigids)"
      },
      {
        "name": "d_load",
        "type": "SReal",
        "xmlname": "load",
        "help": "Apply this factor to the constraint force to enable incremental loading. This value should be in the interval [0.0, 1.0]."
      }
    ],
    "links": [
      {
        "name": "l_topology1",
        "target": "BaseMeshTopology",
        "kind": "single",
        "xmlname": "topology1",
        "help": "link to the first topology container"
      },
      {
        "name": "l_topology2",
        "target": "BaseMeshTopology",
        "kind": "single",
        "xmlname": "topology2",
        "help": "link to the second topology container"
      }
    ],
    "methods": [
      {
        "name": "init",
        "return_type": "void",
        "params": [],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "bwdInit",
        "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": "buildConstraintMatrix",
        "return_type": "void",
        "params": [
          {
            "name": "cParams",
            "type": "const ConstraintParams *"
          },
          {
            "name": "c1",
            "type": "DataMatrixDeriv &"
          },
          {
            "name": "c2",
            "type": "DataMatrixDeriv &"
          },
          {
            "name": "cIndex",
            "type": "unsigned int &"
          },
          {
            "name": "x1",
            "type": "const DataVecCoord &"
          },
          {
            "name": "x2",
            "type": "const DataVecCoord &"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "getConstraintViolation",
        "return_type": "void",
        "params": [
          {
            "name": "cParams",
            "type": "const ConstraintParams *"
          },
          {
            "name": "v",
            "type": "BaseVector *"
          },
          {
            "name": "x1",
            "type": "const DataVecCoord &"
          },
          {
            "name": "x2",
            "type": "const DataVecCoord &"
          },
          {
            "name": "v1",
            "type": "const DataVecDeriv &"
          },
          {
            "name": "v2",
            "type": "const DataVecDeriv &"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "getVelocityViolation",
        "return_type": "void",
        "params": [
          {
            "name": "v",
            "type": "BaseVector *"
          },
          {
            "name": "x1",
            "type": "const DataVecCoord &"
          },
          {
            "name": "x2",
            "type": "const DataVecCoord &"
          },
          {
            "name": "v1",
            "type": "const DataVecDeriv &"
          },
          {
            "name": "v2",
            "type": "const DataVecDeriv &"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "getConstraintResolution",
        "return_type": "void",
        "params": [
          {
            "name": "cParams",
            "type": "const ConstraintParams *"
          },
          {
            "name": "resTab",
            "type": "int &"
          },
          {
            "name": "offset",
            "type": "unsigned int &"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "handleEvent",
        "return_type": "void",
        "params": [
          {
            "name": "event",
            "type": "sofa::core::objectmodel::Event *"
          }
        ],
        "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": "clear",
        "return_type": "void",
        "params": [
          {
            "name": "reserve",
            "type": "int"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "addContact",
        "return_type": "void",
        "params": [
          {
            "name": "norm",
            "type": "Deriv"
          },
          {
            "name": "P",
            "type": "Coord"
          },
          {
            "name": "Q",
            "type": "Coord"
          },
          {
            "name": "contactDistance",
            "type": "Real"
          },
          {
            "name": "m1",
            "type": "int"
          },
          {
            "name": "m2",
            "type": "int"
          },
          {
            "name": "Pfree",
            "type": "Coord"
          },
          {
            "name": "Qfree",
            "type": "Coord"
          },
          {
            "name": "id",
            "type": "long"
          },
          {
            "name": "localid",
            "type": "PersistentID"
          }
        ],
        "is_virtual": true,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "addContact",
        "return_type": "void",
        "params": [
          {
            "name": "norm",
            "type": "Deriv"
          },
          {
            "name": "P",
            "type": "Coord"
          },
          {
            "name": "Q",
            "type": "Coord"
          },
          {
            "name": "contactDistance",
            "type": "Real"
          },
          {
            "name": "m1",
            "type": "int"
          },
          {
            "name": "m2",
            "type": "int"
          },
          {
            "name": "id",
            "type": "long"
          },
          {
            "name": "localid",
            "type": "PersistentID"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "addContact",
        "return_type": "void",
        "params": [
          {
            "name": "norm",
            "type": "Deriv"
          },
          {
            "name": "contactDistance",
            "type": "Real"
          },
          {
            "name": "m1",
            "type": "int"
          },
          {
            "name": "m2",
            "type": "int"
          },
          {
            "name": "id",
            "type": "long"
          },
          {
            "name": "localid",
            "type": "PersistentID"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "removeContact",
        "return_type": "void",
        "params": [
          {
            "name": "objectId",
            "type": "int"
          },
          {
            "name": "indices",
            "type": "int"
          }
        ],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "getBilateralInteractionIdentifiers",
        "return_type": "int",
        "params": [],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      },
      {
        "name": "getPairInteractionIdentifiers",
        "return_type": "int",
        "params": [],
        "is_virtual": false,
        "is_pure_virtual": false,
        "is_static": false,
        "access": "public"
      }
    ]
  },
  "desc": {
    "name": "BilateralLagrangianConstraint",
    "description": "This component represents a bilateral holonomic constraint that defines an equality relationship between two points or rigid bodies in the simulation.",
    "parameters": [
      {
        "name": "keepOrientDiff",
        "type": "bool",
        "default_value": "",
        "description": "If true, keeps the orientation difference between connected objects."
      },
      {
        "name": "m1",
        "type": "vector<int>",
        "default_value": "",
        "description": "Indices of points/rigid bodies in the first set to constrain."
      },
      {
        "name": "m2",
        "type": "vector<int>",
        "default_value": "",
        "description": "Indices of points/rigid bodies in the second set to constrain."
      },
      {
        "name": "restVector",
        "type": "vector<Deriv>",
        "default_value": "",
        "description": "Rest positions or orientations for constrained points/rigid bodies."
      }
    ],
    "methods": [
      {
        "name": "init()",
        "description": "Initializes the constraint component and its parameters."
      },
      {
        "name": "bwdInit()",
        "description": "Performs any necessary backward initialization, particularly handling orientation differences if specified by keepOrientDiff."
      },
      {
        "name": "getConstraintResolution(ConstraintParams* cParams, std::vector<ConstraintResolution*>& resTab, unsigned int& offset)",
        "description": "Gets the constraint resolution strategy for bilateral constraints."
      },
      {
        "name": "buildConstraintMatrix(const ConstraintParams* cParams, DataMatrixDeriv &c1_d, DataMatrixDeriv &c2_d, unsigned int &constraintId, const DataVecCoord &x1, const DataVecCoord &x2)",
        "description": "Builds the constraint matrix for bilateral constraints between two sets of points or rigid bodies."
      },
      {
        "name": "getConstraintViolation(const ConstraintParams* cParams, BaseVector *v, const DataVecCoord &d_x1, const DataVecCoord &d_x2, const DataVecDeriv &v1, const DataVecDeriv &v2)",
        "description": "Computes the current constraint violation for each constrained point or rigid body."
      },
      {
        "name": "addContact(Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id, PersistentID localid)",
        "description": "Adds a new contact constraint between two points or rigid bodies and updates the rest positions/orientations accordingly."
      }
    ],
    "example_use_case": "This component can be used to create attachments or constraints between different parts of a deformable object simulation. For example, it could be used to ensure that certain vertices on a cloth model remain attached to specific points on a rigid body, maintaining their relative positions and orientations throughout the simulation.",
    "notes": "The BilateralLagrangianConstraint component is designed to work with both Vec3 (vector) types for point-based constraints as well as Rigid3Types for constraints involving rigid bodies. It can enforce equality relationships in position or orientation between specified points or rigid bodies within a simulation, making it useful for creating complex mechanical systems where certain components must remain connected."
  },
  "maths": {
    "maths": "## Bilateral Holonomic Constraint\n\nThe `BilateralLagrangianConstraint` in the SOFA framework defines an equality constraint between two points or rigid bodies. This type of constraint ensures that certain physical quantities remain equal over time, thus creating a direct relationship between the degrees of freedom (DOFs) of the connected entities.\n\n### Mathematical Formulation\n\nFor simplicity, let's denote the positions of two points as $\\mathbf{p}_1$ and $\\mathbf{p}_2$, where $\\mathbf{p}_i \\in \\mathbb{R}^3$. The equality constraint can be expressed in the following form:\n\n$$\n\\mathbf{h}(\\mathbf{q}) = \\mathbf{p}_1(\\mathbf{q}) - \\mathbf{p}_2(\\mathbf{q}) = 0,\n$$\n\nwhere $\\mathbf{q}$ represents the generalized coordinates of the system, and $\\mathbf{h}(\\cdot)$ is a constraint function that enforces the equality between the two points. This can be extended to rigid bodies where $\\mathbf{p}_1$ and $\\mathbf{p}_2$ are not just positions but also orientations represented by quaternions.\n\n### Constraint Jacobian\n\nThe constraint Jacobian matrix, denoted as $\\mathbf{J}$, is used to express the relationship between changes in the generalized coordinates ($\\Delta \\mathbf{q}$) and changes in the constraints ($\\Delta \\mathbf{h}(\\mathbf{q})$):\n\n$$\n\\mathbf{J} = \\frac{\\partial \\mathbf{h}}{\\partial \\mathbf{q}},\n$$\n\nThe constraint Jacobian matrix can be derived as follows:\n\nFor points in 3D space, the Jacobian is a $6 \\times N$ matrix where each row represents one of the 6 constraints (three for position and three for orientation). For example, if we have two rigid bodies connected by this constraint, the Jacobian would look like:\n\n$$\n\\mathbf{J} = \n\\begin{bmatrix}\n    \\frac{\\partial h_x}{\\partial q_1} & \\cdots & \\frac{\\partial h_x}{\\partial q_N} \\\\\n    \\vdots & \\ddots & \\vdots \\\\\n    \\frac{\\partial h_z}{\\partial q_1} & \\cdots & \\frac{\\partial h_z}{\\partial q_N}\n\\end{bmatrix},\n$$\n\nwhere $h_x, h_y, h_z$ are the position components of the constraint function.\n\n### Constraint Violation\n\nThe constraint violation $\\mathbf{v}$ is calculated as:\n\n$$\n\\mathbf{v} = \\mathbf{p}_2 - \\mathbf{p}_1,\n$$\n\nFor rigid bodies, the position and orientation components need to be considered separately. The orientation difference can be computed using a quaternion representation of rotation.\n\n### Constraint Force\n\nThe constraint force $\\boldsymbol{\\lambda}$ is introduced as a Lagrange multiplier that enforces the equality constraints:\n\n$$\n\\mathbf{J}^T \\boldsymbol{\\lambda} = -\\mathbf{M}^{-1} (\\mathbf{h}(\\mathbf{q}) + \\dot{\\mathbf{h}}(\\mathbf{q})),\n$$\n\nwhere $\\mathbf{M}$ is the mass matrix of the system and $\\boldsymbol{\\lambda}$ is a vector of Lagrange multipliers. The constraint force ensures that the constraints are satisfied at each time step.\n\n### Constraint Resolution\n\nIn practice, to enforce these constraints, the constraint resolution typically involves solving the following linear system:\n\n$$\n(\\mathbf{J}^T \\mathbf{M}^{-1} \\mathbf{J}) \\boldsymbol{\\lambda} = -\\mathbf{h}(\\mathbf{q}),\n$$\n\nThis equation is solved to determine the Lagrange multipliers $\\boldsymbol{\\lambda}$ which are then used to compute the constraint forces that are applied to enforce the constraints.\n\n### Implementation Details\n\n- **Rigid Bodies**: The `BilateralLagrangianConstraint` can be defined for rigid bodies, where each body has six degrees of freedom (three translational and three rotational). In this case, the constraint enforces both position and orientation equality between two points on different rigid bodies.\n\n- **Position & Orientation Violation Calculation**: The violation calculation accounts for both positional differences ($\\mathbf{p}_2 - \\mathbf{p}_1$) and orientation differences (computed using quaternion algebra).\n\n- **Contact Handling**: The component can handle contacts where the initial positions are recorded and used to enforce constraints based on these initial relative configurations.\n\nThis bilateral holonomic constraint is particularly useful in scenarios involving attachments or fixed connections between bodies, ensuring that they maintain a predefined relationship throughout the simulation."
  },
  "summary": {
    "abstract": "The `BilateralLagrangianConstraint` enforces an equality relationship between two points or rigid bodies, ensuring that their relative positions and orientations remain constant throughout the simulation.",
    "sheet": "# BilateralLagrangianConstraint\n\n## Overview\n\nThe `BilateralLagrangianConstraint` is a component in the SOFA framework that defines an equality constraint (attachment) between two points or rigid bodies. It inherits from `PairInteractionConstraint`, and it requires links to two topology containers (`topology1` and `topology2`).\n\n## Mathematical Model\n\nThe bilateral holonomic constraint enforces an equality relationship between the positions and orientations of two points or rigid bodies. The constraint function is defined as:\n\n\\[\n\\mathbf{h}(\\mathbf{q}) = \\mathbf{p}_1(\\mathbf{q}) - \\mathbf{p}_2(\\mathbf{q}) = 0,\n\\]\n\nwhere $\\mathbf{p}_i$ are the positions of the points or rigid bodies, and $\\mathbf{q}$ represents the generalized coordinates. The constraint Jacobian matrix is given by:\n\n\\[\n\\mathbf{J} = \\frac{\\partial \\mathbf{h}}{\\partial \\mathbf{q}},\n\\]\n\nwhich relates changes in the generalized coordinates to changes in the constraints.\n\nThe constraint violation $\\mathbf{v}$ is calculated as:\n\n\\[\n\\mathbf{v} = \\mathbf{p}_2 - \\mathbf{p}_1,\n\\]\n\nand the constraint force $\\boldsymbol{\\lambda}$, introduced as a Lagrange multiplier, enforces the equality constraints through the equation:\n\n\\[\n\\mathbf{J}^T \\boldsymbol{\\lambda} = -\\mathbf{M}^{-1} (\\mathbf{h}(\\mathbf{q}) + \\dot{\\mathbf{h}}(\\mathbf{q})),\n\\]\n\nwhere $\\mathbf{M}$ is the mass matrix of the system.\n\n## Parameters and Data\n\n- **rest_vector**: Relative position to maintain between attached points (optional).\n  - Type: `VecDeriv`\n  - XML Name: `rest_vector`\n\n- **activate**: Control constraint activation (true by default).\n  - Type: `bool`\n  - XML Name: `activate`\n\n- **keepOrientationDifference**: Keep the initial difference in orientation (only for rigids).\n  - Type: `bool`\n  - XML Name: `keepOrientationDifference`\n\n- **load**: Apply this factor to the constraint force to enable incremental loading. This value should be in the interval [0.0, 1.0].\n  - Type: `SReal`\n  - XML Name: `load`\n\n## Dependencies and Connections\n\nThe component requires links to two topology containers (`topology1` and `topology2`). It fits into the scene graph by enforcing constraints between these topologies, ensuring that their relative positions and orientations remain constant throughout the simulation."
  }
}