Skip to content

Quaternion Coordinates — RibleQCF

RibleQCF is an extension package that adds quaternion-based coordinates (QC) as an alternative to the default Natural Coordinate Formulation (NCF). A single rigid body is described by 7 generalized coordinates — 3 for translation and 4 for a unit quaternion — yielding 6 degrees of freedom after the unit-norm constraint is enforced. The inertia representation and its numerical influence follow the framework established in [2] and [3].

Tip

QCF produces a non-constant mass matrix, which requires recomputations during updates and has involved jacobian formulations.

Coordinate Type QC

The core type QCF.QC stores mass and a diagonalized inertia tensor along with several precomputed scalars derived from them:

julia
struct QC{T,JT} <: AbstractCoordinates{3,T}
    m      # mass
    m⁻¹    # 1/mass
    γ      # max diagonal of inertia (regularization parameter)
# J - γ·I
    γ⁻¹    # 1/γ
    J⁻¹γ   # J⁻¹ - (1/γ)·I
end

Construct a QC instance by passing mass and a 3×3 inertia matrix:

julia
m = 0.5
J = Diagonal(SA[0.001, 0.001, 0.002])

qc = QCF.QC(m, J)

Only the diagonal of the inertia matrix is used; off-diagonal terms are discarded internally. The optional keyword γ defaults to maximum(diag(J)) and acts as a regularization parameter that keeps the rotational mass matrix well-conditioned.

Checking the coordinate trait

You can query whether a body uses constant-mass coordinates at any level:

julia
has_constant_mass_matrix(body.coords)   # Val(false) for QC
has_constant_mass_matrix(body)          # propagates from coords
has_constant_mass_matrix(structure)     # propagates from bodies

Nonconstant Mass Matrix

Unlike NCF (where has_constant_mass_matrix returns Val(true)), the QCF generalized mass matrix depends on the current quaternion state:

julia
has_constant_mass_matrix(::QCF.QC) = Val(false)

The 7×7 mass matrix is block-diagonal:

where is the 4×4 left-quaternion-multiplication matrix. Because changes every step, the solver must recompute and refactorize it at each iteration. Rible handles this automatically through its solver dispatch: when it detects Val(false), it selects the Zhong06_Nonconstant_Mass solver family instead of the constant-mass family.

Practical implications

  • Cost per step is higher than NCF due to per-step mass-matrix assembly and factorization. For single-body simulations the difference is negligible; for large multi-body systems with many QCF bodies, consider whether NCF suffices.

  • Tight tolerances help. The quaternion constraint   drifts if the solver tolerances are loose. Using ftol = 1e-14 and maxiters = 50 is a good default.

Intrinsic Constraint

QC carries one intrinsic algebraic constraint — the unit quaternion norm:

This constraint is enforced automatically by the solver alongside any joint constraints. The framework provides the constraint function, its Jacobian, and the force-Jacobian in constraints.jl.

Complete Example: Spinning Top with QCF

The bundled spinning-top model supports both NCF and QCF via the cT argument. Below we construct a QCF top, verify its nonconstant-mass trait, and run a full contact simulation.

Construction

julia
include(joinpath(pathof(Rible), "../../examples/robots/spinningtop.jl"))

origin_position = [0.0, 0.0, 0.5]
R = RotX(0.0)
origin_velocity = [1.0, 0.0, 0.0]
Ω = [0.0, 0.0, 200.0]

top = make_top(origin_position, R, origin_velocity, Ω, :QCF; μ = 0.95, e = 0.5, loadmesh = true)
Robot{Structure{TypeSortedCollections.TypeSortedCollection{Tuple{Vector{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}}, 1}, Vector{Int64}, Connectivity{Vector{Vector{Int64}}}, Rible.StructureState{CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}, Vector{CoordinatesState{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, Vector{Float64}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}}}}, @NamedTuple{activated_bits::BitVector, persistent_bits::BitVector, friction_coefficients::Vector{Float64}, restitution_coefficients::Vector{Float64}, gaps::Vector{Float64}}, Rible.StructureCache{InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseVector{Float64, Int64}}}}, ControlHub{Vector{Int64}, TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ErrorGauge{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, PositionCaptum, Vector{Float64}}}}, 1}, TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ExternalForceActuator{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, NaiveOperator, Vector{Float64}, Float64}}}, 1}, Coalition, @NamedTuple{c::Vector{Float64}, e::Vector{Float64}, u::Vector{Float64}}}, StructArrays.StructVector{CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}, @NamedTuple{t::Vector{Float64}, q::Vector{Vector{Float64}}, q̇::Vector{Vector{Float64}}, q̈::Vector{Vector{Float64}}, F::Vector{Vector{Float64}}, λ::Vector{Vector{Float64}}, s::Vector{Vector{Float64}}, p::Vector{Vector{Float64}}, c::Vector{Vector{Float64}}}, Int64}, Vector{Vector{Rible.Contact{Float64}}}, Vector{@NamedTuple{na::Int64, bodyid2act_idx::Vector{Vector{Int64}}, persistent_idx::Vector{Int64}, activated_bits::BitVector, H::LinearAlgebra.Diagonal{Float64, Vector{Float64}}, activated_restitution_coefficients::Vector{Float64}, D::Matrix{Float64}, Dper::Matrix{Float64}, Dimp::Matrix{Float64}, ∂Dq̇∂q::Matrix{Float64}, ∂DᵀΛ∂q::Matrix{Float64}, ŕ::Vector{Float64}, L::Matrix{Float64}, Lv::Matrix{Float64}, Λ::Vector{Float64}, Γ::Vector{Float64}}}, StructArrays.StructVector{@NamedTuple{c::Vector{Float64}, e::Vector{Float64}, u::Vector{Float64}}, @NamedTuple{c::Vector{Vector{Float64}}, e::Vector{Vector{Float64}}, u::Vector{Vector{Float64}}}, Int64}}(Structure{TypeSortedCollections.TypeSortedCollection{Tuple{Vector{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}}, 1}, Vector{Int64}, Connectivity{Vector{Vector{Int64}}}, Rible.StructureState{CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}, Vector{CoordinatesState{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, Vector{Float64}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}}}}, @NamedTuple{activated_bits::BitVector, persistent_bits::BitVector, friction_coefficients::Vector{Float64}, restitution_coefficients::Vector{Float64}, gaps::Vector{Float64}}, Rible.StructureCache{InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseVector{Float64, Int64}}}}(3, TypeSortedCollections.TypeSortedCollection{Tuple{Vector{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}}, 1}((RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}[RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}(RigidBodyProperty{3, Float64, 9}(true, true, 1, :generic, 0.5838707, [0.00022129 0.0 0.0; 0.0 0.00022129 0.0; 0.0 0.0 0.00030207], Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.0, 0.0), Locus{3, Float64, 9}[Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, -0.03795882], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5)]), RigidBodyState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}[Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.46204118], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0])]), RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}(0.5838707, 1.7127079677058636, 0.00030207, Diagonal([-8.078e-5, -8.078e-5, 0.0]), 3310.4909458072634, Diagonal([1208.4660789114314, 1208.4660789114314, 0.0])), RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}([1.0 0.0 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], StaticArraysCore.MMatrix{3, 7, Float64, 21}[[1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … -0.07591764 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0]], InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}(sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [0.5838707, 0.5838707, 0.5838707, 0.00120828, 0.00088516, 0.00088516, 0.00120828], 7, 7), sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [1.7127079677058636, 1.7127079677058636, 1.7127079677058636, 827.6227364518159, 1129.7392561796737, 1129.7392561796737, 827.6227364518159], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, -0.0, 0.0], true), nothing), Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}(...))],), ([1],)), Int64[], Connectivity{Vector{Vector{Int64}}}(1, 0, 0, 0, 7, 1, 0, 1, 6, 6, 0, [1, 2, 3, 4, 5, 6, 7], [[1, 2, 3, 4, 5, 6, 7]], [[1]], [[1, 2, 3, 4, 5, 6]], Vector{Int64}[], Vector{Int64}[], [[1, 2, 3, 4, 5, 6]], Signifier{Int64}[Signifier{Int64}(1, 1), Signifier{Int64}(1, 2), Signifier{Int64}(1, 3), Signifier{Int64}(1, 4), Signifier{Int64}(1, 5), Signifier{Int64}(1, 6)], [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]], [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]], 7, 18, 18, 0, 18, Vector{Int64}[], Vector{Int64}[]), Rible.StructureState{CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}, Vector{CoordinatesState{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, Vector{Float64}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}}}}(CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}(0.0, [0.0, 0.0, 0.5, 1.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, -0.0, 0.0, 0.0, 100.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0], Float64[], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0], [0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.0, 0.0, -0.03795882, 0.0, 0.0, 0.0]), CoordinatesState{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, Vector{Float64}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}}[CoordinatesState{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}, Vector{Float64}, SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}}(0.0, [0.0, 0.0, 0.5, 1.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, -0.0, 0.0, 0.0, 100.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0], Float64[], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.0, 0.0, -0.03795882, 0.0, 0.0, 0.0])]), (activated_bits = Bool[0, 0, 0, 0, 0, 0], persistent_bits = Bool[0, 0, 0, 0, 0, 0], friction_coefficients = [0.95, 0.95, 0.95, 0.95, 0.95, 0.95], restitution_coefficients = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5], gaps = [Inf, Inf, Inf, Inf, Inf, Inf]), Rible.StructureCache{InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseVector{Float64, Int64}}}(InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseVector{Float64, Int64}}(sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 7, 7), sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 7, 7), sparse(Int64[], Int64[], Float64[], 7, 7), sparse(Int64[], Int64[], Float64[], 7, 7), sparsevec(Int64[], Float64[], 7), sparsevec(Int64[], Float64[], 7), true))), ControlHub{Vector{Int64}, TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ErrorGauge{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, PositionCaptum, Vector{Float64}}}}, 1}, TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ExternalForceActuator{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, NaiveOperator, Vector{Float64}, Float64}}}, 1}, Coalition, @NamedTuple{c::Vector{Float64}, e::Vector{Float64}, u::Vector{Float64}}}(Int64[], TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ErrorGauge{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, PositionCaptum, Vector{Float64}}}}, 1}((ErrorGauge{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, PositionCaptum, Vector{Float64}}[ErrorGauge{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, PositionCaptum, Vector{Float64}}(1, Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}(RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}(RigidBodyProperty{3, Float64, 9}(true, true, 1, :generic, 0.5838707, [0.00022129 0.0 0.0; 0.0 0.00022129 0.0; 0.0 0.0 0.00030207], Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.0, 0.0), Locus{3, Float64, 9}[Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, -0.03795882], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5)]), RigidBodyState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}[Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.46204118], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0])]), RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}(0.5838707, 1.7127079677058636, 0.00030207, Diagonal([-8.078e-5, -8.078e-5, 0.0]), 3310.4909458072634, Diagonal([1208.4660789114314, 1208.4660789114314, 0.0])), RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}([1.0 0.0 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], StaticArraysCore.MMatrix{3, 7, Float64, 21}[[1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … -0.07591764 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0]], InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}(sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [0.5838707, 0.5838707, 0.5838707, 0.00120828, 0.00088516, 0.00088516, 0.00120828], 7, 7), sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [1.7127079677058636, 1.7127079677058636, 1.7127079677058636, 827.6227364518159, 1129.7392561796737, 1129.7392561796737, 827.6227364518159], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, -0.0, 0.0], true), nothing), Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}(...)), 6), PositionCaptum(), [0.5, 0.0, 0.2])],), ([1],)), TypeSortedCollections.TypeSortedCollection{Tuple{Vector{ExternalForceActuator{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, NaiveOperator, Vector{Float64}, Float64}}}, 1}((ExternalForceActuator{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, NaiveOperator, Vector{Float64}, Float64}[ExternalForceActuator{Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}, NaiveOperator, Vector{Float64}, Float64}(1, Signifier{RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}}(RigidBody{3, 3, Float64, 9, RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}, RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}, GeometryBasics.Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}, (:position, :normal, :color), Tuple{Vector{GeometryBasics.Point{3, Float64}}, Vector{GeometryBasics.Vec{3, Float32}}, Vector{ColorTypes.RGB{Float32}}}, Vector{GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}}}(RigidBodyProperty{3, Float64, 9}(true, true, 1, :generic, 0.5838707, [0.00022129 0.0 0.0; 0.0 0.00022129 0.0; 0.0 0.0 0.00030207], Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.0, 0.0), Locus{3, Float64, 9}[Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, -0.03795882], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5), Locus{3, Float64, 9}([0.0, 0.0, 0.0], Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), 0.95, 0.5)]), RigidBodyState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}[Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.03111269837220809, 0.03111269837220809, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.46204118], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0]), Rible.LocusState{3, 3, Float64, 9}(Rible.CartesianFrame{3, 3, Float64, 9}([0.0, 0.0, 0.5], Rible.Axes{3, Float64, 9}([0.0 0.0 1.0; 1.0 0.0 0.0; 0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], Rible.ContactState{3, Float64, 9}(false, true, Inf, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]), [1.0, 0.0, 0.0])]), RibleQCF.QC{Float64, LinearAlgebra.Diagonal{Float64, StaticArraysCore.SVector{3, Float64}}}(0.5838707, 1.7127079677058636, 0.00030207, Diagonal([-8.078e-5, -8.078e-5, 0.0]), 3310.4909458072634, Diagonal([1208.4660789114314, 1208.4660789114314, 0.0])), RigidBodyCache{StaticArraysCore.MMatrix{3, 7, Float64, 21}, InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}, Nothing}([1.0 0.0 … 0.0 0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], StaticArraysCore.MMatrix{3, 7, Float64, 21}[[1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … 0.0 -0.06222539674441618; 0.0 1.0 … 0.0 0.06222539674441618; 0.0 0.0 … -0.06222539674441618 0.0], [1.0 0.0 … -0.07591764 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0], [1.0 0.0 … 0.0 -0.0; 0.0 1.0 … 0.0 0.0; 0.0 0.0 … -0.0 0.0]], InertiaCache{SparseArrays.SparseMatrixCSC{Float64, Int64}, SparseArrays.SparseMatrixCSC{Float64, Int64}, StaticArraysCore.MVector{7, Float64}}(sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [0.5838707, 0.5838707, 0.5838707, 0.00120828, 0.00088516, 0.00088516, 0.00120828], 7, 7), sparse([1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7], [1.7127079677058636, 1.7127079677058636, 1.7127079677058636, 827.6227364518159, 1129.7392561796737, 1129.7392561796737, 827.6227364518159], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), sparse([4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7], [4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7], [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0], 7, 7), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, -0.0, 0.0], true), nothing), Mesh{3, Float64, GeometryBasics.NgonFace{3, GeometryBasics.OffsetInteger{-1, UInt32}}}(...)), 5), NaiveOperator(1), [0.0, 1.0, 0.0], [0.0])],), ([1],)), Coalition(1, 0, 1, 0, 1, Vector{Int64}[], [[1]], 1, [[1]]), (c = Float64[], e = [0.16999999999999998], u = [0.0])), CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}[CoordinatesState{Float64, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}}(0.0, [0.0, 0.0, 0.5, 1.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, -0.0, 0.0, 0.0, 100.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0], Float64[], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0], [0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.03111269837220809, 0.03111269837220809, 0.0, 0.0, 0.0, -0.03795882, 0.0, 0.0, 0.0])], Vector{Rible.Contact{Float64}}[[Rible.Contact{Float64}(1, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])), Rible.Contact{Float64}(2, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])), Rible.Contact{Float64}(3, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])), Rible.Contact{Float64}(4, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])), Rible.Contact{Float64}(5, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])), Rible.Contact{Float64}(6, 0.95, 0.5, Rible.ContactState{3, Float64, 9}(false, true, 1.0, Rible.Axes{3, Float64, 9}([-0.0 -0.0 1.0; 1.0 -0.0 0.0; -0.0 1.0 0.0]), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]))]], @NamedTuple{na::Int64, bodyid2act_idx::Vector{Vector{Int64}}, persistent_idx::Vector{Int64}, activated_bits::BitVector, H::LinearAlgebra.Diagonal{Float64, Vector{Float64}}, activated_restitution_coefficients::Vector{Float64}, D::Matrix{Float64}, Dper::Matrix{Float64}, Dimp::Matrix{Float64}, ∂Dq̇∂q::Matrix{Float64}, ∂DᵀΛ∂q::Matrix{Float64}, ŕ::Vector{Float64}, L::Matrix{Float64}, Lv::Matrix{Float64}, Λ::Vector{Float64}, Γ::Vector{Float64}}[(na = 0, bodyid2act_idx = [[0, 0, 0, 0, 0, 0]], persistent_idx = [], activated_bits = [0, 0, 0, 0, 0, 0], H = Diagonal(Float64[]), activated_restitution_coefficients = [], D = Matrix{Float64}(undef, 0, 7), Dper = Matrix{Float64}(undef, 0, 7), Dimp = Matrix{Float64}(undef, 0, 7), ∂Dq̇∂q = Matrix{Float64}(undef, 0, 7), ∂DᵀΛ∂q = [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], ŕ = [], L = Matrix{Float64}(undef, 0, 0), Lv = Matrix{Float64}(undef, 0, 0), Λ = [], Γ = [])], [(c = Float64[], e = [0.16999999999999998], u = [0.0])])

Verify the nonconstant-mass trait

julia
body1 = get_bodies(top.structure)[1]
has_constant_mass_matrix(body1.coords) === Val(false)
true

Contact setup and simulation

The solver object is the same as for NCF — a Zhong06 integrator with an inner contact solver. Internally, the framework routes QCF bodies to the nonconstant-mass code path.

julia
planes = StaticContactSurfaces([
    HalfSpace([0.0, 0.0, 1.0], [0.0, 0.0, 0.0]),
])

contact_model = RestitutionFrictionCombined(
    NewtonRestitution(),
    CoulombFriction(),
)

prob = DynamicsProblem(top; env=planes, contact_model)

solver = DynamicsSolver(
    Zhong06(),
    InnerLayerContactSolver(InteriorPointMethod()),
)

sim_result = solve!(
    prob,
    solver;
    tspan = (0.0, 0.2),
    dt = 1e-3,
    ftol = 1e-14,
    maxiters = 50,
    exception = false,
)

tip_pos = get_trajectory!(top, 1, 1).u[end]
tip_vel = get_velocity!(top, 1, 1).u[end]
tip_pos, tip_vel
([0.15600299208285928, -0.0005131221481740021, 0.3038000000000203], [1.1026244296346408, -8.79940158342844, -1.9619999999997975])

Visualization

Because the top was constructed with loadmesh = true, vis! renders the STL geometry directly:

julia
key_steps = round.(Int, range(1, length(top.traj.t), length = 4))

fig_traj = plot_traj!(
    top;
    do_slide = false,
    show_info = false,
    show_loci = false,
    show_background = false,
    show_ground = false,
    gridsize = (2, 2),
    at_steps = key_steps,
)

Comparing QCF and NCF results

You can reuse the same initial conditions with :NCF to compare:

julia
top_ncf = make_top(origin_position, R, origin_velocity, Ω, :NCF; μ = 0.95, e = 0.5, loadmesh = false)

has_constant_mass_matrix(get_bodies(top_ncf.structure)[1].coords) === Val(true)
true

References

  1. X. Xu and W. Zhong. On the Numerical Influences of Inertia Representation for Rigid Body Dynamics in Terms of Unit Quaternion. Journal of Applied Mechanics-Transactions of the ASME 83, 061006 (2016). Accessed on Oct 30, 2022.

  2. X. Xu, J. Luo and Z. Wu. The Numerical Influence of Additional Parameters of Inertia Representations for Quaternion-Based Rigid Body Dynamics. Multibody System Dynamics 49, 237–270 (2020). Accessed on Oct 13, 2022.