From 7ec50b2dd98414ce87e030e7b481df34d2f59017 Mon Sep 17 00:00:00 2001 From: bakpaul Date: Tue, 21 May 2024 17:30:19 +0200 Subject: [PATCH 01/21] Add fixed weak constraint and examples --- .../SolidMechanics/Spring/CMakeLists.txt | 3 + .../spring/FixedWeakConstraint.cpp | 53 +++ .../spring/FixedWeakConstraint.h | 116 +++++++ .../spring/FixedWeakConstraint.inl | 324 ++++++++++++++++++ .../Spring/FixedWeakConstaint_Rigid3.scn | 55 +++ .../Spring/FixedWeakConstaint_Vec3.scn | 70 ++++ 6 files changed, 621 insertions(+) create mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp create mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h create mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl create mode 100644 examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Rigid3.scn create mode 100644 examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn diff --git a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt index 12dbde4f034..4cb8698c1fe 100644 --- a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt +++ b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt @@ -12,6 +12,8 @@ set(HEADER_FILES # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.h ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.inl + ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FixedWeakConstraint.h + ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FixedWeakConstraint.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FrameSpringForceField.h ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FrameSpringForceField.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/GearSpringForceField.h @@ -58,6 +60,7 @@ set(SOURCE_FILES ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/AngularSpringForceField.cpp # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.cpp ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.cpp + ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FixedWeakConstraint.cpp ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FrameSpringForceField.cpp ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/GearSpringForceField.cpp ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/JointSpring.cpp diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp new file mode 100644 index 00000000000..b67469aecd8 --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp @@ -0,0 +1,53 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#define SOFA_COMPONENT_FORCEFIELD_RESTSHAPESPRINGSFORCEFIELD_CPP + +#include + +#include +#include +#include + + +namespace sofa::component::solidmechanics::spring +{ + +using namespace sofa::type; +using namespace sofa::defaulttype; + +int FixedWeakConstraintClass = core::RegisterObject("Elastic springs generating forces on degrees of freedom between their current and rest shape position") + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >() + + ; + +template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; + + +} // namespace sofa::component::solidmechanics::spring diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h new file mode 100644 index 00000000000..16aac5b5578 --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -0,0 +1,116 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include + +#include +#include +#include +#include +#include + + +namespace sofa::core::behavior +{ + +template< class T > class MechanicalState; + +} // namespace sofa::core::behavior + +namespace sofa::component::solidmechanics::spring +{ + +/** +* @brief This class describes a simple elastic springs ForceField between DOFs positions and rest positions. +* +* Springs are applied to given degrees of freedom between their current positions and their rest shape positions. +* An external MechanicalState reference can also be passed to the ForceField as rest shape position. +*/ +template +class FixedWeakConstraint : public core::behavior::ForceField +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(FixedWeakConstraint, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); + + typedef core::behavior::ForceField Inherit; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename DataTypes::VecDeriv VecDeriv; + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::CPos CPos; + typedef typename DataTypes::Deriv Deriv; + typedef typename DataTypes::Real Real; + typedef type::vector< sofa::Index > VecIndex; + typedef sofa::core::topology::TopologySubsetIndices DataSubsetIndex; + typedef type::vector< Real > VecReal; + + static constexpr sofa::Size spatial_dimensions = Coord::spatial_dimensions; + static constexpr sofa::Size coord_total_size = Coord::total_size; + + typedef core::objectmodel::Data DataVecCoord; + typedef core::objectmodel::Data DataVecDeriv; + + typedef sofa::core::topology::TopologySubsetIndices SetIndex; + + SetIndex d_indices; + Data d_fixAll; + Data< Real > d_stiffness; ///< stiffness values between the actual position and the rest shape position + Data< Real > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points + Data< bool > d_drawSpring; ///< draw Spring + Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) + + linearalgebra::EigenBaseSparseMatrix matS; + /// Link to be set to the topology container in the component graph. + SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; + +protected: + FixedWeakConstraint(); + bool checkOutOfBoundsIndices(); + +public: + virtual void init() override; + + /// Add the forces. + void addForce(const core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v) override; + void addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) override; + SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override; + + /// Brings ForceField contribution to the global system stiffness matrix. + void addKToMatrix(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix ) override; + void buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) override; + void buildDampingMatrix(core::behavior::DampingMatrix* matrix) override; + + void draw(const core::visual::VisualParams* vparams) override; + + +}; + +#if !defined(SOFA_COMPONENT_FORCEFIELD_RESTSHAPESPRINGSFORCEFIELD_CPP) +extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +#endif + +} // namespace sofa::component::solidmechanics::spring diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl new file mode 100644 index 00000000000..5e5d3e4407b --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -0,0 +1,324 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace sofa::component::solidmechanics::spring +{ + +using helper::WriteAccessor; +using helper::ReadAccessor; +using core::behavior::BaseMechanicalState; +using core::behavior::MultiMatrixAccessor; +using core::behavior::ForceField; +using linearalgebra::BaseMatrix; +using core::VecCoordId; +using core::MechanicalParams; +using type::Vec3; +using type::Vec4f; +using type::vector; +using core::visual::VisualParams; + +template +FixedWeakConstraint::FixedWeakConstraint() + : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) + , d_stiffness(initData(&d_stiffness, 1.0,"stiffness", "stiffness value between the actual position and the rest shape position")) + , d_angularStiffness(initData(&d_angularStiffness,1.0, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) + , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) + , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) + , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) +{ + this->addUpdateCallback("updateInputs", {&d_indices}, [this](const core::DataTracker& t) + { + SOFA_UNUSED(t); + if(checkOutOfBoundsIndices()) + { + msg_error() << "Input indices out of bound"; + return sofa::core::objectmodel::ComponentState::Invalid; + } + + return sofa::core::objectmodel::ComponentState::Valid; + }, {}); +} + +template +void FixedWeakConstraint::init() +{ + Inherit::init(); + if (l_topology.empty()) + { + msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; + l_topology.set(this->getContext()->getMeshTopologyLink()); + if(! l_topology.get()) + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + } + + if (sofa::core::topology::BaseMeshTopology* _topology = l_topology.get()) + { + msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; + + // Initialize topological changes support + d_indices.createTopologyHandler(_topology); + } + + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); +} + +template +bool FixedWeakConstraint::checkOutOfBoundsIndices() +{ + for(auto idx : d_indices.getValue()) + { + if(idx >= this->mstate->getSize()) + return true; + } + return false; +} + +template +SReal FixedWeakConstraint::getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const +{ + SOFA_UNUSED(mparams); + SOFA_UNUSED(x); + + msg_warning() << "Method getPotentialEnergy not implemented yet."; + return 0.0; +} + +template +void FixedWeakConstraint::addForce(const MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) +{ + SOFA_UNUSED(mparams); + SOFA_UNUSED(v); + + WriteAccessor< DataVecDeriv > f1 = f; + ReadAccessor< DataVecCoord > p1 = x; + + const DataVecCoord * restPosition = this->mstate->read(sofa::core::VecId::resetPosition()); + if (!restPosition) + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + + ReadAccessor< DataVecCoord > p0 = *restPosition; + + const Real& stiffness = d_stiffness.getValue(); + const Real& angularStiffness = d_angularStiffness.getValue(); + + f1.resize(p1.size()); + + + for (sofa::Index i = 0; i < d_indices.getValue().size(); i++) + { + const sofa::Index index = d_indices.getValue()[i]; + + // rigid case + if constexpr (sofa::type::isRigidType()) + { + // translation + CPos dx = p1[index].getCenter() - p0[index].getCenter(); + getVCenter(f1[index]) -= dx * stiffness; + + // rotation + type::Quat dq = p1[index].getOrientation() * p0[index].getOrientation().inverse(); + dq.normalize(); + + type::Vec<3, Real> dir{type::NOINIT}; + Real angle = 0.; + + if (dq[3] < 0.) + { + dq = dq * -1.0; + } + + if (dq[3] < 1.0) + dq.quatToAxis(dir, angle); + + getVOrientation(f1[index]) -= dir * angle * angularStiffness; + } + else // non-rigid implementation + { + Deriv dx = p1[index] - p0[index]; + f1[index] -= dx * stiffness; + } + } +} + +template +void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) +{ + WriteAccessor< DataVecDeriv > df1 = df; + ReadAccessor< DataVecDeriv > dx1 = dx; + Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); + const Real& stiffness = d_stiffness.getValue(); + const Real& angularStiffness = d_angularStiffness.getValue(); + + for (unsigned int i = 0; i < d_indices.getValue().size(); i++) + { + const sofa::Index curIndex = d_indices.getValue()[i]; + + if constexpr (sofa::type::isRigidType()) + { + getVCenter(df1[curIndex]) -= getVCenter(dx1[curIndex]) * stiffness * kFactor; + getVOrientation(df1[curIndex]) -= getVOrientation(dx1[curIndex]) * angularStiffness * kFactor; + } + else + { + df1[d_indices.getValue()[i]] -= dx1[d_indices.getValue()[i]] * stiffness * kFactor; + } + } + + +} + +template +void FixedWeakConstraint::draw(const VisualParams *vparams) +{ + if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) + return; + + const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); + vparams->drawTool()->setLightingEnabled(false); + + const DataVecCoord * restPosition = this->mstate->read(sofa::core::VecId::resetPosition()); + if (!restPosition) + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + + + ReadAccessor< DataVecCoord > p0 = *restPosition; + ReadAccessor< DataVecCoord > p = this->mstate->read(VecCoordId::position()); + + const VecIndex& indices = d_indices.getValue(); + + std::vector vertices; + + for (sofa::Index i=0; i(3)) ; j++) + { + v0[j] = (DataTypes::getCPos(p[index]))[j]; + v1[j] = (DataTypes::getCPos(p0[index]))[j]; + } + + vertices.push_back(v0); + vertices.push_back(v1); + } + + vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); +} + +template +void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) +{ + const MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); + BaseMatrix* mat = mref.matrix; + const unsigned int offset = mref.offset; + Real kFact = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); + + const Real& k = d_stiffness.getValue(); + const Real& k_a = d_angularStiffness.getValue(); + + constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes + constexpr sofa::Size total_size = Deriv::total_size; + + sofa::Index curIndex = 0; + + for (sofa::Index index = 0; index < d_indices.getValue().size(); index++) + { + curIndex = d_indices.getValue()[index]; + + // translation + const auto vt = -kFact * k; + for (sofa::Size i = 0; i < space_size; i++) + { + mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vt); + } + + // rotation (if applicable) + if constexpr (sofa::type::isRigidType()) + { + const auto vr = -kFact * k_a; + for (sofa::Size i = space_size; i < total_size; i++) + { + mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vr); + } + } + } +} + +template +void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) +{ + const Real& vt = -d_stiffness.getValue(); + const Real& vr = -d_angularStiffness.getValue(); + + constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes + constexpr sofa::Size total_size = Deriv::total_size; + + auto dfdx = matrix->getForceDerivativeIn(this->mstate) + .withRespectToPositionsIn(this->mstate); + + for (const auto index : d_indices.getValue()) + { + // translation + for(sofa::Index i = 0; i < space_size; i++) + { + dfdx(total_size * index + i, total_size * index + i) += vt; + } + + // rotation (if applicable) + if constexpr (sofa::type::isRigidType()) + { + for (sofa::Size i = space_size; i < total_size; ++i) + { + dfdx(total_size * index + i, total_size * index + i) += vr; + } + } + } +} + +template +void FixedWeakConstraint::buildDampingMatrix( + core::behavior::DampingMatrix* matrix) +{ + SOFA_UNUSED(matrix); +} +} // namespace sofa::component::solidmechanics::spring diff --git a/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Rigid3.scn b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Rigid3.scn new file mode 100644 index 00000000000..af8009855fd --- /dev/null +++ b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Rigid3.scn @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn new file mode 100644 index 00000000000..6787469b811 --- /dev/null +++ b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 01f9faf60e1afef459a59542095892c36f7fb912 Mon Sep 17 00:00:00 2001 From: bakpaul Date: Tue, 21 May 2024 17:47:29 +0200 Subject: [PATCH 02/21] Remove nasty using --- .../spring/FixedWeakConstraint.h | 7 --- .../spring/FixedWeakConstraint.inl | 45 +++++++------------ 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index 16aac5b5578..c8bf8ef0f84 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -31,13 +31,6 @@ #include -namespace sofa::core::behavior -{ - -template< class T > class MechanicalState; - -} // namespace sofa::core::behavior - namespace sofa::component::solidmechanics::spring { diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index 5e5d3e4407b..07748e53308 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -36,19 +36,6 @@ namespace sofa::component::solidmechanics::spring { -using helper::WriteAccessor; -using helper::ReadAccessor; -using core::behavior::BaseMechanicalState; -using core::behavior::MultiMatrixAccessor; -using core::behavior::ForceField; -using linearalgebra::BaseMatrix; -using core::VecCoordId; -using core::MechanicalParams; -using type::Vec3; -using type::Vec4f; -using type::vector; -using core::visual::VisualParams; - template FixedWeakConstraint::FixedWeakConstraint() : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) @@ -116,13 +103,13 @@ SReal FixedWeakConstraint::getPotentialEnergy(const core::MechanicalP } template -void FixedWeakConstraint::addForce(const MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) +void FixedWeakConstraint::addForce(const core::MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) { SOFA_UNUSED(mparams); SOFA_UNUSED(v); - WriteAccessor< DataVecDeriv > f1 = f; - ReadAccessor< DataVecCoord > p1 = x; + helper::WriteAccessor< DataVecDeriv > f1 = f; + helper::ReadAccessor< DataVecCoord > p1 = x; const DataVecCoord * restPosition = this->mstate->read(sofa::core::VecId::resetPosition()); if (!restPosition) @@ -131,7 +118,7 @@ void FixedWeakConstraint::addForce(const MechanicalParams* mparams , return; } - ReadAccessor< DataVecCoord > p0 = *restPosition; + helper::ReadAccessor< DataVecCoord > p0 = *restPosition; const Real& stiffness = d_stiffness.getValue(); const Real& angularStiffness = d_angularStiffness.getValue(); @@ -176,10 +163,10 @@ void FixedWeakConstraint::addForce(const MechanicalParams* mparams , } template -void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) +void FixedWeakConstraint::addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) { - WriteAccessor< DataVecDeriv > df1 = df; - ReadAccessor< DataVecDeriv > dx1 = dx; + helper::WriteAccessor< DataVecDeriv > df1 = df; + helper::ReadAccessor< DataVecDeriv > dx1 = dx; Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); const Real& stiffness = d_stiffness.getValue(); const Real& angularStiffness = d_angularStiffness.getValue(); @@ -203,7 +190,7 @@ void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, } template -void FixedWeakConstraint::draw(const VisualParams *vparams) +void FixedWeakConstraint::draw(const core::visual::VisualParams *vparams) { if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) return; @@ -219,19 +206,19 @@ void FixedWeakConstraint::draw(const VisualParams *vparams) } - ReadAccessor< DataVecCoord > p0 = *restPosition; - ReadAccessor< DataVecCoord > p = this->mstate->read(VecCoordId::position()); + helper::ReadAccessor< DataVecCoord > p0 = *restPosition; + helper::ReadAccessor< DataVecCoord > p = this->mstate->read(core::VecCoordId::position()); const VecIndex& indices = d_indices.getValue(); - std::vector vertices; + std::vector vertices; for (sofa::Index i=0; i(3)) ; j++) { v0[j] = (DataTypes::getCPos(p[index]))[j]; @@ -246,10 +233,10 @@ void FixedWeakConstraint::draw(const VisualParams *vparams) } template -void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) +void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* mparams, const core::behavior::MultiMatrixAccessor* matrix ) { - const MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); - BaseMatrix* mat = mref.matrix; + const core::behavior::MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); + linearalgebra::BaseMatrix* mat = mref.matrix; const unsigned int offset = mref.offset; Real kFact = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); From bc1916b8c58790dbebeeba125165226393940163 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Wed, 5 Jun 2024 11:50:28 +0200 Subject: [PATCH 03/21] WIP --- .../spring/FixedWeakConstraint.inl | 1 + .../Spring/tests/CMakeLists.txt | 1 + .../Spring/tests/FixedWeakConstraint_test.cpp | 131 ++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index 07748e53308..ad17c811ca3 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -39,6 +39,7 @@ namespace sofa::component::solidmechanics::spring template FixedWeakConstraint::FixedWeakConstraint() : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) + , d_fixAll(initData(&d_fixAll, false,"fixAll", "stiffness value between the actual position and the rest shape position")) , d_stiffness(initData(&d_stiffness, 1.0,"stiffness", "stiffness value between the actual position and the rest shape position")) , d_angularStiffness(initData(&d_angularStiffness,1.0, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) diff --git a/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt b/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt index e474d48f5fa..d03f0f9ca5f 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt +++ b/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCE_FILES RestShapeSpringsForceField_test.cpp StiffSpringForceField_test.cpp TriangularBendingSprings_test.cpp + FixedWeakConstraint_test.cpp ) add_executable(${PROJECT_NAME} ${SOURCE_FILES}) diff --git a/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp new file mode 100644 index 00000000000..af99a3e063a --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp @@ -0,0 +1,131 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +using sofa::testing::BaseTest; + +#include +using namespace sofa::simpleapi; + +#include +#include + +#include +using sofa::component::statecontainer::MechanicalObject; + +using sofa::defaulttype::Vec3Types; +using sofa::defaulttype::Rigid3dTypes; +using sofa::helper::ReadAccessor; +using sofa::Data; + +/// Test suite for RestShapeSpringsForceField +class RestStiffSpringsForceField_test : public BaseTest +{ +public: + ~RestStiffSpringsForceField_test() override; + sofa::simulation::Node::SPtr createScene(const std::string& type); + + template + void testDefaultBehavior(sofa::simulation::Node::SPtr root); + + template + void checkDifference(MechanicalObject& mo); +}; + +RestStiffSpringsForceField_test::~RestStiffSpringsForceField_test() +{ +} + +sofa::simulation::Node::SPtr RestStiffSpringsForceField_test::createScene(const std::string& type) +{ + const auto theSimulation = createSimulation(); + auto theRoot = createRootNode(theSimulation, "root"); + sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); + sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); + sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + + createObject(theRoot, "DefaultAnimationLoop"); + createObject(theRoot, "EulerImplicitSolver"); + createObject(theRoot, "CGLinearSolver", {{ "iterations", "25" }, { "tolerance", "1e-5" }, {"threshold", "1e-5"}}); + + /// Create an object with a mass and use a rest shape spring ff so it stays + /// at the initial position + const auto fixedObject = createChild(theRoot, "fixedObject"); + auto fixedObject_dofs = createObject(fixedObject, "MechanicalObject", {{"name","dofs"}, + {"size","10"}, + {"template",type}}); + createObject(fixedObject, "UniformMass", {{"totalMass", "1"}}); + + createObject(fixedObject, "FixedWeakConstraint", {{"stiffness","1000"},{"fixAll","true"}}); + + const auto movingObject = createChild(theRoot, "movingObject"); + auto movingObject_dofs = createObject(movingObject, "MechanicalObject", {{"name","dofs"}, + {"size","10"}, + {"template",type}}); + createObject(movingObject, "UniformMass", {{"totalMass", "1"}}); + + sofa::simulation::node::initRoot(theRoot.get()); + for(unsigned int i=0;i<20;i++) + { + sofa::simulation::node::animate(theRoot.get(), 0.01_sreal); + } + return theRoot; +} + +template +void RestStiffSpringsForceField_test::checkDifference(MechanicalObject& mo) +{ + ReadAccessor< Data > positions = mo.x; + ReadAccessor< Data > rest_positions = mo.x0; + for(size_t i=0;i +void RestStiffSpringsForceField_test::testDefaultBehavior(sofa::simulation::Node::SPtr root) +{ + auto fixedDofs = dynamic_cast*>(root->getChild("fixedObject")->getObject("dofs")); + ASSERT_TRUE( fixedDofs != nullptr ); + + auto movingDofs = dynamic_cast*>(root->getChild("movingObject")->getObject("dofs")); + ASSERT_TRUE( movingDofs != nullptr ); + + checkDifference(*fixedDofs); +} + + +TEST_F(RestStiffSpringsForceField_test, defaultBehaviorVec3) +{ + this->testDefaultBehavior(this->createScene("Vec3")); +} + +TEST_F(RestStiffSpringsForceField_test, defaultBehaviorRigid3) +{ + this->testDefaultBehavior(this->createScene("Rigid3")); +} From 01dab0f544eb0efd6f225abb6b1b80219a04fd95 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Fri, 26 Jul 2024 16:59:35 +0200 Subject: [PATCH 04/21] Fix compilation --- .../Spring/tests/FixedWeakConstraint_test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp index af99a3e063a..6362a67d214 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp +++ b/Sofa/Component/SolidMechanics/Spring/tests/FixedWeakConstraint_test.cpp @@ -37,10 +37,10 @@ using sofa::helper::ReadAccessor; using sofa::Data; /// Test suite for RestShapeSpringsForceField -class RestStiffSpringsForceField_test : public BaseTest +class FixedWeakConstraint_test : public BaseTest { public: - ~RestStiffSpringsForceField_test() override; + ~FixedWeakConstraint_test() override; sofa::simulation::Node::SPtr createScene(const std::string& type); template @@ -50,11 +50,11 @@ class RestStiffSpringsForceField_test : public BaseTest void checkDifference(MechanicalObject& mo); }; -RestStiffSpringsForceField_test::~RestStiffSpringsForceField_test() +FixedWeakConstraint_test::~FixedWeakConstraint_test() { } -sofa::simulation::Node::SPtr RestStiffSpringsForceField_test::createScene(const std::string& type) +sofa::simulation::Node::SPtr FixedWeakConstraint_test::createScene(const std::string& type) { const auto theSimulation = createSimulation(); auto theRoot = createRootNode(theSimulation, "root"); @@ -92,7 +92,7 @@ sofa::simulation::Node::SPtr RestStiffSpringsForceField_test::createScene(const } template -void RestStiffSpringsForceField_test::checkDifference(MechanicalObject& mo) +void FixedWeakConstraint_test::checkDifference(MechanicalObject& mo) { ReadAccessor< Data > positions = mo.x; ReadAccessor< Data > rest_positions = mo.x0; @@ -108,7 +108,7 @@ void RestStiffSpringsForceField_test::checkDifference(MechanicalObject& mo } template -void RestStiffSpringsForceField_test::testDefaultBehavior(sofa::simulation::Node::SPtr root) +void FixedWeakConstraint_test::testDefaultBehavior(sofa::simulation::Node::SPtr root) { auto fixedDofs = dynamic_cast*>(root->getChild("fixedObject")->getObject("dofs")); ASSERT_TRUE( fixedDofs != nullptr ); @@ -120,12 +120,12 @@ void RestStiffSpringsForceField_test::testDefaultBehavior(sofa::simulation::Node } -TEST_F(RestStiffSpringsForceField_test, defaultBehaviorVec3) +TEST_F(FixedWeakConstraint_test, defaultBehaviorVec3) { this->testDefaultBehavior(this->createScene("Vec3")); } -TEST_F(RestStiffSpringsForceField_test, defaultBehaviorRigid3) +TEST_F(FixedWeakConstraint_test, defaultBehaviorRigid3) { this->testDefaultBehavior(this->createScene("Rigid3")); } From f6bb00b02afafaedda59ee8c0103ecafce1b360d Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Fri, 26 Jul 2024 18:26:37 +0200 Subject: [PATCH 05/21] Added base virtualization for restShape spring forcefield. Still need to add inline method to regroup addForce implementations and apply it to RestShapeSpringsFF --- .../SolidMechanics/Spring/CMakeLists.txt | 2 + .../spring/BaseRestShapeSpringsForceField.h | 75 ++++++++++++++ .../spring/BaseRestShapeSpringsForceField.inl | 81 ++++++++++++++++ .../spring/FixedWeakConstraint.cpp | 3 +- .../spring/FixedWeakConstraint.h | 16 +-- .../spring/FixedWeakConstraint.inl | 97 ++++++++----------- .../spring/RestShapeSpringsForceField.h | 3 +- .../spring/RestShapeSpringsForceField.inl | 2 - 8 files changed, 207 insertions(+), 72 deletions(-) create mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h create mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl diff --git a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt index 4cb8698c1fe..2e947d48f65 100644 --- a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt +++ b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt @@ -10,6 +10,8 @@ set(HEADER_FILES ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/AngularSpringForceField.inl # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.h # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.inl + ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BaseRestShapeSpringsForceField.h + ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BaseRestShapeSpringsForceField.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.h ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FixedWeakConstraint.h diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h new file mode 100644 index 00000000000..293c182d324 --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h @@ -0,0 +1,75 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include + +namespace sofa::component::solidmechanics::spring { + +template +class BaseRestShapeSpringsForceField : public core::behavior::ForceField +{ + typedef core::behavior::ForceField Inherit; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename DataTypes::VecDeriv VecDeriv; + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::CPos CPos; + typedef typename DataTypes::Deriv Deriv; + typedef typename DataTypes::Real Real; + typedef type::vector< sofa::Index > VecIndex; + typedef sofa::core::topology::TopologySubsetIndices DataSubsetIndex; + typedef type::vector< Real > VecReal; +public: + + SOFA_CLASS(SOFA_TEMPLATE(BaseRestShapeSpringsForceField, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); + typedef sofa::core::topology::TopologySubsetIndices SetIndex; + + + SetIndex d_indices; + Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position + Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points + Data< bool > d_drawSpring; ///< draw Spring + Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) + + /// Link to be set to the topology container in the component graph. + SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; + + BaseRestShapeSpringsForceField(); + + virtual void init() override; + + virtual bool checkOutOfBoundsIndices() = 0; + + + +}; + +} + diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl new file mode 100644 index 00000000000..fd60b042965 --- /dev/null +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl @@ -0,0 +1,81 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include + +namespace sofa::component::solidmechanics::spring { + +template +BaseRestShapeSpringsForceField::BaseRestShapeSpringsForceField() + : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) + , d_stiffness(initData(&d_stiffness, {1.0},"stiffness", "stiffness value between the actual position and the rest shape position")) + , d_angularStiffness(initData(&d_angularStiffness,{1.0}, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) + , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) + , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) + , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) +{ + this->addUpdateCallback("updateInputs", {&d_indices}, [this](const core::DataTracker& t) + { + SOFA_UNUSED(t); + if(this->checkOutOfBoundsIndices()) + { + msg_error() << "Input indices out of bound"; + return sofa::core::objectmodel::ComponentState::Invalid; + } + + return sofa::core::objectmodel::ComponentState::Valid; + }, {}); +} + +template +void BaseRestShapeSpringsForceField::init() +{ + if(d_stiffness.getValue().size() != d_indices.getValue().size()) + { + msg_warning() << "Input stiffness isn't the same size as indices. Either shrinking it or copying the first value to match indices size."; + helper::WriteAccessor< Data > stiffness = d_stiffness; + const unsigned oldSize = stiffness.size(); + stiffness.resize(d_indices.getValue().size()); + for(unsigned i=oldSize; i< stiffness.size(); ++i) + { + stiffness[i] = stiffness[0]; + } + } + if constexpr (sofa::type::isRigidType()) + { + if (d_angularStiffness.getValue().size() != d_indices.getValue().size()) + { + msg_warning() << "Input angular stiffness isn't the same size as indices. Either shrinking it or copying the first value to match indices size."; + helper::WriteAccessor > stiffness = d_angularStiffness; + const unsigned oldSize = stiffness.size(); + stiffness.resize(d_indices.getValue().size()); + for(unsigned i=oldSize; i< stiffness.size(); ++i) + { + stiffness[i] = stiffness[0]; + } + } + } +} + +} \ No newline at end of file diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp index b67469aecd8..304992ce4b2 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace sofa::component::solidmechanics::spring @@ -34,7 +35,7 @@ namespace sofa::component::solidmechanics::spring using namespace sofa::type; using namespace sofa::defaulttype; -int FixedWeakConstraintClass = core::RegisterObject("Elastic springs generating forces on degrees of freedom between their current and rest shape position") +int FixedWeakConstraintClass = core::RegisterObject("Weak constraints fixing dofs at their rest shape using springs") .add< FixedWeakConstraint >() .add< FixedWeakConstraint >() .add< FixedWeakConstraint >() diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index c8bf8ef0f84..3b44cdb67fc 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace sofa::component::solidmechanics::spring @@ -41,10 +42,10 @@ namespace sofa::component::solidmechanics::spring * An external MechanicalState reference can also be passed to the ForceField as rest shape position. */ template -class FixedWeakConstraint : public core::behavior::ForceField +class FixedWeakConstraint : public BaseRestShapeSpringsForceField { public: - SOFA_CLASS(SOFA_TEMPLATE(FixedWeakConstraint, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); + SOFA_CLASS(SOFA_TEMPLATE(FixedWeakConstraint, DataTypes), SOFA_TEMPLATE(BaseRestShapeSpringsForceField, DataTypes)); typedef core::behavior::ForceField Inherit; typedef typename DataTypes::VecCoord VecCoord; @@ -65,20 +66,11 @@ class FixedWeakConstraint : public core::behavior::ForceField typedef sofa::core::topology::TopologySubsetIndices SetIndex; - SetIndex d_indices; Data d_fixAll; - Data< Real > d_stiffness; ///< stiffness values between the actual position and the rest shape position - Data< Real > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points - Data< bool > d_drawSpring; ///< draw Spring - Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) - - linearalgebra::EigenBaseSparseMatrix matS; - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; protected: FixedWeakConstraint(); - bool checkOutOfBoundsIndices(); + virtual bool checkOutOfBoundsIndices() override; public: virtual void init() override; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index ad17c811ca3..053a9e0d6fd 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -38,54 +38,37 @@ namespace sofa::component::solidmechanics::spring template FixedWeakConstraint::FixedWeakConstraint() - : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) - , d_fixAll(initData(&d_fixAll, false,"fixAll", "stiffness value between the actual position and the rest shape position")) - , d_stiffness(initData(&d_stiffness, 1.0,"stiffness", "stiffness value between the actual position and the rest shape position")) - , d_angularStiffness(initData(&d_angularStiffness,1.0, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) - , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) - , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) - , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) -{ - this->addUpdateCallback("updateInputs", {&d_indices}, [this](const core::DataTracker& t) - { - SOFA_UNUSED(t); - if(checkOutOfBoundsIndices()) - { - msg_error() << "Input indices out of bound"; - return sofa::core::objectmodel::ComponentState::Invalid; - } - - return sofa::core::objectmodel::ComponentState::Valid; - }, {}); -} + : d_fixAll(initData(&d_fixAll, false,"fixAll", "stiffness value between the actual position and the rest shape position")) +{} template void FixedWeakConstraint::init() { Inherit::init(); - if (l_topology.empty()) + if (this->l_topology.empty()) { msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); - if(! l_topology.get()) + this->l_topology.set(this->getContext()->getMeshTopologyLink()); + if(! this->l_topology.get()) this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); } - if (sofa::core::topology::BaseMeshTopology* _topology = l_topology.get()) + if (sofa::core::topology::BaseMeshTopology* _topology = this->l_topology.get()) { - msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; + msg_info() << "Topology path used: '" << this->l_topology.getLinkedPath() << "'"; // Initialize topological changes support - d_indices.createTopologyHandler(_topology); + this->d_indices.createTopologyHandler(_topology); } + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); } template bool FixedWeakConstraint::checkOutOfBoundsIndices() { - for(auto idx : d_indices.getValue()) + for(auto idx : this->d_indices.getValue()) { if(idx >= this->mstate->getSize()) return true; @@ -121,22 +104,22 @@ void FixedWeakConstraint::addForce(const core::MechanicalParams* mpa helper::ReadAccessor< DataVecCoord > p0 = *restPosition; - const Real& stiffness = d_stiffness.getValue(); - const Real& angularStiffness = d_angularStiffness.getValue(); + const auto& stiffness = this->d_stiffness.getValue(); + const auto& angularStiffness = this->d_angularStiffness.getValue(); f1.resize(p1.size()); - for (sofa::Index i = 0; i < d_indices.getValue().size(); i++) + for (sofa::Index i = 0; i < this->d_indices.getValue().size(); i++) { - const sofa::Index index = d_indices.getValue()[i]; + const sofa::Index index = this->d_indices.getValue()[i]; // rigid case if constexpr (sofa::type::isRigidType()) { // translation CPos dx = p1[index].getCenter() - p0[index].getCenter(); - getVCenter(f1[index]) -= dx * stiffness; + getVCenter(f1[index]) -= dx * stiffness[i]; // rotation type::Quat dq = p1[index].getOrientation() * p0[index].getOrientation().inverse(); @@ -153,12 +136,12 @@ void FixedWeakConstraint::addForce(const core::MechanicalParams* mpa if (dq[3] < 1.0) dq.quatToAxis(dir, angle); - getVOrientation(f1[index]) -= dir * angle * angularStiffness; + getVOrientation(f1[index]) -= dir * angle * angularStiffness[i]; } else // non-rigid implementation { Deriv dx = p1[index] - p0[index]; - f1[index] -= dx * stiffness; + f1[index] -= dx * stiffness[i]; } } } @@ -169,21 +152,21 @@ void FixedWeakConstraint::addDForce(const core::MechanicalParams* mpa helper::WriteAccessor< DataVecDeriv > df1 = df; helper::ReadAccessor< DataVecDeriv > dx1 = dx; Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - const Real& stiffness = d_stiffness.getValue(); - const Real& angularStiffness = d_angularStiffness.getValue(); + const auto& stiffness = this->d_stiffness.getValue(); + const auto& angularStiffness = this->d_angularStiffness.getValue(); - for (unsigned int i = 0; i < d_indices.getValue().size(); i++) + for (unsigned int i = 0; i < this->d_indices.getValue().size(); i++) { - const sofa::Index curIndex = d_indices.getValue()[i]; + const sofa::Index curIndex = this->d_indices.getValue()[i]; if constexpr (sofa::type::isRigidType()) { - getVCenter(df1[curIndex]) -= getVCenter(dx1[curIndex]) * stiffness * kFactor; - getVOrientation(df1[curIndex]) -= getVOrientation(dx1[curIndex]) * angularStiffness * kFactor; + getVCenter(df1[curIndex]) -= getVCenter(dx1[curIndex]) * stiffness[i] * kFactor; + getVOrientation(df1[curIndex]) -= getVOrientation(dx1[curIndex]) * angularStiffness[i] * kFactor; } else { - df1[d_indices.getValue()[i]] -= dx1[d_indices.getValue()[i]] * stiffness * kFactor; + df1[this->d_indices.getValue()[i]] -= dx1[this->d_indices.getValue()[i]] * stiffness[i] * kFactor; } } @@ -193,7 +176,7 @@ void FixedWeakConstraint::addDForce(const core::MechanicalParams* mpa template void FixedWeakConstraint::draw(const core::visual::VisualParams *vparams) { - if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) + if (!vparams->displayFlags().getShowForceFields() || !this->d_drawSpring.getValue()) return; const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); @@ -210,7 +193,7 @@ void FixedWeakConstraint::draw(const core::visual::VisualParams *vpa helper::ReadAccessor< DataVecCoord > p0 = *restPosition; helper::ReadAccessor< DataVecCoord > p = this->mstate->read(core::VecCoordId::position()); - const VecIndex& indices = d_indices.getValue(); + const VecIndex& indices = this->d_indices.getValue(); std::vector vertices; @@ -230,7 +213,7 @@ void FixedWeakConstraint::draw(const core::visual::VisualParams *vpa vertices.push_back(v1); } - vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); + vparams->drawTool()->drawLines(vertices,5, this->d_springColor.getValue()); } template @@ -241,20 +224,20 @@ void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* const unsigned int offset = mref.offset; Real kFact = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - const Real& k = d_stiffness.getValue(); - const Real& k_a = d_angularStiffness.getValue(); + const auto& k = this->d_stiffness.getValue(); + const auto& k_a = this->d_angularStiffness.getValue(); constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes constexpr sofa::Size total_size = Deriv::total_size; sofa::Index curIndex = 0; - for (sofa::Index index = 0; index < d_indices.getValue().size(); index++) + for (sofa::Index index = 0; index < this->d_indices.getValue().size(); index++) { - curIndex = d_indices.getValue()[index]; + curIndex = this->d_indices.getValue()[index]; // translation - const auto vt = -kFact * k; + const auto vt = -kFact * k[index]; for (sofa::Size i = 0; i < space_size; i++) { mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vt); @@ -263,7 +246,7 @@ void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* // rotation (if applicable) if constexpr (sofa::type::isRigidType()) { - const auto vr = -kFact * k_a; + const auto vr = -kFact * k_a[index]; for (sofa::Size i = space_size; i < total_size; i++) { mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vr); @@ -275,8 +258,8 @@ void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* template void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) { - const Real& vt = -d_stiffness.getValue(); - const Real& vr = -d_angularStiffness.getValue(); + const auto& vt = this->d_stiffness.getValue(); + const auto& vr = this->d_angularStiffness.getValue(); constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes constexpr sofa::Size total_size = Deriv::total_size; @@ -284,12 +267,16 @@ void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::Stiffn auto dfdx = matrix->getForceDerivativeIn(this->mstate) .withRespectToPositionsIn(this->mstate); - for (const auto index : d_indices.getValue()) + + const VecIndex& indices = this->d_indices.getValue(); + for (sofa::Index i=0; i::buildStiffnessMatrix(core::behavior::Stiffn { for (sofa::Size i = space_size; i < total_size; ++i) { - dfdx(total_size * index + i, total_size * index + i) += vr; + dfdx(total_size * index + i, total_size * index + i) += -vr[i]; } } } diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h index c08facb46d4..30236ea8f2e 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h @@ -128,12 +128,11 @@ protected : bool checkOutOfBoundsIndices(); bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); + VecIndex m_indices; VecIndex m_ext_indices; type::vector m_pivots; - SReal lastUpdatedStep{}; - private : bool useRestMState{}; /// An external MechanicalState is used as rest reference. diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl index 2c677371551..0491a081417 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl @@ -167,8 +167,6 @@ void RestShapeSpringsForceField::bwdInit() } } - lastUpdatedStep = -1.0; - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); } From 06090ff6297dd434a2a67a2b5fcb7a2d86a055b2 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Mon, 9 Dec 2024 12:08:23 +0100 Subject: [PATCH 06/21] WIP: SQtill need to unify inint, reinit, bwdinint, enables fixAll and apply it to RestShape --- .../SolidMechanics/Spring/CMakeLists.txt | 2 - .../spring/BaseRestShapeSpringsForceField.h | 75 --- .../spring/BaseRestShapeSpringsForceField.inl | 81 --- .../spring/FixedWeakConstraint.cpp | 22 +- .../spring/FixedWeakConstraint.h | 64 ++- .../spring/FixedWeakConstraint.inl | 467 ++++++++++++++---- 6 files changed, 441 insertions(+), 270 deletions(-) delete mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h delete mode 100644 Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl diff --git a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt index 586b615587c..42954ca0934 100644 --- a/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt +++ b/Sofa/Component/SolidMechanics/Spring/CMakeLists.txt @@ -10,8 +10,6 @@ set(HEADER_FILES ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/AngularSpringForceField.inl # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.h # ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BoxStiffSpringForceField.inl - ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BaseRestShapeSpringsForceField.h - ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/BaseRestShapeSpringsForceField.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.h ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FastTriangularBendingSprings.inl ${SOFACOMPONENTSOLIDMECHANICSSPRING_SOURCE_DIR}/FixedWeakConstraint.h diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h deleted file mode 100644 index 293c182d324..00000000000 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.h +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#include - -#include -#include -#include -#include -#include - -namespace sofa::component::solidmechanics::spring { - -template -class BaseRestShapeSpringsForceField : public core::behavior::ForceField -{ - typedef core::behavior::ForceField Inherit; - typedef typename DataTypes::VecCoord VecCoord; - typedef typename DataTypes::VecDeriv VecDeriv; - typedef typename DataTypes::Coord Coord; - typedef typename DataTypes::CPos CPos; - typedef typename DataTypes::Deriv Deriv; - typedef typename DataTypes::Real Real; - typedef type::vector< sofa::Index > VecIndex; - typedef sofa::core::topology::TopologySubsetIndices DataSubsetIndex; - typedef type::vector< Real > VecReal; -public: - - SOFA_CLASS(SOFA_TEMPLATE(BaseRestShapeSpringsForceField, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); - typedef sofa::core::topology::TopologySubsetIndices SetIndex; - - - SetIndex d_indices; - Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position - Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points - Data< bool > d_drawSpring; ///< draw Spring - Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) - - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; - - BaseRestShapeSpringsForceField(); - - virtual void init() override; - - virtual bool checkOutOfBoundsIndices() = 0; - - - -}; - -} - diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl deleted file mode 100644 index fd60b042965..00000000000 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/BaseRestShapeSpringsForceField.inl +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include -#include - -namespace sofa::component::solidmechanics::spring { - -template -BaseRestShapeSpringsForceField::BaseRestShapeSpringsForceField() - : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) - , d_stiffness(initData(&d_stiffness, {1.0},"stiffness", "stiffness value between the actual position and the rest shape position")) - , d_angularStiffness(initData(&d_angularStiffness,{1.0}, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) - , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) - , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) - , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) -{ - this->addUpdateCallback("updateInputs", {&d_indices}, [this](const core::DataTracker& t) - { - SOFA_UNUSED(t); - if(this->checkOutOfBoundsIndices()) - { - msg_error() << "Input indices out of bound"; - return sofa::core::objectmodel::ComponentState::Invalid; - } - - return sofa::core::objectmodel::ComponentState::Valid; - }, {}); -} - -template -void BaseRestShapeSpringsForceField::init() -{ - if(d_stiffness.getValue().size() != d_indices.getValue().size()) - { - msg_warning() << "Input stiffness isn't the same size as indices. Either shrinking it or copying the first value to match indices size."; - helper::WriteAccessor< Data > stiffness = d_stiffness; - const unsigned oldSize = stiffness.size(); - stiffness.resize(d_indices.getValue().size()); - for(unsigned i=oldSize; i< stiffness.size(); ++i) - { - stiffness[i] = stiffness[0]; - } - } - if constexpr (sofa::type::isRigidType()) - { - if (d_angularStiffness.getValue().size() != d_indices.getValue().size()) - { - msg_warning() << "Input angular stiffness isn't the same size as indices. Either shrinking it or copying the first value to match indices size."; - helper::WriteAccessor > stiffness = d_angularStiffness; - const unsigned oldSize = stiffness.size(); - stiffness.resize(d_indices.getValue().size()); - for(unsigned i=oldSize; i< stiffness.size(); ++i) - { - stiffness[i] = stiffness[0]; - } - } - } -} - -} \ No newline at end of file diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp index 304992ce4b2..7a2c57d84ba 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.cpp @@ -19,36 +19,30 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#define SOFA_COMPONENT_FORCEFIELD_RESTSHAPESPRINGSFORCEFIELD_CPP +#define SOFA_COMPONENT_FORCEFIELD_FixedWeakConstraint_CPP #include #include #include #include -#include namespace sofa::component::solidmechanics::spring { -using namespace sofa::type; using namespace sofa::defaulttype; -int FixedWeakConstraintClass = core::RegisterObject("Weak constraints fixing dofs at their rest shape using springs") - .add< FixedWeakConstraint >() - .add< FixedWeakConstraint >() - .add< FixedWeakConstraint >() - .add< FixedWeakConstraint >() - .add< FixedWeakConstraint >() - - ; +void registerFixedWeakConstraint(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Elastic springs generating forces on degrees of freedom between their current and rest shape position.") + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >() + .add< FixedWeakConstraint >()); +} -template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; -template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; - } // namespace sofa::component::solidmechanics::spring diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index 3b44cdb67fc..c94944d1894 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -29,9 +29,15 @@ #include #include #include -#include +namespace sofa::core::behavior +{ + +template< class T > class MechanicalState; + +} // namespace sofa::core::behavior + namespace sofa::component::solidmechanics::spring { @@ -40,12 +46,12 @@ namespace sofa::component::solidmechanics::spring * * Springs are applied to given degrees of freedom between their current positions and their rest shape positions. * An external MechanicalState reference can also be passed to the ForceField as rest shape position. -*/ + */ template -class FixedWeakConstraint : public BaseRestShapeSpringsForceField +class FixedWeakConstraint : public core::behavior::ForceField { -public: - SOFA_CLASS(SOFA_TEMPLATE(FixedWeakConstraint, DataTypes), SOFA_TEMPLATE(BaseRestShapeSpringsForceField, DataTypes)); + public: + SOFA_CLASS(SOFA_TEMPLATE(FixedWeakConstraint, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); typedef core::behavior::ForceField Inherit; typedef typename DataTypes::VecCoord VecCoord; @@ -64,21 +70,39 @@ class FixedWeakConstraint : public BaseRestShapeSpringsForceField typedef core::objectmodel::Data DataVecCoord; typedef core::objectmodel::Data DataVecDeriv; - typedef sofa::core::topology::TopologySubsetIndices SetIndex; + DataSubsetIndex d_points; ///< points controlled by the rest shape springs + Data d_fixAll; ///< points controlled by the rest shape springs + Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position + Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points + Data< bool > d_drawSpring; ///< draw Spring + Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) - Data d_fixAll; -protected: + protected: FixedWeakConstraint(); - virtual bool checkOutOfBoundsIndices() override; -public: - virtual void init() override; + static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); + + public: + /// BaseObject initialization method. + void bwdInit() override ; + void reinit() override ; /// Add the forces. void addForce(const core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v) override; + /// Link to be set to the topology container in the component graph. + SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; + void addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) override; - SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override; + + SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override + { + SOFA_UNUSED(mparams); + SOFA_UNUSED(x); + + msg_warning() << "Method getPotentialEnergy not implemented yet."; + return 0.0; + } /// Brings ForceField contribution to the global system stiffness matrix. void addKToMatrix(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix ) override; @@ -88,12 +112,22 @@ class FixedWeakConstraint : public BaseRestShapeSpringsForceField void draw(const core::visual::VisualParams* vparams) override; + virtual const DataVecCoord* getExtPosition() const; + virtual const VecIndex& getIndices() const; + virtual const VecIndex& getExtIndices() const; + virtual const type::fixed_array& getActiveDirections() const; + + protected : + + void recomputeIndices(); + virtual bool checkOutOfBoundsIndices(); + bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); + + }; -#if !defined(SOFA_COMPONENT_FORCEFIELD_RESTSHAPESPRINGSFORCEFIELD_CPP) -extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; +#if !defined(SOFA_COMPONENT_FORCEFIELD_FixedWeakConstraint_CPP) extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; -extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; extern template class SOFA_COMPONENT_SOLIDMECHANICS_SPRING_API FixedWeakConstraint; #endif diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index 053a9e0d6fd..9453ba7222c 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -36,93 +36,325 @@ namespace sofa::component::solidmechanics::spring { +using helper::WriteAccessor; +using helper::ReadAccessor; +using core::behavior::BaseMechanicalState; +using core::behavior::MultiMatrixAccessor; +using core::behavior::ForceField; +using linearalgebra::BaseMatrix; +using core::VecCoordId; +using core::MechanicalParams; +using type::Vec3; +using type::Vec4f; +using type::vector; +using core::visual::VisualParams; + template FixedWeakConstraint::FixedWeakConstraint() - : d_fixAll(initData(&d_fixAll, false,"fixAll", "stiffness value between the actual position and the rest shape position")) -{} + : d_points(initData(&d_points, "points", "points controlled by the rest shape springs")) + , d_fixAll(initData(&d_fixAll, false, "fixAll", "Force to fix all points")) + , d_stiffness(initData(&d_stiffness, "stiffness", "stiffness values between the actual position and the rest shape position")) + , d_angularStiffness(initData(&d_angularStiffness, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) + , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) + , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) + , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) +{ + this->addUpdateCallback("updateIndices", {&d_points}, [this](const core::DataTracker& t) + { + SOFA_UNUSED(t); + this->recomputeIndices(); + return sofa::core::objectmodel::ComponentState::Valid; + }, {}); +} template -void FixedWeakConstraint::init() +void FixedWeakConstraint::bwdInit() { - Inherit::init(); - if (this->l_topology.empty()) + ForceField::init(); + + if (d_stiffness.getValue().empty()) + { + msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 "; + d_stiffness.setValue({static_cast(100)}); + } + + if (l_restMState.get() == nullptr) + { + useRestMState = false; + msg_info() << "no external rest shape used"; + + if(!l_restMState.empty()) + { + msg_warning() << "external_rest_shape in node " << this->getContext()->getName() << " not found"; + } + } + else + { + msg_info() << "external rest shape used"; + useRestMState = true; + } + + if (l_topology.empty()) { msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - this->l_topology.set(this->getContext()->getMeshTopologyLink()); - if(! this->l_topology.get()) - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + l_topology.set(this->getContext()->getMeshTopologyLink()); } - if (sofa::core::topology::BaseMeshTopology* _topology = this->l_topology.get()) + if (sofa::core::topology::BaseMeshTopology* _topology = l_topology.get()) { - msg_info() << "Topology path used: '" << this->l_topology.getLinkedPath() << "'"; + msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; // Initialize topological changes support - this->d_indices.createTopologyHandler(_topology); + d_points.createTopologyHandler(_topology); + } + else + { + msg_info() << "Cannot find the topology: topological changes will not be supported"; } + recomputeIndices(); + if (this->d_componentState.getValue() == sofa::core::objectmodel::ComponentState::Invalid) + return; + + const BaseMechanicalState* state = this->getContext()->getMechanicalState(); + if(!state) + { + msg_warning() << "MechanicalState of the current context returns null pointer"; + } + else + { + assert(state); + matS.resize(state->getMatrixSize(),state->getMatrixSize()); + } + + /// Compile time condition to check if we are working with a Rigid3Types or a type that does not + /// need the Angular Stiffness parameters. + //if constexpr (isRigid()) + if constexpr (sofa::type::isRigidType()) + { + sofa::helper::ReadAccessor> s = d_stiffness; + sofa::helper::WriteOnlyAccessor> as = d_angularStiffness; + + if (as.size() < s.size()) + { + msg_info() << "'stiffness' is larger than 'angularStiffness', add the default value (100.0) to the missing entries."; + + for(size_t i = as.size();i s.size()) + { + msg_info() << "'stiffness' is smaller than 'angularStiffness', clamp the extra values in angularStiffness."; + as.resize(s.size()); + } + } this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); } + +template +void FixedWeakConstraint::reinit() +{ + if (!checkOutOfBoundsIndices()) + { + m_indices.clear(); + } + else + { + msg_info() << "Indices successfully checked"; + } + + if (d_stiffness.getValue().empty()) + { + msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 " ; + + VecReal stiffs; + stiffs.push_back(100.0); + d_stiffness.setValue(stiffs); + } + else + { + const VecReal &k = d_stiffness.getValue(); + if ( k.size() != m_indices.size() ) + { + msg_warning() << "Size of stiffness vector is not correct (" << k.size() << "), should be either 1 or " << m_indices.size() << msgendl + << "First value of stiffness will be used"; + } + } + +} + +template +void FixedWeakConstraint::recomputeIndices() +{ + m_indices.clear(); + m_ext_indices.clear(); + + for (const sofa::Index i : d_points.getValue()) + { + m_indices.push_back(i); + } + + for (const sofa::Index i : d_external_points.getValue()) + { + m_ext_indices.push_back(i); + } + + if (m_indices.empty()) + { + // no point are defined, default case: points = all points + msg_info() << "No point are defined. Change to default case: points = all points"; + for (sofa::Index i = 0; i < this->mstate->getSize(); i++) + { + m_indices.push_back(i); + } + } + + if (m_ext_indices.empty()) + { + if (useRestMState) + { + if (const DataVecCoord* extPosition = getExtPosition()) + { + const auto& extPositionValue = extPosition->getValue(); + for (sofa::Index i = 0; i < extPositionValue.size(); i++) + { + m_ext_indices.push_back(i); + } + } + else + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + } + } + else + { + for (const sofa::Index i : m_indices) + { + m_ext_indices.push_back(i); + } + } + } + + if (!checkOutOfBoundsIndices()) + { + msg_error() << "The dimension of the source and the targeted points are different "; + m_indices.clear(); + } + else + { + msg_info() << "Indices successfully checked"; + } +} + template bool FixedWeakConstraint::checkOutOfBoundsIndices() { - for(auto idx : this->d_indices.getValue()) + if (!checkOutOfBoundsIndices(getIndices(), this->mstate->getSize())) { - if(idx >= this->mstate->getSize()) - return true; + msg_error() << "Out of Bounds d_indices detected. ForceField is not activated."; + return false; } - return false; + return true; } template -SReal FixedWeakConstraint::getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const +bool FixedWeakConstraint::checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension) { - SOFA_UNUSED(mparams); - SOFA_UNUSED(x); + for (sofa::Index i = 0; i < indices.size(); i++) + { + if (indices[i] >= dimension) + { + return false; + } + } + return true; +} - msg_warning() << "Method getPotentialEnergy not implemented yet."; - return 0.0; +template +const typename FixedWeakConstraint::DataVecCoord* FixedWeakConstraint::getExtPosition() const +{ + if (this->mstate) + { + return this->mstate->read(core::vec_id::write_access::restPosition); + } + return nullptr; +} + +template +const FixedWeakConstraint::VecIndex& FixedWeakConstraint::getIndices() const +{ + + return d_points.getValue(); +} + +template +const FixedWeakConstraint::VecIndex& FixedWeakConstraint::getExtIndices() const +{ + return d_points.getValue(); } template -void FixedWeakConstraint::addForce(const core::MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) +const type::fixed_array::coord_total_size>& FixedWeakConstraint::getActiveDirections() const +{ + return s_defaultActiveDirections; +} + +template +void FixedWeakConstraint::addForce(const MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) { SOFA_UNUSED(mparams); SOFA_UNUSED(v); - helper::WriteAccessor< DataVecDeriv > f1 = f; - helper::ReadAccessor< DataVecCoord > p1 = x; + WriteAccessor< DataVecDeriv > f1 = f; + ReadAccessor< DataVecCoord > p1 = x; - const DataVecCoord * restPosition = this->mstate->read(sofa::core::VecId::resetPosition()); - if (!restPosition) + const DataVecCoord* extPosition = getExtPosition(); + const auto & indices = getIndices(); + const auto & extIndices = getExtIndices(); + if (!extPosition) { this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); return; } - helper::ReadAccessor< DataVecCoord > p0 = *restPosition; + ReadAccessor< DataVecCoord > p0 = *extPosition; - const auto& stiffness = this->d_stiffness.getValue(); - const auto& angularStiffness = this->d_angularStiffness.getValue(); + const VecReal& k = d_stiffness.getValue(); + const VecReal& k_a = d_angularStiffness.getValue(); - f1.resize(p1.size()); + f1.resize(p1.size()); - for (sofa::Index i = 0; i < this->d_indices.getValue().size(); i++) + for (sofa::Index i = 0; i < indices.size(); i++) { - const sofa::Index index = this->d_indices.getValue()[i]; + const sofa::Index index = indices[i]; + sofa::Index ext_index = extIndices[i]; + + const auto stiffness = k[static_cast(i < k.size()) * i]; + + const auto & activeDirections = getActiveDirections(); // rigid case if constexpr (sofa::type::isRigidType()) { - // translation - CPos dx = p1[index].getCenter() - p0[index].getCenter(); - getVCenter(f1[index]) -= dx * stiffness[i]; + + CPos dx = p1[index].getCenter() - p0[ext_index].getCenter(); + // We filter the difference dx by setting to 0 the entries corresponding + // to 0 values in d_activeDirections + for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) + { + if (!activeDirections[entryId]) + dx[entryId] = 0; + } + getVCenter(f1[index]) -= dx * stiffness; + + // rotation - type::Quat dq = p1[index].getOrientation() * p0[index].getOrientation().inverse(); + type::Quat dq = p1[index].getOrientation() * p0[ext_index].getOrientation().inverse(); dq.normalize(); type::Vec<3, Real> dir{type::NOINIT}; @@ -136,37 +368,90 @@ void FixedWeakConstraint::addForce(const core::MechanicalParams* mpa if (dq[3] < 1.0) dq.quatToAxis(dir, angle); - getVOrientation(f1[index]) -= dir * angle * angularStiffness[i]; + // We change the direction of the axis of rotation based on + // the 0 values in d_activeDirections. This is equivalent + // to senting to 0 the rotation axis components along x, y + // and/or z, depending on the rotations we want to take into + // account. + for (sofa::Size entryId = spatial_dimensions; entryId < coord_total_size; ++entryId) + { + if (!activeDirections[entryId]) + dir[entryId-spatial_dimensions] = 0; + } + + const auto angularStiffness = k_a[static_cast(i < k_a.size()) * i]; + getVOrientation(f1[index]) -= dir * angle * angularStiffness; } else // non-rigid implementation { - Deriv dx = p1[index] - p0[index]; - f1[index] -= dx * stiffness[i]; + Deriv dx = p1[index] - p0[ext_index]; + // We filter the difference dx by setting to 0 the entries corresponding + // to 0 values in d_activeDirections + for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) + { + if (!activeDirections[entryId]) + dx[entryId] = 0; + } + f1[index] -= dx * stiffness; } } } template -void FixedWeakConstraint::addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) +void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) { - helper::WriteAccessor< DataVecDeriv > df1 = df; - helper::ReadAccessor< DataVecDeriv > dx1 = dx; + WriteAccessor< DataVecDeriv > df1 = df; + ReadAccessor< DataVecDeriv > dx1 = dx; Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - const auto& stiffness = this->d_stiffness.getValue(); - const auto& angularStiffness = this->d_angularStiffness.getValue(); + const VecReal& k = d_stiffness.getValue(); + const VecReal& k_a = d_angularStiffness.getValue(); + const auto & activeDirections = getActiveDirections(); + + const auto & indices = getIndices(); - for (unsigned int i = 0; i < this->d_indices.getValue().size(); i++) + for (unsigned int i = 0; i < indices.size(); i++) { - const sofa::Index curIndex = this->d_indices.getValue()[i]; + const sofa::Index curIndex = indices[i]; + const auto stiffness = k[static_cast(i < k.size()) * i]; if constexpr (sofa::type::isRigidType()) { - getVCenter(df1[curIndex]) -= getVCenter(dx1[curIndex]) * stiffness[i] * kFactor; - getVOrientation(df1[curIndex]) -= getVOrientation(dx1[curIndex]) * angularStiffness[i] * kFactor; + const auto angularStiffness = k_a[static_cast(i < k_a.size()) * i]; + + // We filter the difference in translation by setting to 0 the entries corresponding + // to 0 values in d_activeDirections + auto currentSpringDx = getVCenter(dx1[curIndex]); + for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) + { + if (!activeDirections[entryId]) + currentSpringDx[entryId] = 0; + } + getVCenter(df1[curIndex]) -= currentSpringDx * stiffness * kFactor; + + auto currentSpringRotationalDx = getVOrientation(dx1[curIndex]); + // We change the direction of the axis of rotation based on + // the 0 values in d_activeDirections. This is equivalent + // to senting to 0 the rotation axis components along x, y + // and/or z, depending on the rotations we want to take into + // account. + for (sofa::Size entryId = spatial_dimensions; entryId < coord_total_size; ++entryId) + { + if (!activeDirections[entryId]) + currentSpringRotationalDx[entryId-spatial_dimensions] = 0; + } + getVOrientation(df1[curIndex]) -= currentSpringRotationalDx * angularStiffness * kFactor; } else { - df1[this->d_indices.getValue()[i]] -= dx1[this->d_indices.getValue()[i]] * stiffness[i] * kFactor; + // We filter the difference in translation by setting to 0 the entries corresponding + // to 0 values in d_activeDirections + auto currentSpringDx = dx1[indices[i]]; + for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) + { + if (!activeDirections[entryId]) + currentSpringDx[entryId] = 0; + } + df1[indices[i]] -= currentSpringDx * stiffness * kFactor; } } @@ -174,82 +459,93 @@ void FixedWeakConstraint::addDForce(const core::MechanicalParams* mpa } template -void FixedWeakConstraint::draw(const core::visual::VisualParams *vparams) +void FixedWeakConstraint::draw(const VisualParams *vparams) { - if (!vparams->displayFlags().getShowForceFields() || !this->d_drawSpring.getValue()) - return; + if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) + return; /// \todo put this in the parent class const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); vparams->drawTool()->setLightingEnabled(false); - const DataVecCoord * restPosition = this->mstate->read(sofa::core::VecId::resetPosition()); - if (!restPosition) + const DataVecCoord* extPosition = getExtPosition(); + if (!extPosition) { this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); return; } + ReadAccessor< DataVecCoord > p0 = *extPosition; + ReadAccessor< DataVecCoord > p = this->mstate->read(sofa::core::vec_id::write_access::position); - helper::ReadAccessor< DataVecCoord > p0 = *restPosition; - helper::ReadAccessor< DataVecCoord > p = this->mstate->read(core::VecCoordId::position()); + const auto & indices = getIndices(); + const auto & extIndices = getExtIndices(); - const VecIndex& indices = this->d_indices.getValue(); - - std::vector vertices; + std::vector vertices; for (sofa::Index i=0; i(3)) ; j++) { v0[j] = (DataTypes::getCPos(p[index]))[j]; - v1[j] = (DataTypes::getCPos(p0[index]))[j]; + v1[j] = (DataTypes::getCPos(p0[ext_index]))[j]; } vertices.push_back(v0); vertices.push_back(v1); } - vparams->drawTool()->drawLines(vertices,5, this->d_springColor.getValue()); + //todo(dmarchal) because of https://github.com/sofa-framework/sofa/issues/64 + vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); + } template -void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* mparams, const core::behavior::MultiMatrixAccessor* matrix ) +void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) { - const core::behavior::MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); - linearalgebra::BaseMatrix* mat = mref.matrix; + const MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); + BaseMatrix* mat = mref.matrix; const unsigned int offset = mref.offset; Real kFact = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - const auto& k = this->d_stiffness.getValue(); - const auto& k_a = this->d_angularStiffness.getValue(); + const VecReal& k = d_stiffness.getValue(); + const VecReal& k_a = d_angularStiffness.getValue(); + const auto & activeDirections = getActiveDirections(); + const auto & indices = getIndices(); constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes constexpr sofa::Size total_size = Deriv::total_size; sofa::Index curIndex = 0; - for (sofa::Index index = 0; index < this->d_indices.getValue().size(); index++) + for (sofa::Index index = 0; index < indices.size(); index++) { - curIndex = this->d_indices.getValue()[index]; + curIndex = indices[index]; // translation - const auto vt = -kFact * k[index]; + const auto vt = -kFact * k[(index < k.size()) * index]; for (sofa::Size i = 0; i < space_size; i++) { - mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vt); + // Contribution to the stiffness matrix are only taken into + // account for 1 values in d_activeDirections + if (activeDirections[i]) + mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vt); } // rotation (if applicable) if constexpr (sofa::type::isRigidType()) { - const auto vr = -kFact * k_a[index]; + const auto vr = -kFact * k_a[(index < k_a.size()) * index]; for (sofa::Size i = space_size; i < total_size; i++) { - mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vr); + // Contribution to the stiffness matrix are only taken into + // account for 1 values in d_activeDirections + if (activeDirections[i]) + mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vr); } } } @@ -258,33 +554,38 @@ void FixedWeakConstraint::addKToMatrix(const core::MechanicalParams* template void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) { - const auto& vt = this->d_stiffness.getValue(); - const auto& vr = this->d_angularStiffness.getValue(); + const VecReal& k = d_stiffness.getValue(); + const VecReal& k_a = d_angularStiffness.getValue(); + const auto & activeDirections = getActiveDirections(); + const auto & indices = getIndices(); constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes constexpr sofa::Size total_size = Deriv::total_size; auto dfdx = matrix->getForceDerivativeIn(this->mstate) - .withRespectToPositionsIn(this->mstate); + .withRespectToPositionsIn(this->mstate); - - const VecIndex& indices = this->d_indices.getValue(); - for (sofa::Index i=0; i()) { + const auto vr = -k_a[(index < k_a.size()) * index]; for (sofa::Size i = space_size; i < total_size; ++i) { - dfdx(total_size * index + i, total_size * index + i) += -vr[i]; + // Contribution to the stiffness matrix are only taken into + // account for 1 values in d_activeDirections + if (activeDirections[i]) + { + dfdx(total_size * index + i, total_size * index + i) += vr; + } } } } From 909c760e1163551331beb1e4003b607a8753ab76 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 10 Dec 2024 12:11:07 +0100 Subject: [PATCH 07/21] Factorise every method in the FixedWeakConstraint object. Need to specialize it inside the RestShapeSpringForcefield --- .../spring/FixedWeakConstraint.h | 13 +- .../spring/FixedWeakConstraint.inl | 311 ++++++++---------- .../component/solidmechanics/spring/init.cpp | 2 + 3 files changed, 146 insertions(+), 180 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index c94944d1894..28913e39618 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -70,7 +70,7 @@ class FixedWeakConstraint : public core::behavior::ForceField typedef core::objectmodel::Data DataVecCoord; typedef core::objectmodel::Data DataVecDeriv; - DataSubsetIndex d_points; ///< points controlled by the rest shape springs + DataSubsetIndex d_indices; ///< points controlled by the rest shape springs Data d_fixAll; ///< points controlled by the rest shape springs Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points @@ -80,9 +80,9 @@ class FixedWeakConstraint : public core::behavior::ForceField protected: FixedWeakConstraint(); - static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); + public: /// BaseObject initialization method. void bwdInit() override ; @@ -112,17 +112,16 @@ class FixedWeakConstraint : public core::behavior::ForceField void draw(const core::visual::VisualParams* vparams) override; + protected : + virtual const DataVecCoord* getExtPosition() const; virtual const VecIndex& getIndices() const; virtual const VecIndex& getExtIndices() const; virtual const type::fixed_array& getActiveDirections() const; + virtual const bool checkState(); - protected : - - void recomputeIndices(); - virtual bool checkOutOfBoundsIndices(); bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); - + virtual bool checkOutOfBoundsIndices(); }; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index 9453ba7222c..bcfd747d507 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -49,9 +49,10 @@ using type::Vec4f; using type::vector; using core::visual::VisualParams; + template FixedWeakConstraint::FixedWeakConstraint() - : d_points(initData(&d_points, "points", "points controlled by the rest shape springs")) + : d_indices(initData(&d_indices, "indices", "points controlled by the rest shape springs")) , d_fixAll(initData(&d_fixAll, false, "fixAll", "Force to fix all points")) , d_stiffness(initData(&d_stiffness, "stiffness", "stiffness values between the actual position and the rest shape position")) , d_angularStiffness(initData(&d_angularStiffness, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) @@ -59,41 +60,31 @@ FixedWeakConstraint::FixedWeakConstraint() , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) { - this->addUpdateCallback("updateIndices", {&d_points}, [this](const core::DataTracker& t) + this->addUpdateCallback("updateIndices", {&d_indices}, [this](const core::DataTracker& t) { SOFA_UNUSED(t); - this->recomputeIndices(); - return sofa::core::objectmodel::ComponentState::Valid; + if (!checkOutOfBoundsIndices()) + { + msg_error(this) << "Some input indices are out of bound"; + return sofa::core::objectmodel::ComponentState::Invalid; + } + else + { + return sofa::core::objectmodel::ComponentState::Valid; + } }, {}); } + template -void FixedWeakConstraint::bwdInit() +const bool FixedWeakConstraint::checkState() { - ForceField::init(); - if (d_stiffness.getValue().empty()) { msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 "; d_stiffness.setValue({static_cast(100)}); } - if (l_restMState.get() == nullptr) - { - useRestMState = false; - msg_info() << "no external rest shape used"; - - if(!l_restMState.empty()) - { - msg_warning() << "external_rest_shape in node " << this->getContext()->getName() << " not found"; - } - } - else - { - msg_info() << "external rest shape used"; - useRestMState = true; - } - if (l_topology.empty()) { msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; @@ -105,27 +96,14 @@ void FixedWeakConstraint::bwdInit() msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; // Initialize topological changes support - d_points.createTopologyHandler(_topology); + d_indices.createTopologyHandler(_topology); } else { msg_info() << "Cannot find the topology: topological changes will not be supported"; } - recomputeIndices(); - if (this->d_componentState.getValue() == sofa::core::objectmodel::ComponentState::Invalid) - return; - const BaseMechanicalState* state = this->getContext()->getMechanicalState(); - if(!state) - { - msg_warning() << "MechanicalState of the current context returns null pointer"; - } - else - { - assert(state); - matS.resize(state->getMatrixSize(),state->getMatrixSize()); - } /// Compile time condition to check if we are working with a Rigid3Types or a type that does not /// need the Angular Stiffness parameters. @@ -150,111 +128,57 @@ void FixedWeakConstraint::bwdInit() } } - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); -} - - -template -void FixedWeakConstraint::reinit() -{ if (!checkOutOfBoundsIndices()) { - m_indices.clear(); - } - else - { - msg_info() << "Indices successfully checked"; - } - - if (d_stiffness.getValue().empty()) - { - msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 " ; - - VecReal stiffs; - stiffs.push_back(100.0); - d_stiffness.setValue(stiffs); + return false; } else { - const VecReal &k = d_stiffness.getValue(); - if ( k.size() != m_indices.size() ) - { - msg_warning() << "Size of stiffness vector is not correct (" << k.size() << "), should be either 1 or " << m_indices.size() << msgendl - << "First value of stiffness will be used"; - } + return true; } - } template -void FixedWeakConstraint::recomputeIndices() +void FixedWeakConstraint::bwdInit() { - m_indices.clear(); - m_ext_indices.clear(); + ForceField::init(); - for (const sofa::Index i : d_points.getValue()) + if (checkState()) { - m_indices.push_back(i); + this->d_componentState.setValue(core::objectmodel::ComponentState::Valid); } - - for (const sofa::Index i : d_external_points.getValue()) + else { - m_ext_indices.push_back(i); - } + this->d_componentState.setValue(core::objectmodel::ComponentState::Invalid); - if (m_indices.empty()) - { - // no point are defined, default case: points = all points - msg_info() << "No point are defined. Change to default case: points = all points"; - for (sofa::Index i = 0; i < this->mstate->getSize(); i++) - { - m_indices.push_back(i); - } } +} - if (m_ext_indices.empty()) - { - if (useRestMState) - { - if (const DataVecCoord* extPosition = getExtPosition()) - { - const auto& extPositionValue = extPosition->getValue(); - for (sofa::Index i = 0; i < extPositionValue.size(); i++) - { - m_ext_indices.push_back(i); - } - } - else - { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - } - } - else - { - for (const sofa::Index i : m_indices) - { - m_ext_indices.push_back(i); - } - } - } - if (!checkOutOfBoundsIndices()) +template +void FixedWeakConstraint::reinit() +{ + ForceField::reinit(); + + if (checkState()) { - msg_error() << "The dimension of the source and the targeted points are different "; - m_indices.clear(); + this->d_componentState.setValue(core::objectmodel::ComponentState::Valid); } else { - msg_info() << "Indices successfully checked"; + this->d_componentState.setValue(core::objectmodel::ComponentState::Invalid); + } + } + + template bool FixedWeakConstraint::checkOutOfBoundsIndices() { if (!checkOutOfBoundsIndices(getIndices(), this->mstate->getSize())) { - msg_error() << "Out of Bounds d_indices detected. ForceField is not activated."; return false; } return true; @@ -284,22 +208,22 @@ const typename FixedWeakConstraint::DataVecCoord* FixedWeakConstraint } template -const FixedWeakConstraint::VecIndex& FixedWeakConstraint::getIndices() const +const typename FixedWeakConstraint::VecIndex& FixedWeakConstraint::getIndices() const { - return d_points.getValue(); + return d_indices.getValue(); } template -const FixedWeakConstraint::VecIndex& FixedWeakConstraint::getExtIndices() const +const typename FixedWeakConstraint::VecIndex& FixedWeakConstraint::getExtIndices() const { - return d_points.getValue(); + return d_indices.getValue(); } template const type::fixed_array::coord_total_size>& FixedWeakConstraint::getActiveDirections() const { - return s_defaultActiveDirections; + return FixedWeakConstraint::s_defaultActiveDirections; } template @@ -328,10 +252,19 @@ void FixedWeakConstraint::addForce(const MechanicalParams* mparams , f1.resize(p1.size()); - for (sofa::Index i = 0; i < indices.size(); i++) + const bool fixedAll = d_fixAll.getValue(); + const unsigned maxIt = fixedAll ? this->mstate->getSize() : indices.size(); + + for (sofa::Index i = 0; i < maxIt; i++) { - const sofa::Index index = indices[i]; - sofa::Index ext_index = extIndices[i]; + sofa::Index ext_index = i; + sofa::Index index = i; + + if (!fixedAll) + { + index = indices[i]; + ext_index = extIndices[i]; + } const auto stiffness = k[static_cast(i < k.size()) * i]; @@ -409,9 +342,18 @@ void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, const auto & indices = getIndices(); - for (unsigned int i = 0; i < indices.size(); i++) + const bool fixedAll = d_fixAll.getValue(); + const unsigned maxIt = fixedAll ? this->mstate->getSize() : indices.size(); + + for (sofa::Index i = 0; i < maxIt; i++) { - const sofa::Index curIndex = indices[i]; + sofa::Index curIndex = i; + + if (!fixedAll) + { + curIndex = indices[i]; + } + const auto stiffness = k[static_cast(i < k.size()) * i]; if constexpr (sofa::type::isRigidType()) @@ -445,64 +387,19 @@ void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, { // We filter the difference in translation by setting to 0 the entries corresponding // to 0 values in d_activeDirections - auto currentSpringDx = dx1[indices[i]]; + auto currentSpringDx = dx1[curIndex]; for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) { if (!activeDirections[entryId]) currentSpringDx[entryId] = 0; } - df1[indices[i]] -= currentSpringDx * stiffness * kFactor; + df1[curIndex] -= currentSpringDx * stiffness * kFactor; } } } -template -void FixedWeakConstraint::draw(const VisualParams *vparams) -{ - if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) - return; /// \todo put this in the parent class - - const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); - vparams->drawTool()->setLightingEnabled(false); - - const DataVecCoord* extPosition = getExtPosition(); - if (!extPosition) - { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - - ReadAccessor< DataVecCoord > p0 = *extPosition; - ReadAccessor< DataVecCoord > p = this->mstate->read(sofa::core::vec_id::write_access::position); - - const auto & indices = getIndices(); - const auto & extIndices = getExtIndices(); - - std::vector vertices; - - for (sofa::Index i=0; i(3)) ; j++) - { - v0[j] = (DataTypes::getCPos(p[index]))[j]; - v1[j] = (DataTypes::getCPos(p0[ext_index]))[j]; - } - - vertices.push_back(v0); - vertices.push_back(v1); - } - - //todo(dmarchal) because of https://github.com/sofa-framework/sofa/issues/64 - vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); - -} template void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) @@ -520,11 +417,17 @@ void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparam constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes constexpr sofa::Size total_size = Deriv::total_size; - sofa::Index curIndex = 0; + const bool fixedAll = d_fixAll.getValue(); + const unsigned maxIt = fixedAll ? this->mstate->getSize() : indices.size(); - for (sofa::Index index = 0; index < indices.size(); index++) + for (sofa::Index index = 0; index < maxIt; index++) { - curIndex = indices[index]; + sofa::Index curIndex = index; + + if (!fixedAll) + { + curIndex = indices[index]; + } // translation const auto vt = -kFact * k[(index < k.size()) * index]; @@ -564,9 +467,17 @@ void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::Stiffn auto dfdx = matrix->getForceDerivativeIn(this->mstate) .withRespectToPositionsIn(this->mstate); + const bool fixedAll = d_fixAll.getValue(); + const unsigned maxIt = fixedAll ? this->mstate->getSize() : indices.size(); - for (const auto index : indices) + for (sofa::Index i = 0; i < maxIt; i++) { + sofa::Index index = i; + + if (!fixedAll) + { + index = indices[i]; + } // translation const auto vt = -k[(index < k.size()) * index]; for(sofa::Index i = 0; i < space_size; i++) @@ -597,4 +508,58 @@ void FixedWeakConstraint::buildDampingMatrix( { SOFA_UNUSED(matrix); } + +template +void FixedWeakConstraint::draw(const VisualParams *vparams) +{ + if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) + return; /// \todo put this in the parent class + + const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); + vparams->drawTool()->setLightingEnabled(false); + + const DataVecCoord* extPosition = getExtPosition(); + if (!extPosition) + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + + ReadAccessor< DataVecCoord > p0 = *extPosition; + ReadAccessor< DataVecCoord > p = this->mstate->read(sofa::core::vec_id::write_access::position); + std::vector vertices; + + + const auto & indices = getIndices(); + const auto & extIndices = getExtIndices(); + const bool fixedAll = d_fixAll.getValue(); + const unsigned maxIt = fixedAll ? this->mstate->getSize() : indices.size(); + + for (sofa::Index i = 0; i < maxIt; i++) + { + sofa::Index ext_index = i; + sofa::Index index = i; + + if (!fixedAll) + { + index = indices[i]; + ext_index = extIndices[i]; + } + + Vec3 v0(0.0, 0.0, 0.0); + Vec3 v1(0.0, 0.0, 0.0); + for(sofa::Index j=0 ; j< std::min(DataTypes::spatial_dimensions, static_cast(3)) ; j++) + { + v0[j] = (DataTypes::getCPos(p[index]))[j]; + v1[j] = (DataTypes::getCPos(p0[ext_index]))[j]; + } + + vertices.push_back(v0); + vertices.push_back(v1); + } + + //todo(dmarchal) because of https://github.com/sofa-framework/sofa/issues/64 + vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); + +} } // namespace sofa::component::solidmechanics::spring diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/init.cpp b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/init.cpp index 329e648e6b7..3d415081f78 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/init.cpp +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/init.cpp @@ -28,6 +28,7 @@ namespace sofa::component::solidmechanics::spring extern void registerAngularSpringForceField(sofa::core::ObjectFactory* factory); extern void registerFastTriangularBendingSprings(sofa::core::ObjectFactory* factory); +extern void registerFixedWeakConstraint(sofa::core::ObjectFactory* factory); extern void registerFrameSpringForceField(sofa::core::ObjectFactory* factory); extern void registerGearSpringForceField(sofa::core::ObjectFactory* factory); extern void registerNonUniformHexahedronFEMForceFieldAndMass(sofa::core::ObjectFactory* factory); @@ -72,6 +73,7 @@ void registerObjects(sofa::core::ObjectFactory* factory) { registerAngularSpringForceField(factory); registerFastTriangularBendingSprings(factory); + registerFixedWeakConstraint(factory); registerFrameSpringForceField(factory); registerGearSpringForceField(factory); registerNonUniformHexahedronFEMForceFieldAndMass(factory); From 937acc8ad9f547c63e05e079bd41f2aaba0dcbff Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 10 Dec 2024 14:51:19 +0100 Subject: [PATCH 08/21] Apply changes to RestShapeSpringForceField --- .../spring/FixedWeakConstraint.h | 26 +- .../spring/FixedWeakConstraint.inl | 36 +- .../spring/RestShapeSpringsForceField.h | 69 +-- .../spring/RestShapeSpringsForceField.inl | 534 ++---------------- 4 files changed, 90 insertions(+), 575 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index 28913e39618..d5ed13fe513 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace sofa::core::behavior @@ -71,38 +72,27 @@ class FixedWeakConstraint : public core::behavior::ForceField typedef core::objectmodel::Data DataVecDeriv; DataSubsetIndex d_indices; ///< points controlled by the rest shape springs + core::objectmodel::lifecycle::RemovedData d_points{this,"v24.12","v25.06","points","This data has been replaced by \'indices\'. Please update your scene."}; + Data d_fixAll; ///< points controlled by the rest shape springs Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points Data< bool > d_drawSpring; ///< draw Spring Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) - - protected: - FixedWeakConstraint(); - static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); + /// Link to be set to the topology container in the component graph. + SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; - public: /// BaseObject initialization method. void bwdInit() override ; void reinit() override ; /// Add the forces. void addForce(const core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v) override; - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; void addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) override; - - SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override - { - SOFA_UNUSED(mparams); - SOFA_UNUSED(x); - - msg_warning() << "Method getPotentialEnergy not implemented yet."; - return 0.0; - } + SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override; /// Brings ForceField contribution to the global system stiffness matrix. void addKToMatrix(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix ) override; @@ -113,6 +103,8 @@ class FixedWeakConstraint : public core::behavior::ForceField protected : + FixedWeakConstraint(); + static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); virtual const DataVecCoord* getExtPosition() const; virtual const VecIndex& getIndices() const; @@ -120,9 +112,9 @@ class FixedWeakConstraint : public core::behavior::ForceField virtual const type::fixed_array& getActiveDirections() const; virtual const bool checkState(); - bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); virtual bool checkOutOfBoundsIndices(); + bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); }; #if !defined(SOFA_COMPONENT_FORCEFIELD_FixedWeakConstraint_CPP) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index bcfd747d507..5ab787e4025 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -81,26 +81,26 @@ const bool FixedWeakConstraint::checkState() { if (d_stiffness.getValue().empty()) { - msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 "; + msg_info(this) << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 "; d_stiffness.setValue({static_cast(100)}); } if (l_topology.empty()) { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; + msg_info(this) << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; l_topology.set(this->getContext()->getMeshTopologyLink()); } if (sofa::core::topology::BaseMeshTopology* _topology = l_topology.get()) { - msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; + msg_info(this) << "Topology path used: '" << l_topology.getLinkedPath() << "'"; // Initialize topological changes support d_indices.createTopologyHandler(_topology); } else { - msg_info() << "Cannot find the topology: topological changes will not be supported"; + msg_info(this) << "Cannot find the topology: topological changes will not be supported"; } @@ -115,7 +115,7 @@ const bool FixedWeakConstraint::checkState() if (as.size() < s.size()) { - msg_info() << "'stiffness' is larger than 'angularStiffness', add the default value (100.0) to the missing entries."; + msg_info(this) << "'stiffness' is larger than 'angularStiffness', add the default value (100.0) to the missing entries."; for(size_t i = as.size();i::checkState() } }else if (as.size() > s.size()) { - msg_info() << "'stiffness' is smaller than 'angularStiffness', clamp the extra values in angularStiffness."; + msg_info(this) << "'stiffness' is smaller than 'angularStiffness', clamp the extra values in angularStiffness."; as.resize(s.size()); } } @@ -229,6 +229,9 @@ const type::fixed_array::coord_total_size>& template void FixedWeakConstraint::addForce(const MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) { + if (this->d_componentState.getValue() != core::objectmodel::ComponentState::Valid) + return; + SOFA_UNUSED(mparams); SOFA_UNUSED(v); @@ -333,6 +336,9 @@ void FixedWeakConstraint::addForce(const MechanicalParams* mparams , template void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) { + if (this->d_componentState.getValue() != core::objectmodel::ComponentState::Valid) + return; + WriteAccessor< DataVecDeriv > df1 = df; ReadAccessor< DataVecDeriv > dx1 = dx; Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); @@ -400,10 +406,22 @@ void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, } +template +SReal FixedWeakConstraint::getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const +{ + SOFA_UNUSED(mparams); + SOFA_UNUSED(x); + + msg_warning() << "Method getPotentialEnergy not implemented yet."; + return 0.0; +} template void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) { + if (this->d_componentState.getValue() != core::objectmodel::ComponentState::Valid) + return; + const MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); BaseMatrix* mat = mref.matrix; const unsigned int offset = mref.offset; @@ -457,6 +475,9 @@ void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparam template void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) { + if (this->d_componentState.getValue() != core::objectmodel::ComponentState::Valid) + return; + const VecReal& k = d_stiffness.getValue(); const VecReal& k_a = d_angularStiffness.getValue(); const auto & activeDirections = getActiveDirections(); @@ -512,6 +533,9 @@ void FixedWeakConstraint::buildDampingMatrix( template void FixedWeakConstraint::draw(const VisualParams *vparams) { + if (this->d_componentState.getValue() != core::objectmodel::ComponentState::Valid) + return; + if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) return; /// \todo put this in the parent class diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h index ea0972703e3..9860d236f94 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include namespace sofa::core::behavior @@ -48,12 +50,12 @@ namespace sofa::component::solidmechanics::spring * An external MechanicalState reference can also be passed to the ForceField as rest shape position. */ template -class RestShapeSpringsForceField : public core::behavior::ForceField +class RestShapeSpringsForceField : public FixedWeakConstraint { public: - SOFA_CLASS(SOFA_TEMPLATE(RestShapeSpringsForceField, DataTypes), SOFA_TEMPLATE(core::behavior::ForceField, DataTypes)); + SOFA_CLASS(SOFA_TEMPLATE(RestShapeSpringsForceField, DataTypes), SOFA_TEMPLATE(FixedWeakConstraint, DataTypes)); - typedef core::behavior::ForceField Inherit; + typedef FixedWeakConstraint Inherit; typedef typename DataTypes::VecCoord VecCoord; typedef typename DataTypes::VecDeriv VecDeriv; typedef typename DataTypes::Coord Coord; @@ -70,72 +72,31 @@ class RestShapeSpringsForceField : public core::behavior::ForceField typedef core::objectmodel::Data DataVecCoord; typedef core::objectmodel::Data DataVecDeriv; - DataSubsetIndex d_points; ///< points controlled by the rest shape springs - Data< VecReal > d_stiffness; ///< stiffness values between the actual position and the rest shape position - Data< VecReal > d_angularStiffness; ///< angularStiffness assigned when controlling the rotation of the points - Data< type::vector< CPos > > d_pivotPoints; ///< global pivot points used when translations instead of the rigid mass centers - Data< VecIndex > d_external_points; ///< points from the external Mechanical State that define the rest shape springs - Data< bool > d_recompute_indices; ///< Recompute indices (should be false for BBOX) - Data< bool > d_drawSpring; ///< draw Spring - Data< sofa::type::RGBAColor > d_springColor; ///< spring color. (default=[0.0,1.0,0.0,1.0]) Data< type::fixed_array > d_activeDirections; ///< directions (translation, and rotation in case of Rigids) in which the spring is active + Data< VecIndex > d_externalIndices; ///< points from the external Mechanical State that define the rest shape springs + core::objectmodel::lifecycle::RemovedData d_external_points{this,"v24.12","v25.06","external_points","This data has been replaced by \'externalIndices\'. Please update your scene."}; + core::objectmodel::DataCallback c_fixAllCallback; SingleLink, sofa::core::behavior::MechanicalState< DataTypes >, BaseLink::FLAG_STOREPATH|BaseLink::FLAG_STRONGLINK> l_restMState; - linearalgebra::EigenBaseSparseMatrix matS; - -protected: - RestShapeSpringsForceField(); - - static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); + SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; -public: /// BaseObject initialization method. void bwdInit() override ; - void parse(core::objectmodel::BaseObjectDescription *arg) override ; - void reinit() override ; - - /// Add the forces. - void addForce(const core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v) override; - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; - void addDForce(const core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) override; - SReal getPotentialEnergy(const core::MechanicalParams* mparams, const DataVecCoord& x) const override - { - SOFA_UNUSED(mparams); - SOFA_UNUSED(x); - - msg_warning() << "Method getPotentialEnergy not implemented yet."; - return 0.0; - } - - /// Brings ForceField contribution to the global system stiffness matrix. - void addKToMatrix(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix ) override; - void buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) override; - void buildDampingMatrix(core::behavior::DampingMatrix* matrix) override; - - void draw(const core::visual::VisualParams* vparams) override; - - - const DataVecCoord* getExtPosition() const; - const VecIndex& getIndices() const { return m_indices; } - const VecIndex& getExtIndices() const { return (useRestMState ? m_ext_indices : m_indices); } protected : + RestShapeSpringsForceField(); - void recomputeIndices(); - bool checkOutOfBoundsIndices(); - bool checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension); - + virtual const DataVecCoord* getExtPosition() const override; + virtual const VecIndex& getExtIndices() const override; + virtual const type::fixed_array& getActiveDirections() const override; - VecIndex m_indices; - VecIndex m_ext_indices; - type::vector m_pivots; + virtual bool checkOutOfBoundsIndices(); private : - bool useRestMState{}; /// An external MechanicalState is used as rest reference. + bool m_useRestMState; /// An external MechanicalState is used as rest reference. }; #if !defined(SOFA_COMPONENT_FORCEFIELD_RESTSHAPESPRINGSFORCEFIELD_CPP) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl index 83cca22cf0a..eded05ba9ce 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -51,54 +52,37 @@ using core::visual::VisualParams; template RestShapeSpringsForceField::RestShapeSpringsForceField() - : d_points(initData(&d_points, "points", "points controlled by the rest shape springs")) - , d_stiffness(initData(&d_stiffness, "stiffness", "stiffness values between the actual position and the rest shape position")) - , d_angularStiffness(initData(&d_angularStiffness, "angularStiffness", "angularStiffness assigned when controlling the rotation of the points")) - , d_pivotPoints(initData(&d_pivotPoints, "pivot_points", "global pivot points used when translations instead of the rigid mass centers")) - , d_external_points(initData(&d_external_points, "external_points", "points from the external Mechanical State that define the rest shape springs")) - , d_recompute_indices(initData(&d_recompute_indices, true, "recompute_indices", "Recompute indices (should be false for BBOX)")) - , d_drawSpring(initData(&d_drawSpring,false,"drawSpring","draw Spring")) - , d_springColor(initData(&d_springColor, sofa::type::RGBAColor::green(), "springColor","spring color. (default=[0.0,1.0,0.0,1.0])")) - , d_activeDirections(initData(&d_activeDirections, s_defaultActiveDirections, - "activeDirections", std::string("Directions in which the spring is active (default=[" + sofa::helper::join(s_defaultActiveDirections, ',') + "])").c_str())) + : d_activeDirections(initData(&d_activeDirections, FixedWeakConstraint::s_defaultActiveDirections, + "activeDirections", std::string("Directions in which the spring is active (default=[" + sofa::helper::join(FixedWeakConstraint::s_defaultActiveDirections, ',') + "])").c_str())) + , d_externalIndices(initData(&d_externalIndices, "externalIndices","Indices from the external Mechanical State that define the rest shape springs")) , l_restMState(initLink("external_rest_shape", "rest_shape can be defined by the position of an external Mechanical State")) , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) { - this->addUpdateCallback("updateIndices", {&d_points}, [this](const core::DataTracker& t) + c_fixAllCallback.addInput(&this->d_fixAll); + c_fixAllCallback.addCallback([this]() { - SOFA_UNUSED(t); - this->recomputeIndices(); - return sofa::core::objectmodel::ComponentState::Valid; - }, {}); -} - -template -void RestShapeSpringsForceField::parse(core::objectmodel::BaseObjectDescription *arg) -{ - const char* attr = arg->getAttribute("external_rest_shape") ; - if( attr != nullptr && attr[0] != '@') - { - msg_error() << "RestShapeSpringsForceField have changed since 17.06. The parameter 'external_rest_shape' is now a Link. To fix your scene you need to add and '@' in front of the provided path. See PR#315" ; - } - Inherit::parse(arg) ; + if (this->getMState()->getSize() != l_restMState->getSize()) + { + msg_error(this) <<"the fixAll option only works with either one mstate or when the two mstate have the same size."; + this->d_componentState.setValue(core::objectmodel::ComponentState::Invalid); + } + else + { + this->d_componentState.setValue(core::objectmodel::ComponentState::Valid); + } + }); } template void RestShapeSpringsForceField::bwdInit() { - ForceField::init(); - - if (d_stiffness.getValue().empty()) - { - msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 "; - d_stiffness.setValue({static_cast(100)}); - } + FixedWeakConstraint::bwdInit(); if (l_restMState.get() == nullptr) { - useRestMState = false; - msg_info() << "no external rest shape used"; + m_useRestMState = false; + msg_info(this) << "no external rest shape used"; if(!l_restMState.empty()) { @@ -107,176 +91,23 @@ void RestShapeSpringsForceField::bwdInit() } else { - msg_info() << "external rest shape used"; - useRestMState = true; - } - - if (l_topology.empty()) - { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); - } - - if (sofa::core::topology::BaseMeshTopology* _topology = l_topology.get()) - { - msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; - - // Initialize topological changes support - d_points.createTopologyHandler(_topology); - } - else - { - msg_info() << "Cannot find the topology: topological changes will not be supported"; + msg_info(this) << "external rest shape used"; + m_useRestMState = true; } - - recomputeIndices(); - if (this->d_componentState.getValue() == sofa::core::objectmodel::ComponentState::Invalid) - return; - - const BaseMechanicalState* state = this->getContext()->getMechanicalState(); - if(!state) - { - msg_warning() << "MechanicalState of the current context returns null pointer"; - } - else - { - assert(state); - matS.resize(state->getMatrixSize(),state->getMatrixSize()); - } - - /// Compile time condition to check if we are working with a Rigid3Types or a type that does not - /// need the Angular Stiffness parameters. - //if constexpr (isRigid()) - if constexpr (sofa::type::isRigidType()) - { - sofa::helper::ReadAccessor> s = d_stiffness; - sofa::helper::WriteOnlyAccessor> as = d_angularStiffness; - - if (as.size() < s.size()) - { - msg_info() << "'stiffness' is larger than 'angularStiffness', add the default value (100.0) to the missing entries."; - - for(size_t i = as.size();i s.size()) - { - msg_info() << "'stiffness' is smaller than 'angularStiffness', clamp the extra values in angularStiffness."; - as.resize(s.size()); - } - } - - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); } -template -void RestShapeSpringsForceField::reinit() -{ - if (!checkOutOfBoundsIndices()) - { - m_indices.clear(); - } - else - { - msg_info() << "Indices successfully checked"; - } - - if (d_stiffness.getValue().empty()) - { - msg_info() << "No stiffness is defined, assuming equal stiffness on each node, k = 100.0 " ; - - VecReal stiffs; - stiffs.push_back(100.0); - d_stiffness.setValue(stiffs); - } - else - { - const VecReal &k = d_stiffness.getValue(); - if ( k.size() != m_indices.size() ) - { - msg_warning() << "Size of stiffness vector is not correct (" << k.size() << "), should be either 1 or " << m_indices.size() << msgendl - << "First value of stiffness will be used"; - } - } - -} - -template -void RestShapeSpringsForceField::recomputeIndices() -{ - m_indices.clear(); - m_ext_indices.clear(); - - for (const sofa::Index i : d_points.getValue()) - { - m_indices.push_back(i); - } - - for (const sofa::Index i : d_external_points.getValue()) - { - m_ext_indices.push_back(i); - } - - if (m_indices.empty()) - { - // no point are defined, default case: points = all points - msg_info() << "No point are defined. Change to default case: points = all points"; - for (sofa::Index i = 0; i < this->mstate->getSize(); i++) - { - m_indices.push_back(i); - } - } - - if (m_ext_indices.empty()) - { - if (useRestMState) - { - if (const DataVecCoord* extPosition = getExtPosition()) - { - const auto& extPositionValue = extPosition->getValue(); - for (sofa::Index i = 0; i < extPositionValue.size(); i++) - { - m_ext_indices.push_back(i); - } - } - else - { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - } - } - else - { - for (const sofa::Index i : m_indices) - { - m_ext_indices.push_back(i); - } - } - } - - if (!checkOutOfBoundsIndices()) - { - msg_error() << "The dimension of the source and the targeted points are different "; - m_indices.clear(); - } - else - { - msg_info() << "Indices successfully checked"; - } -} - template bool RestShapeSpringsForceField::checkOutOfBoundsIndices() { - if (!checkOutOfBoundsIndices(m_indices, this->mstate->getSize())) + if (!FixedWeakConstraint::checkOutOfBoundsIndices(this->getIndices(), this->mstate->getSize())) { msg_error() << "Out of Bounds d_indices detected. ForceField is not activated."; return false; } if (const DataVecCoord* extPosition = getExtPosition()) { - if (!checkOutOfBoundsIndices(m_ext_indices, sofa::Size(extPosition->getValue().size()))) + if (!FixedWeakConstraint::checkOutOfBoundsIndices(getExtIndices(), sofa::Size(extPosition->getValue().size()))) { msg_error() << "Out of Bounds m_ext_indices detected. ForceField is not activated."; return false; @@ -286,7 +117,7 @@ bool RestShapeSpringsForceField::checkOutOfBoundsIndices() { this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); } - if (m_indices.size() != m_ext_indices.size()) + if (this->getIndices().size() != getExtIndices().size()) { msg_error() << "Dimensions of the source and the targeted points are different. ForceField is not activated."; return false; @@ -294,28 +125,19 @@ bool RestShapeSpringsForceField::checkOutOfBoundsIndices() return true; } -template -bool RestShapeSpringsForceField::checkOutOfBoundsIndices(const VecIndex &indices, const sofa::Size dimension) -{ - for (sofa::Index i = 0; i < indices.size(); i++) - { - if (indices[i] >= dimension) - { - return false; - } - } - return true; -} - template const typename RestShapeSpringsForceField::DataVecCoord* RestShapeSpringsForceField::getExtPosition() const { - if(useRestMState) + if(m_useRestMState) { if (l_restMState) { return l_restMState->read(core::vec_id::write_access::position); } + else + { + msg_error(this)<<"The external rest shape is not set correctly."; + } } else { @@ -327,308 +149,24 @@ const typename RestShapeSpringsForceField::DataVecCoord* RestShapeSpr return nullptr; } -template -void RestShapeSpringsForceField::addForce(const MechanicalParams* mparams , DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v ) -{ - SOFA_UNUSED(mparams); - SOFA_UNUSED(v); - - WriteAccessor< DataVecDeriv > f1 = f; - ReadAccessor< DataVecCoord > p1 = x; - - const DataVecCoord* extPosition = getExtPosition(); - if (!extPosition) - { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - - ReadAccessor< DataVecCoord > p0 = *extPosition; - - const VecReal& k = d_stiffness.getValue(); - const VecReal& k_a = d_angularStiffness.getValue(); - - f1.resize(p1.size()); - - if (d_recompute_indices.getValue()) - { - recomputeIndices(); - } - - for (sofa::Index i = 0; i < m_indices.size(); i++) - { - const sofa::Index index = m_indices[i]; - sofa::Index ext_index = m_indices[i]; - if (useRestMState) - ext_index = m_ext_indices[i]; - - const auto stiffness = k[static_cast(i < k.size()) * i]; - - const auto activeDirections = d_activeDirections.getValue(); - - // rigid case - if constexpr (sofa::type::isRigidType()) - { - // translation - if (i >= m_pivots.size()) - { - CPos dx = p1[index].getCenter() - p0[ext_index].getCenter(); - // We filter the difference dx by setting to 0 the entries corresponding - // to 0 values in d_activeDirections - for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) - { - if (!activeDirections[entryId]) - dx[entryId] = 0; - } - getVCenter(f1[index]) -= dx * stiffness; - } - else - { - CPos localPivot = p0[ext_index].getOrientation().inverseRotate(m_pivots[i] - p0[ext_index].getCenter()); - CPos rotatedPivot = p1[index].getOrientation().rotate(localPivot); - CPos pivot2 = p1[index].getCenter() + rotatedPivot; - CPos dx = pivot2 - m_pivots[i]; - getVCenter(f1[index]) -= dx * stiffness; - } - - // rotation - type::Quat dq = p1[index].getOrientation() * p0[ext_index].getOrientation().inverse(); - dq.normalize(); - - type::Vec<3, Real> dir{type::NOINIT}; - Real angle = 0.; - - if (dq[3] < 0.) - { - dq = dq * -1.0; - } - - if (dq[3] < 1.0) - dq.quatToAxis(dir, angle); - - // We change the direction of the axis of rotation based on - // the 0 values in d_activeDirections. This is equivalent - // to senting to 0 the rotation axis components along x, y - // and/or z, depending on the rotations we want to take into - // account. - for (sofa::Size entryId = spatial_dimensions; entryId < coord_total_size; ++entryId) - { - if (!activeDirections[entryId]) - dir[entryId-spatial_dimensions] = 0; - } - - const auto angularStiffness = k_a[static_cast(i < k_a.size()) * i]; - getVOrientation(f1[index]) -= dir * angle * angularStiffness; - } - else // non-rigid implementation - { - Deriv dx = p1[index] - p0[ext_index]; - // We filter the difference dx by setting to 0 the entries corresponding - // to 0 values in d_activeDirections - for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) - { - if (!activeDirections[entryId]) - dx[entryId] = 0; - } - f1[index] -= dx * stiffness; - } - } -} template -void RestShapeSpringsForceField::addDForce(const MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx) +const typename RestShapeSpringsForceField::VecIndex& RestShapeSpringsForceField::getExtIndices() const { - WriteAccessor< DataVecDeriv > df1 = df; - ReadAccessor< DataVecDeriv > dx1 = dx; - Real kFactor = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - const VecReal& k = d_stiffness.getValue(); - const VecReal& k_a = d_angularStiffness.getValue(); - const auto activeDirections = d_activeDirections.getValue(); - - for (unsigned int i = 0; i < m_indices.size(); i++) + if (m_useRestMState ) { - const sofa::Index curIndex = m_indices[i]; - const auto stiffness = k[static_cast(i < k.size()) * i]; - - if constexpr (sofa::type::isRigidType()) - { - const auto angularStiffness = k_a[static_cast(i < k_a.size()) * i]; - - // We filter the difference in translation by setting to 0 the entries corresponding - // to 0 values in d_activeDirections - auto currentSpringDx = getVCenter(dx1[curIndex]); - for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) - { - if (!activeDirections[entryId]) - currentSpringDx[entryId] = 0; - } - getVCenter(df1[curIndex]) -= currentSpringDx * stiffness * kFactor; - - auto currentSpringRotationalDx = getVOrientation(dx1[curIndex]); - // We change the direction of the axis of rotation based on - // the 0 values in d_activeDirections. This is equivalent - // to senting to 0 the rotation axis components along x, y - // and/or z, depending on the rotations we want to take into - // account. - for (sofa::Size entryId = spatial_dimensions; entryId < coord_total_size; ++entryId) - { - if (!activeDirections[entryId]) - currentSpringRotationalDx[entryId-spatial_dimensions] = 0; - } - getVOrientation(df1[curIndex]) -= currentSpringRotationalDx * angularStiffness * kFactor; - } - else - { - // We filter the difference in translation by setting to 0 the entries corresponding - // to 0 values in d_activeDirections - auto currentSpringDx = dx1[m_indices[i]]; - for (sofa::Size entryId = 0; entryId < spatial_dimensions; ++entryId) - { - if (!activeDirections[entryId]) - currentSpringDx[entryId] = 0; - } - df1[m_indices[i]] -= currentSpringDx * stiffness * kFactor; - } + return d_externalIndices.getValue(); } - - -} - -template -void RestShapeSpringsForceField::draw(const VisualParams *vparams) -{ - if (!vparams->displayFlags().getShowForceFields() || !d_drawSpring.getValue()) - return; /// \todo put this in the parent class - - const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); - vparams->drawTool()->setLightingEnabled(false); - - const DataVecCoord* extPosition = getExtPosition(); - if (!extPosition) - { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - - ReadAccessor< DataVecCoord > p0 = *extPosition; - ReadAccessor< DataVecCoord > p = this->mstate->read(sofa::core::vec_id::write_access::position); - - const VecIndex& indices = m_indices; - const VecIndex& ext_indices = (useRestMState ? m_ext_indices : m_indices); - - std::vector vertices; - - for (sofa::Index i=0; i(3)) ; j++) - { - v0[j] = (DataTypes::getCPos(p[index]))[j]; - v1[j] = (DataTypes::getCPos(p0[ext_index]))[j]; - } - - vertices.push_back(v0); - vertices.push_back(v1); - } - - //todo(dmarchal) because of https://github.com/sofa-framework/sofa/issues/64 - vparams->drawTool()->drawLines(vertices,5, d_springColor.getValue()); - -} - -template -void RestShapeSpringsForceField::addKToMatrix(const MechanicalParams* mparams, const MultiMatrixAccessor* matrix ) -{ - const MultiMatrixAccessor::MatrixRef mref = matrix->getMatrix(this->mstate); - BaseMatrix* mat = mref.matrix; - const unsigned int offset = mref.offset; - Real kFact = (Real)sofa::core::mechanicalparams::kFactorIncludingRayleighDamping(mparams, this->rayleighStiffness.getValue()); - - const VecReal& k = d_stiffness.getValue(); - const VecReal& k_a = d_angularStiffness.getValue(); - const auto activeDirections = d_activeDirections.getValue(); - - constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes - constexpr sofa::Size total_size = Deriv::total_size; - - sofa::Index curIndex = 0; - - for (sofa::Index index = 0; index < m_indices.size(); index++) + else { - curIndex = m_indices[index]; - - // translation - const auto vt = -kFact * k[(index < k.size()) * index]; - for (sofa::Size i = 0; i < space_size; i++) - { - // Contribution to the stiffness matrix are only taken into - // account for 1 values in d_activeDirections - if (activeDirections[i]) - mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vt); - } - - // rotation (if applicable) - if constexpr (sofa::type::isRigidType()) - { - const auto vr = -kFact * k_a[(index < k_a.size()) * index]; - for (sofa::Size i = space_size; i < total_size; i++) - { - // Contribution to the stiffness matrix are only taken into - // account for 1 values in d_activeDirections - if (activeDirections[i]) - mat->add(offset + total_size * curIndex + i, offset + total_size * curIndex + i, vr); - } - } + return this->d_indices.getValue(); } } template -void RestShapeSpringsForceField::buildStiffnessMatrix(core::behavior::StiffnessMatrix* matrix) +const type::fixed_array::coord_total_size>& RestShapeSpringsForceField::getActiveDirections() const { - const VecReal& k = d_stiffness.getValue(); - const VecReal& k_a = d_angularStiffness.getValue(); - const auto activeDirections = d_activeDirections.getValue(); - - constexpr sofa::Size space_size = Deriv::spatial_dimensions; // == total_size if DataTypes = VecTypes - constexpr sofa::Size total_size = Deriv::total_size; - - auto dfdx = matrix->getForceDerivativeIn(this->mstate) - .withRespectToPositionsIn(this->mstate); - - for (const auto index : m_indices) - { - // translation - const auto vt = -k[(index < k.size()) * index]; - for(sofa::Index i = 0; i < space_size; i++) - { - dfdx(total_size * index + i, total_size * index + i) += vt; - } - - // rotation (if applicable) - if constexpr (sofa::type::isRigidType()) - { - const auto vr = -k_a[(index < k_a.size()) * index]; - for (sofa::Size i = space_size; i < total_size; ++i) - { - // Contribution to the stiffness matrix are only taken into - // account for 1 values in d_activeDirections - if (activeDirections[i]) - { - dfdx(total_size * index + i, total_size * index + i) += vr; - } - } - } - } + return d_activeDirections.getValue(); } -template -void RestShapeSpringsForceField::buildDampingMatrix( - core::behavior::DampingMatrix* matrix) -{ - SOFA_UNUSED(matrix); -} } // namespace sofa::component::solidmechanics::spring From 0754eb8aaf58d1e4b42e1de44111051f004bcde2 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 10 Dec 2024 15:20:42 +0100 Subject: [PATCH 09/21] apply changes to scenes --- .../examples/ArticulatedArm/robot.py | 2 +- .../Geomagic/scenes/Geomagic-DeformableCubes.scn | 2 +- .../Geomagic/scenes/Geomagic-DeformableSphere.scn | 2 +- .../plugins/Geomagic/scenes/Geomagic-RigidCubes.scn | 2 +- ...Geomagic-RigidSkull-restShapeSpringForceField.scn | 2 +- .../plugins/Geomagic/scenes/Geomagic-RigidSphere.scn | 2 +- .../Geomagic/scenes/GeomagicEmulator-RigidCubes.scn | 2 +- .../PersistentContact/examples/instrument.xml | 4 ++-- .../PersistentContact/examples/instrument2.xml | 4 ++-- .../plugins/Sensable/examples/Old Examples/omni1.scn | 2 +- .../plugins/Sensable/examples/Old Examples/omni2.scn | 2 +- applications/plugins/Xitact/examples/1xitact.scn | 2 +- applications/plugins/Xitact/examples/2xitact2.scn | 2 +- .../plugins/Xitact/examples/XitactGrasping.scn | 4 ++-- .../examples/XitactGraspingWithForceFeedBack.scn | 4 ++-- .../Xitact/examples/XitactGrasping_coupledModel.scn | 8 ++++---- .../examples/XitactGrasping_coupledModel_withITP.scn | 12 ++++++------ applications/plugins/Xitact/examples/xitactTest.scn | 4 ++-- .../Lagrangian/FixedLagrangianConstaint_Vec3.scn | 2 +- .../FEM/RestShapeSpringsForceField3.scn | 2 +- .../Spring/RestShapeSpringsForceField2.scn | 2 +- .../Spring/angularSpringForceField.scn | 2 +- 22 files changed, 35 insertions(+), 35 deletions(-) diff --git a/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py b/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py index a8e7179a80f..8b72a19be18 100644 --- a/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py +++ b/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py @@ -88,7 +88,7 @@ def addRobot(self, name='Robot', translation=[0,0,0]): articulations.addObject('MechanicalObject', name='dofs', template='Vec1', rest_position=robot.getData('angles').getLinkPath(), position=initAngles) articulations.addObject('ArticulatedHierarchyContainer') articulations.addObject('UniformMass', totalMass=1) - articulations.addObject('RestShapeSpringsForceField', stiffness=1e10, points=list(range(6))) + articulations.addObject('RestShapeSpringsForceField', stiffness=1e10, indices=list(range(6))) # Rigid rigid = articulations.addChild('Rigid') diff --git a/applications/plugins/Geomagic/scenes/Geomagic-DeformableCubes.scn b/applications/plugins/Geomagic/scenes/Geomagic-DeformableCubes.scn index 8447dc4d862..3295ff9ddcd 100644 --- a/applications/plugins/Geomagic/scenes/Geomagic-DeformableCubes.scn +++ b/applications/plugins/Geomagic/scenes/Geomagic-DeformableCubes.scn @@ -126,7 +126,7 @@ - + diff --git a/applications/plugins/Geomagic/scenes/Geomagic-DeformableSphere.scn b/applications/plugins/Geomagic/scenes/Geomagic-DeformableSphere.scn index d3f88c411bb..a969ae31d7c 100644 --- a/applications/plugins/Geomagic/scenes/Geomagic-DeformableSphere.scn +++ b/applications/plugins/Geomagic/scenes/Geomagic-DeformableSphere.scn @@ -105,7 +105,7 @@ - + diff --git a/applications/plugins/Geomagic/scenes/Geomagic-RigidCubes.scn b/applications/plugins/Geomagic/scenes/Geomagic-RigidCubes.scn index b49b7dd575d..c667058822b 100644 --- a/applications/plugins/Geomagic/scenes/Geomagic-RigidCubes.scn +++ b/applications/plugins/Geomagic/scenes/Geomagic-RigidCubes.scn @@ -88,7 +88,7 @@ - + diff --git a/applications/plugins/Geomagic/scenes/Geomagic-RigidSkull-restShapeSpringForceField.scn b/applications/plugins/Geomagic/scenes/Geomagic-RigidSkull-restShapeSpringForceField.scn index 37ccac55ceb..7c956d6f764 100644 --- a/applications/plugins/Geomagic/scenes/Geomagic-RigidSkull-restShapeSpringForceField.scn +++ b/applications/plugins/Geomagic/scenes/Geomagic-RigidSkull-restShapeSpringForceField.scn @@ -59,7 +59,7 @@ - + diff --git a/applications/plugins/Geomagic/scenes/Geomagic-RigidSphere.scn b/applications/plugins/Geomagic/scenes/Geomagic-RigidSphere.scn index 880396565d4..fb730dd5bbc 100644 --- a/applications/plugins/Geomagic/scenes/Geomagic-RigidSphere.scn +++ b/applications/plugins/Geomagic/scenes/Geomagic-RigidSphere.scn @@ -76,7 +76,7 @@ - + diff --git a/applications/plugins/Geomagic/scenes/GeomagicEmulator-RigidCubes.scn b/applications/plugins/Geomagic/scenes/GeomagicEmulator-RigidCubes.scn index f950b7b60e1..f4d7be61acc 100644 --- a/applications/plugins/Geomagic/scenes/GeomagicEmulator-RigidCubes.scn +++ b/applications/plugins/Geomagic/scenes/GeomagicEmulator-RigidCubes.scn @@ -88,7 +88,7 @@ - + diff --git a/applications/plugins/PersistentContact/examples/instrument.xml b/applications/plugins/PersistentContact/examples/instrument.xml index fd67eb58411..551bf782cde 100644 --- a/applications/plugins/PersistentContact/examples/instrument.xml +++ b/applications/plugins/PersistentContact/examples/instrument.xml @@ -5,12 +5,12 @@ - + - + diff --git a/applications/plugins/PersistentContact/examples/instrument2.xml b/applications/plugins/PersistentContact/examples/instrument2.xml index f338f657865..f6a6e04273c 100644 --- a/applications/plugins/PersistentContact/examples/instrument2.xml +++ b/applications/plugins/PersistentContact/examples/instrument2.xml @@ -5,12 +5,12 @@ - + - + diff --git a/applications/plugins/Sensable/examples/Old Examples/omni1.scn b/applications/plugins/Sensable/examples/Old Examples/omni1.scn index b3978a75c3e..b635978b532 100644 --- a/applications/plugins/Sensable/examples/Old Examples/omni1.scn +++ b/applications/plugins/Sensable/examples/Old Examples/omni1.scn @@ -20,7 +20,7 @@ - + diff --git a/applications/plugins/Sensable/examples/Old Examples/omni2.scn b/applications/plugins/Sensable/examples/Old Examples/omni2.scn index 9d38b20cd1e..4e19ad2b2a7 100644 --- a/applications/plugins/Sensable/examples/Old Examples/omni2.scn +++ b/applications/plugins/Sensable/examples/Old Examples/omni2.scn @@ -15,7 +15,7 @@ - + diff --git a/applications/plugins/Xitact/examples/1xitact.scn b/applications/plugins/Xitact/examples/1xitact.scn index 66de05934b7..338be5d68d8 100644 --- a/applications/plugins/Xitact/examples/1xitact.scn +++ b/applications/plugins/Xitact/examples/1xitact.scn @@ -14,7 +14,7 @@ - + diff --git a/applications/plugins/Xitact/examples/2xitact2.scn b/applications/plugins/Xitact/examples/2xitact2.scn index e717de5cb74..4f62edbbb67 100644 --- a/applications/plugins/Xitact/examples/2xitact2.scn +++ b/applications/plugins/Xitact/examples/2xitact2.scn @@ -15,7 +15,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping.scn b/applications/plugins/Xitact/examples/XitactGrasping.scn index a2b37a124ca..228bf45a0c6 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn b/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn index 3725346d2fe..7a15d6ce5ff 100644 --- a/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn +++ b/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn index 6431ef2d7d9..a08c6f561d8 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -221,7 +221,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn index c9c2a905e1f..bf57c1fb18c 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -221,7 +221,7 @@ - + @@ -319,7 +319,7 @@ - + @@ -338,7 +338,7 @@ - + diff --git a/applications/plugins/Xitact/examples/xitactTest.scn b/applications/plugins/Xitact/examples/xitactTest.scn index 8b9ce1ecf9a..88bad4d4613 100644 --- a/applications/plugins/Xitact/examples/xitactTest.scn +++ b/applications/plugins/Xitact/examples/xitactTest.scn @@ -17,7 +17,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/examples/Component/Constraint/Lagrangian/FixedLagrangianConstaint_Vec3.scn b/examples/Component/Constraint/Lagrangian/FixedLagrangianConstaint_Vec3.scn index 8e4fe5d1f71..2b1705c4c29 100644 --- a/examples/Component/Constraint/Lagrangian/FixedLagrangianConstaint_Vec3.scn +++ b/examples/Component/Constraint/Lagrangian/FixedLagrangianConstaint_Vec3.scn @@ -46,7 +46,7 @@ - + diff --git a/examples/Component/SolidMechanics/FEM/RestShapeSpringsForceField3.scn b/examples/Component/SolidMechanics/FEM/RestShapeSpringsForceField3.scn index 07a305404bd..00ecee50be0 100644 --- a/examples/Component/SolidMechanics/FEM/RestShapeSpringsForceField3.scn +++ b/examples/Component/SolidMechanics/FEM/RestShapeSpringsForceField3.scn @@ -21,7 +21,7 @@ diff --git a/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField2.scn b/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField2.scn index 1bc4f821d8c..07d1c58f388 100644 --- a/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField2.scn +++ b/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField2.scn @@ -26,7 +26,7 @@ - + diff --git a/examples/Component/SolidMechanics/Spring/angularSpringForceField.scn b/examples/Component/SolidMechanics/Spring/angularSpringForceField.scn index 6befcf8641f..8567ed4afb9 100644 --- a/examples/Component/SolidMechanics/Spring/angularSpringForceField.scn +++ b/examples/Component/SolidMechanics/Spring/angularSpringForceField.scn @@ -49,7 +49,7 @@ - + From a13b3ca8e5facfbb7dca114a165027d1e7040483 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Wed, 11 Dec 2024 11:52:11 +0100 Subject: [PATCH 10/21] Remove duplication of the topology link in RestShapeSpringForceField --- .../component/solidmechanics/spring/RestShapeSpringsForceField.h | 1 - .../solidmechanics/spring/RestShapeSpringsForceField.inl | 1 - 2 files changed, 2 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h index 9860d236f94..a073c3f1671 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h @@ -78,7 +78,6 @@ class RestShapeSpringsForceField : public FixedWeakConstraint core::objectmodel::DataCallback c_fixAllCallback; SingleLink, sofa::core::behavior::MechanicalState< DataTypes >, BaseLink::FLAG_STOREPATH|BaseLink::FLAG_STRONGLINK> l_restMState; - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; /// BaseObject initialization method. void bwdInit() override ; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl index eded05ba9ce..c3fc5d30191 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl @@ -56,7 +56,6 @@ RestShapeSpringsForceField::RestShapeSpringsForceField() "activeDirections", std::string("Directions in which the spring is active (default=[" + sofa::helper::join(FixedWeakConstraint::s_defaultActiveDirections, ',') + "])").c_str())) , d_externalIndices(initData(&d_externalIndices, "externalIndices","Indices from the external Mechanical State that define the rest shape springs")) , l_restMState(initLink("external_rest_shape", "rest_shape can be defined by the position of an external Mechanical State")) - , l_topology(initLink("topology", "Link to be set to the topology container in the component graph")) { c_fixAllCallback.addInput(&this->d_fixAll); c_fixAllCallback.addCallback([this]() From 885e98060dce9243d577fe1020e1984dfa4f6ec9 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 23 Jan 2025 11:28:56 +0100 Subject: [PATCH 11/21] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f8ed001c4a939d63bf85445c479df63274838a3b Author: Alex Bilger Date: Wed Jan 22 14:24:35 2025 +0100 [tests] Template method design pattern from BaseTest in derived classes (#5162) * [tests] Template method design pattern from BaseTest in derived classes * rename * use the deprecated function * Make SetUp and TearDown final * fix SofaCarving test * missing override commit 41bac37fe9554189ac6a751ad2159832905021f0 Author: Frederick Roy Date: Tue Jan 21 16:21:12 2025 +0100 [Helper] XCode: run in Debug (and load debug plugins) (#5168) remove deprecated cmake statement Co-authored-by: Hugo commit 723420cf40b5e5c3a3a0c25f600be30b7be04ab5 Author: Hugo Date: Tue Jan 21 16:18:00 2025 +0100 [Project] Start dev phase v25.06 (#5218) * Add ChangeLog for v24.12 * Bump dev version to v25.06.99 commit b445f5768b0aa9b8fc740e5ad33437d67b962831 Author: Frederick Roy Date: Tue Jan 21 16:16:25 2025 +0100 [Helper] WriteAccessorVector: add resize method with default filler value (#5228) add resize with default filler value commit 4ba3bbee02a2af960ced06ad906896baa5843af1 Author: Hugo Date: Tue Jan 21 15:58:00 2025 +0100 [Core] Move all LifeCycle classes in a dedicated namespace (#5225) Co-authored-by: Paul Baksic <30337881+bakpaul@users.noreply.github.com> commit eb9fe59f4219a5757b780261f540ee1fd0c4ae56 Author: Alex Bilger Date: Mon Jan 20 05:45:39 2025 +0100 [Type] Support structured binding for tuple-like types (#5208) * [Type] Support structured binding for tuple-like types * fix redefinition * fix test commit aedc7ffea53e1a1b406b5e1c32b344cf53d9dbd1 Author: Alex Bilger Date: Mon Jan 20 00:10:57 2025 +0100 [Type] Simplification of the Rebind trait using concepts (#5200) * [Type] Simplification of the Rebind trait using concepts * fix * fix and test * parentheses commit 1f11bee4fd3d2611374a0766048f9ec18fbdf3dd Author: Alex Bilger Date: Fri Jan 17 12:39:13 2025 +0100 [Type] Deprecate is_container trait (#5210) commit 3635db7b3daa2d774719075032d45774474e1b04 Author: Alex Bilger Date: Fri Jan 17 08:19:18 2025 +0100 [Type] Convert enable_if to concepts in fixed_array (#5205) commit 107221785bcf8889e6ba48255de743824f94824e Author: Alex Bilger Date: Fri Jan 17 05:42:59 2025 +0100 [Type] Convert is_fixed_array trait to concept (#5209) Co-authored-by: Frederick Roy commit d83d7eda04ec21daf816280034a3631d076c0b9f Author: Alex Bilger Date: Fri Jan 17 01:46:10 2025 +0100 [Type] Convert is_vector trait to concept (#5201) * [Type] Concert is_vector trait to concept * fix * use the concept commit 84e79d16059e78b533486715646f781143c1ac2d Author: Alex Bilger Date: Thu Jan 16 02:48:10 2025 +0100 [Type] A concept for isRigidType (#5199) * [Type] A concept for isRigidType * fix commit f28c570df80c8c479126a6f84150eec2d33177f6 Author: Hugo Date: Wed Jan 15 14:29:40 2025 +0100 [Helper] Fix warning in SelectableItem (#5163) * [Helper] Fix warning in SelectableItem * simpler code * simplify trait using concept * remove unused include --------- Co-authored-by: Alex Bilger commit bf730d23c958a72d06b486164604ec2baafca9ad Author: Hugo Date: Wed Jan 15 05:48:20 2025 +0100 [SolidMechanics] Make Data innerRadius of BeamFEMFF not required (#5203) commit 964136a2c24ba73ac9c77d11da2f8bb8967a3f4f Author: Hugo Date: Thu Jan 9 16:37:53 2025 +0100 [Mapping] Fix draw in RigidMapping (#5204) * [Mapping] Fix draw in RigidMapping * Apply suggestions from code review Co-authored-by: Frederick Roy --------- Co-authored-by: Frederick Roy commit 61d4924ad8c4a35efd88b6d9d9375f2995abd15d Author: Hugo Date: Thu Jan 9 14:35:29 2025 +0100 [Engine] Fix drawLines from ValuesFromPositions (#5206) commit 88320b856fea453ee6311d922f888446acda8018 Author: Alex Bilger Date: Thu Jan 9 07:39:53 2025 +0100 [Config] Introduce SOFA modules data structure (#5148) * Introduce SOFA modules data structure * apply everywhere * don't shadow with unique name * try to fix * generate unit tests automatically * remove dependency to string and make modules constexpr * restore conversion to string * constexpr * remove ambiguity * include modules.h only when necessary commit 1cbfa0351a8518236cc4244a13caed30c71b5d79 Author: Alex Bilger Date: Thu Jan 9 06:09:39 2025 +0100 [DefaultType] Aliases defined twice (#5198) commit 589ea722a36426112f63de90f94ac0a55c8ef27d Author: Alex Bilger Date: Thu Jan 9 01:34:09 2025 +0100 [Core] Isolate the intrusive reference counting (#5149) * [Core] Isolate the intrusive reference counting * add unit tests commit 7b3729f1e1d0e073e64d916f003ef0a64dbcb7bc Author: erik pernod Date: Wed Jan 8 23:33:30 2025 +0100 [Topology] Add function in BaseMeshTopology to compute all topology containers (#3368) * [Topology] rename method initTpology into initContainers and provide access to it from BaseMeshTopology * [MultiThreading] Replace call to getter to init topology by call to initContainers * Fix MeshTopology initContainer * REname initContainers into computeCrossElementBuffers * restore comment * Fix compilation * Update MeshTopology.cpp * Update MeshTopology.cpp * Update applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBVHNarrowPhase.cpp Co-authored-by: Hugo * Update MeshTopology, Keep method ComputeCorssElementBuffer to be call only if needed. Not called at init * Update MeshTopology.h * Update MeshTopology.cpp * Update MeshTopology.h --------- Co-authored-by: Hugo commit 292f5bce9482ecf9632d0a6abe139447e5af3986 Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Wed Jan 8 23:32:44 2025 +0100 [tools] Update post-install fixup to fix rpath (#5197) Update post-install fixup to fix rpath commit 0bc3fb947d9e7b880d2dd863af0aff42e4ca94ee Author: Damien Marchal Date: Mon Jan 6 15:30:09 2025 +0100 [GUI.Qt] Fix invalid color of the warning sign on object (#5190) Fix invalid color of the warning sign on object. commit b5c1f179778b06d8017aa7d2ab394c30fe0a34c9 Author: Hugo Date: Mon Dec 30 12:28:46 2024 +0100 [all] Fix additional warnings (#5180) * [all] Fix additional warnings * Update Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp Co-authored-by: erik pernod * Update Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp --------- Co-authored-by: erik pernod commit 82c4ea2a35689fd14b893a330fd5f3920f69c95d Author: Frederick Roy Date: Sun Dec 29 04:08:56 2024 +0900 [Multithreading] Apply new factory registration mechanism (#5178) * apply new register mechanism to multithreading * fix test * Apply suggestions from code review (update descriptions) Co-authored-by: Hugo --------- Co-authored-by: Hugo commit bcc5a16dd65819649a137e13cba949310c23b65f Author: Frederick Roy Date: Sat Dec 28 00:26:20 2024 +0900 [Helper] PluginManager: support loading from Non-MSVC Multi-Configuration Build (#5133) * remove collections from searchable paths * cmake: pass config info and use it for search paths * remove typo in template parameters * add support for minsizerel * test existence of directory before browsing * just use the string commit 07ce419939a110e39573e3593f68c6d982fc7d05 Author: erik pernod Date: Fri Dec 27 10:57:04 2024 +0100 [Sofa.GL] Fix OglModel crash when texture file is not found (#5182) [OglModel] Backup fix on texture not found crash commit 3711b9e806b63fde2361ceba0298c8c0c3493028 Author: erik pernod Date: Fri Dec 27 10:56:45 2024 +0100 [Core] Fix VisualState.h compilation on windows (#5181) [Visual] Fix VisualState.h compilation commit 238851c9e97237c8a9d30a62277ca8b63be56600 Author: Alex Bilger Date: Thu Dec 26 22:01:07 2024 +0100 [SofaCUDA] Explicit the CUDA C++ standard version to 17 (#5165) commit 30844d0078e1d509b9555491bfe7a1e7aba0610a Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Thu Dec 26 18:36:11 2024 +0100 [Plugins] Remove unsupported plugins: InvertibleFVM, SofaSimpleGUI and SensableEmulation (#5175) Remove unsupported plugins commit e2b94280b27e59533f1080d736fa93d66137a541 Author: Alex Bilger Date: Mon Dec 23 05:52:16 2024 +0100 [Testing] Mitigate plugin import leakage between tests (#5161) * [Testing] ScopedPlugin * add version with lists * unload plugins at tear down * use ScopedPlugin in a test as an example * support multiple calls to loadPlugins commit ca6655444308f62edc0573ba4a093a93271eae2b Author: Alex Bilger Date: Fri Dec 20 13:31:30 2024 +0100 [Config] Upgrade to C++20 (#5111) commit 642cdc6e3971d1d15e77c547f658e1339c0cd173 Author: Hugo Date: Fri Dec 20 04:54:50 2024 +0100 [Lagrangian] Remove unused data numericalTolerance in BLC (#5164) commit 3e508d34dabf30754009cbdb891f32136327ea07 Author: Alex Bilger Date: Fri Dec 20 04:53:09 2024 +0100 [Type] Test and clean BoundingBox (#5138) [Type] Test for BoundingBox commit 3ecd69c9374c47ef411e55072e5dc604bafe5134 Author: Alex Bilger Date: Wed Dec 18 17:24:59 2024 +0100 [SofaCUDA] Remove NO_CUDA condition (#5171) commit 4aca2680b8ace1c0504a0977343c89cbe1137fac Author: Frederick Roy Date: Wed Dec 18 21:28:35 2024 +0900 [Core, Simulation.Core] Registration: (re)enable deprecation warnings (#5155) * enable deprecation warnings for RegisterObject * enable runtime deprecation warnings * re enable disabled tests * fix typo * fix units tests * expect a warning when loading pluginA * load plugins once (avoiding registering several times) * add more info when warning the user of a deprecated registration * set warnings only if dev mode is enabled (SOFA_WITH_DEVTOOLS enabled) * apply new mechanism registration to AugmentedLagrangianConstraint commit 99df0a21e3764151270fe9f698387b599cb5618a Author: Alex Bilger Date: Tue Dec 17 15:26:53 2024 +0100 [Visual] Move, rename and clean OglCylinderModel (#5124) * move files * depreciation * rename * fix color management * remove string to color conversion and use the one from RGBAColor * remove unused private methods * cleaning * component change * remove Index alias * change the description * cache drawTool * remove calls to removed functions commit 02b33665a966ba1bee142e438fca937d21f62096 Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Tue Dec 17 02:06:24 2024 +0100 [All] Fix visualisation (#5152) * Fix visualisation * Remove inheritance from visual model; Remove the use of visitor for VisualStyle and instead call the fwdDraw directly in the two visualVisitor * Change methods name * Update Sofa/framework/Core/src/sofa/core/visual/BaseVisualStyle.h Co-authored-by: Alex Bilger --------- Co-authored-by: Alex Bilger commit 4eda9c72c7b16b665a02f0e8ff36d88d28e17f1f Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Fri Dec 13 15:52:24 2024 +0100 [Constraint.Lagrangian] Add augmented lagrangians (#5003) * Add AugmentedLagrangianConstraint response * accelerate GS convergence * Added virtualization layer for constraints, but linker issue arise. Need to fix it then add virutalization in Contact response * FIX linking * Add virtualization layer for contact response * Fix OBBCapsule * Fix Distance grid and simplify fix for OBB * Fix default friction used by tests * Try fix macos compilation * Add tag for augmented lagrangian * add details to the description of epsilon data * remove multiple registration in factory * MAke parameters struct final * USe data accessor instead * fix compilation * Try fix scene tests * Apply suggestions from code review Co-authored-by: Hugo * Add reference --------- Co-authored-by: Hugo commit 8ba12f01996dcfe4c9d8a9a3230cf833a50a57ef Author: Hugo Date: Fri Dec 13 03:22:11 2024 +0100 [examples] Make symplectic option explicit (#5159) [Explicit] Make symplectic option explicit commit 6ae972f797baed60ee64337d6bee42813c04f640 Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Wed Dec 11 13:56:40 2024 +0100 [Constraint.Projective] Make LinearVelocityProjectiveConstraint work with FreeMotionAL (#5025) * Implement missing methods to work in FreeMotionAnimationLoop and add feature to keep the constraint applied after all the key event have passed * Apply suggestions from code review Co-authored-by: Hugo * Use constexpr when possible * Add example scene * Simplify the example and added the complete scene in the demo folder * Refactor finished mechanism and fix behavior when finished * Update scenes and regression tests * Put the boolean test on wether the constraint is still active or not inside a method --------- Co-authored-by: Hugo commit 6141aac9c1e59608cf1cde4f760f32a3af6bb67c Author: Frederick Roy Date: Wed Dec 11 18:29:09 2024 +0900 [All] Remove spam warnings (#5156) * fix duplicated macro * fix unused variables * use new vecids --- CHANGELOG.md | 229 + CMakeLists.txt | 4 +- .../animationloop/FreeMotionAnimationLoop.h | 4 +- .../animationloop/MultiStepAnimationLoop.h | 6 +- Sofa/Component/CMakeLists.txt | 7 + .../algorithm/BruteForceBroadPhase.h | 4 +- .../collision/detection/algorithm/IncrSAP.h | 4 +- .../tests/CollisionPipeline_test.cpp | 8 +- .../intersection/BaseProximityIntersection.h | 6 +- .../detection/intersection/LocalMinDistance.h | 10 +- .../intersection/MinProximityIntersection.h | 12 +- .../intersection/NewProximityIntersection.h | 4 +- .../tests/LocalMinDistance_test.cpp | 8 +- .../component/collision/detection/init.cpp | 5 +- .../component/collision/geometry/LineModel.h | 6 +- .../component/collision/geometry/PointModel.h | 8 +- .../component/collision/geometry/RayModel.h | 4 +- .../collision/geometry/SphereModel.h | 6 +- .../Collision/Geometry/tests/Sphere_test.cpp | 8 +- .../Geometry/tests/Triangle_test.cpp | 4 +- .../Collision/Response/Contact/CMakeLists.txt | 6 + .../contact/AugmentedLagrangianResponse.cpp | 85 + .../contact/AugmentedLagrangianResponse.h | 67 + .../contact/AugmentedLagrangianResponse.inl | 65 + .../contact/BarycentricStickContact.h | 4 +- .../contact/BaseUnilateralContactResponse.h | 101 + .../contact/BaseUnilateralContactResponse.inl | 271 + .../response/contact/CollisionResponse.h | 6 +- .../response/contact/FrictionContact.cpp | 22 + .../response/contact/FrictionContact.h | 65 +- .../response/contact/FrictionContact.inl | 223 +- .../contact/RuleBasedContactManager.h | 4 +- .../response/contact/StickContactConstraint.h | 4 +- .../TetrahedronAugmentedLagrangianContact.cpp | 60 + .../contact/TetrahedronFrictionContact.cpp | 7 + .../Response/Contact/tests/CMakeLists.txt | 3 +- .../collision/response/mapper/init.cpp | 1 + .../component/collision/response/init.cpp | 5 +- .../src/sofa/component/collision/init.cpp | 7 +- .../PrecomputedConstraintCorrection.h | 14 +- .../UncoupledConstraintCorrection.h | 8 +- .../UncoupledConstraintCorrection.inl | 2 +- .../Lagrangian/Model/CMakeLists.txt | 6 + .../model/AugmentedLagrangianConstraint.cpp | 109 + .../model/AugmentedLagrangianConstraint.h | 87 + .../model/AugmentedLagrangianConstraint.inl | 70 + .../model/AugmentedLagrangianResolution.h | 74 + .../model/BaseContactLagrangianConstraint.h | 160 + .../model/BaseContactLagrangianConstraint.inl | 386 + .../model/BilateralLagrangianConstraint.cpp | 6 +- .../model/BilateralLagrangianConstraint.h | 13 +- .../model/BilateralLagrangianConstraint.inl | 2 - .../model/StopperLagrangianConstraint.h | 8 +- .../model/UnilateralLagrangianConstraint.cpp | 7 + .../model/UnilateralLagrangianConstraint.h | 122 +- .../model/UnilateralLagrangianConstraint.inl | 373 +- .../constraint/lagrangian/model/config.h.in | 10 + .../constraint/lagrangian/model/init.cpp | 2 + .../solver/GenericConstraintSolver.h | 32 +- .../lagrangian/solver/LCPConstraintSolver.h | 40 +- .../component/constraint/lagrangian/init.cpp | 7 +- .../AffineMovementProjectiveConstraint.h | 18 +- .../DirectionProjectiveConstraint.h | 8 +- .../FixedRotationProjectiveConstraint.h | 8 +- .../FixedTranslationProjectiveConstraint.h | 10 +- .../HermiteSplineProjectiveConstraint.h | 20 +- .../projective/LineProjectiveConstraint.h | 10 +- .../LinearMovementProjectiveConstraint.h | 10 +- .../LinearVelocityProjectiveConstraint.h | 27 +- .../LinearVelocityProjectiveConstraint.inl | 226 +- .../OscillatorProjectiveConstraint.h | 4 +- .../ParabolicProjectiveConstraint.h | 14 +- ...artialLinearMovementProjectiveConstraint.h | 28 +- .../projective/PlaneProjectiveConstraint.h | 10 +- .../projective/PointProjectiveConstraint.h | 10 +- ...ositionBasedDynamicsProjectiveConstraint.h | 10 +- .../SkeletalMotionProjectiveConstraint.h | 10 +- ...ffineMovementProjectiveConstraint_test.cpp | 2 +- .../DirectionProjectiveConstraint_test.cpp | 4 +- .../tests/FixedProjectiveConstraint_test.cpp | 6 +- .../tests/LineProjectiveConstraint_test.cpp | 4 +- .../tests/PlaneProjectiveConstraint_test.cpp | 4 +- .../tests/PointProjectiveConstraint_test.cpp | 4 +- .../src/sofa/component/constraint/init.cpp | 5 +- .../sofa/component/controller/Controller.h | 4 +- .../controller/MechanicalStateController.h | 10 +- .../sofa/component/engine/analyze/Distances.h | 32 +- .../engine/analyze/HausdorffDistance.h | 14 +- .../component/engine/analyze/ShapeMatching.h | 18 +- .../Analyze/tests/AverageCoord_test.cpp | 2 +- .../Analyze/tests/ClusteringEngine_test.cpp | 2 +- .../engine/generate/MeshTetraStuffing.h | 26 +- .../ExtrudeEdgesAndGenerateQuads_test.cpp | 2 +- .../Generate/tests/MergePoints_test.cpp | 2 +- .../sofa/component/engine/select/BaseROI.h | 4 +- .../sofa/component/engine/select/MeshROI.h | 8 +- .../sofa/component/engine/select/MeshROI.inl | 4 +- .../engine/select/MeshSubsetEngine.h | 20 +- .../sofa/component/engine/select/SphereROI.h | 14 +- .../engine/select/ValuesFromPositions.inl | 3 +- .../Engine/Select/tests/BoxROI_test.cpp | 11 +- .../Select/tests/ComplementaryROI_test.cpp | 2 +- .../Engine/Select/tests/MeshROI_test.cpp | 10 +- .../Select/tests/MeshSubsetEngine_test.cpp | 6 +- .../Engine/Select/tests/PlaneROI_test.cpp | 2 +- .../Engine/Select/tests/SphereROI_test.cpp | 2 +- .../Transform/tests/DifferenceEngine_test.cpp | 2 +- .../Transform/tests/DilateEngine_test.cpp | 2 +- .../Transform/tests/SmoothMeshEngine_test.cpp | 2 +- .../Engine/src/sofa/component/engine/init.cpp | 9 +- .../sofa/component/haptics/LCPForceFeedback.h | 6 +- .../sofa/component/io/mesh/BlenderExporter.h | 12 +- .../sofa/component/io/mesh/GridMeshCreator.h | 6 +- .../sofa/component/io/mesh/MeshSTLLoader.h | 6 +- .../sofa/component/io/mesh/MeshTrianLoader.h | 10 +- .../component/io/mesh/OffSequenceLoader.h | 6 +- .../component/io/mesh/StringMeshCreator.h | 4 +- .../src/sofa/component/io/mesh/VTKExporter.h | 28 +- .../sofa/component/io/mesh/VoxelGridLoader.h | 20 +- .../IO/Mesh/tests/MeshExporter_test.cpp | 8 +- .../IO/Mesh/tests/MeshGmshLoader_test.cpp | 2 +- .../IO/Mesh/tests/MeshXspLoader_test.cpp | 2 +- .../IO/Mesh/tests/STLExporter_test.cpp | 10 +- .../tests/VisualModelOBJExporter_test.cpp | 4 +- .../IO/src/sofa/component/io/init.cpp | 3 +- .../direct/PrecomputedLinearSolver.h | 6 +- .../linearsolver/direct/SVDLinearSolver.h | 8 +- .../Direct/tests/SparseLDLSolver_test.cpp | 22 +- .../linearsolver/iterative/PCGLinearSolver.h | 14 +- .../PrecomputedWarpPreconditioner.h | 12 +- .../preconditioner/SSORPreconditioner.h | 4 +- .../src/sofa/component/linearsolver/init.cpp | 9 +- .../LinearSystem/tests/MappingGraph_test.cpp | 2 +- .../mapping/linear/BarycentricMappingRigid.h | 6 +- .../linear/DeformableOnRigidFrameMapping.h | 14 +- .../mapping/linear/SkinningMapping.h | 14 +- .../component/mapping/linear/SubsetMapping.h | 16 +- .../mapping/linear/SubsetMultiMapping.h | 4 +- .../component/mapping/linear/TubularMapping.h | 8 +- .../Linear/tests/BarycentricMapping_test.cpp | 2 +- .../nonlinear/DistanceFromTargetMapping.h | 8 +- .../mapping/nonlinear/DistanceMapping.h | 6 +- .../mapping/nonlinear/DistanceMultiMapping.h | 6 +- .../mapping/nonlinear/RigidMapping.inl | 5 +- .../NonLinear/tests/RigidMapping_test.cpp | 2 +- .../tests/SquareDistanceMapping_test.cpp | 4 +- .../src/sofa/component/mapping/init.cpp | 5 +- .../Mass/tests/DiagonalMass_test.cpp | 12 +- .../Mass/tests/MeshMatrixMass_test.cpp | 12 +- .../Component/Mass/tests/UniformMass_test.cpp | 8 +- .../mechanicalload/EdgePressureForceField.h | 24 +- .../OscillatingTorsionPressureForceField.h | 22 +- .../mechanicalload/QuadPressureForceField.h | 16 +- .../mechanicalload/SphereForceField.h | 18 +- .../SurfacePressureForceField.h | 28 +- .../TaitSurfacePressureForceField.h | 38 +- .../mechanicalload/TorsionForceField.h | 10 +- .../TrianglePressureForceField.h | 12 +- .../UniformVelocityDampingForceField.h | 4 +- .../tests/ConstantForceField_test.cpp | 14 +- .../tests/PlaneForceField_test.cpp | 8 +- .../tests/SkeletalMotionConstraint_test.cpp | 4 +- .../odesolver/backward/EulerImplicitSolver.h | 12 +- .../backward/VariationalSymplecticSolver.h | 22 +- .../tests/EulerImplicitSolverStatic_test.cpp | 24 +- .../EulerImplicitSolver_withDamping_test.cpp | 10 +- .../tests/SpringSolverDynamic_test.cpp | 2 +- .../Backward/tests/StaticSolver_test.cpp | 6 +- .../forward/CentralDifferenceSolver.h | 4 +- .../odesolver/forward/DampVelocitySolver.h | 6 +- .../odesolver/testing/ODESolverSpringTest.h | 13 +- .../src/sofa/component/odesolver/init.cpp | 5 +- .../component/playback/InputEventReader.h | 12 +- .../sofa/component/playback/ReadTopology.h | 8 +- .../sofa/component/playback/WriteTopology.h | 12 +- .../Playback/tests/ReadState_test.cpp | 8 +- .../Playback/tests/WriteState_test.cpp | 8 +- .../tests/AddResourceRepository_test.cpp | 4 +- .../tests/MakeAliasComponent_test.cpp | 2 +- .../tests/MakeDataAliasComponent_test.cpp | 4 +- .../tests/MessageHandlerComponent_test.cpp | 2 +- .../component/setting/BackgroundSetting.h | 4 +- .../component/setting/MouseButtonSetting.h | 4 +- .../setting/SofaDefaultPathSetting.h | 4 +- .../src/sofa/component/setting/StatsSetting.h | 8 +- .../sofa/component/setting/ViewerSetting.h | 10 +- .../fem/elastic/BeamFEMForceField.h | 4 +- .../fem/elastic/BeamFEMForceField.inl | 3 - .../FastTetrahedralCorotationalForceField.h | 22 +- .../fem/elastic/HexahedralFEMForceField.h | 8 +- .../elastic/HexahedralFEMForceFieldAndMass.h | 14 +- .../fem/elastic/HexahedronFEMForceField.h | 20 +- .../fem/elastic/QuadBendingFEMForceField.h | 16 +- .../TetrahedralCorotationalFEMForceField.h | 24 +- .../fem/elastic/TetrahedronFEMForceField.h | 46 +- .../fem/elastic/TriangleFEMForceField.h | 14 +- .../TriangularAnisotropicFEMForceField.h | 12 +- .../fem/elastic/TriangularFEMForceField.h | 28 +- .../tests/BaseTetrahedronFEMForceField_test.h | 44 +- .../Elastic/tests/BeamFEMForceField_test.cpp | 6 +- .../tests/TriangleFEMForceField_test.cpp | 42 +- ...perelasticityFEMForceField_params_test.cpp | 2 +- ...yperelasticityFEMForceField_scene_test.cpp | 2 +- .../component/solidmechanics/fem/init.cpp | 7 +- .../spring/AngularSpringForceField.h | 12 +- .../spring/FrameSpringForceField.h | 8 +- .../spring/GearSpringForceField.h | 10 +- .../spring/JointSpringForceField.h | 6 +- .../spring/QuadBendingSprings.h | 4 +- .../spring/RestShapeSpringsForceField.inl | 1 + .../spring/TriangularBendingSprings.h | 4 +- .../TriangularBiquadraticSpringsForceField.h | 20 +- .../TriangularQuadraticSpringsForceField.h | 16 +- .../spring/VectorSpringForceField.h | 10 +- ...ynomialRestShapeSpringsForceField_test.cpp | 6 +- .../tests/RestShapeSpringsForceField_test.cpp | 8 +- .../tests/TriangularBendingSprings_test.cpp | 8 +- .../TetrahedralTensorMassForceField.h | 8 +- .../TriangularTensorMassForceField.h | 8 +- .../simutests/AffinePatch_test.cpp | 2 +- .../simutests/LinearElasticity_test.cpp | 4 +- .../sofa/component/solidmechanics/init.cpp | 7 +- .../component/statecontainer/MappedObject.h | 6 +- .../container/constant/CubeTopology.h | 16 +- .../container/constant/MeshTopology.cpp | 75 +- .../container/constant/MeshTopology.h | 30 +- .../container/constant/SphereQuadTopology.h | 6 +- .../DynamicSparseGridTopologyContainer.h | 14 +- .../dynamic/EdgeSetTopologyContainer.cpp | 4 +- .../dynamic/EdgeSetTopologyContainer.h | 6 +- .../HexahedronSetTopologyContainer.cpp | 6 +- .../dynamic/HexahedronSetTopologyContainer.h | 4 +- .../dynamic/PointSetTopologyContainer.h | 4 +- .../dynamic/QuadSetTopologyContainer.cpp | 6 +- .../dynamic/QuadSetTopologyContainer.h | 4 +- .../TetrahedronSetTopologyContainer.cpp | 6 +- .../dynamic/TetrahedronSetTopologyContainer.h | 4 +- .../dynamic/TriangleSetTopologyContainer.cpp | 6 +- .../dynamic/TriangleSetTopologyContainer.h | 4 +- .../TetrahedronNumericalIntegration_test.cpp | 4 +- .../TriangleNumericalIntegration_test.cpp | 4 +- .../grid/SparseGridMultipleTopology.h | 12 +- .../grid/SparseGridRamificationTopology.h | 4 +- .../container/grid/SparseGridTopology.h | 28 +- .../Grid/tests/SparseGridTopology_test.cpp | 2 +- .../component/topology/container/init.cpp | 7 +- .../mapping/Hexa2QuadTopologicalMapping.h | 4 +- .../mapping/Hexa2TetraTopologicalMapping.h | 4 +- .../mapping/SubsetTopologicalMapping.h | 38 +- .../Tetra2TriangleTopologicalMapping.h | 8 +- .../topology/testing/fake_TopologyScene.h | 13 +- .../utility/TopologicalChangeProcessor.h | 34 +- .../tests/TopologicalChangeProcessor_test.cpp | 4 +- .../Utility/tests/TopologyChecker_test.cpp | 4 +- .../src/sofa/component/topology/init.cpp | 7 +- Sofa/Component/Visual/CMakeLists.txt | 2 + .../src/sofa/component/visual/BaseCamera.h | 36 +- .../component/visual/CylinderVisualModel.cpp | 94 + .../component/visual/CylinderVisualModel.h | 61 + .../sofa/component/visual/InteractiveCamera.h | 8 +- .../sofa/component/visual/RecordedCamera.h | 38 +- .../sofa/component/visual/VisualModelImpl.h | 56 +- .../src/sofa/component/visual/VisualStyle.cpp | 17 +- .../src/sofa/component/visual/VisualStyle.h | 17 +- .../sofa/component/visual/VisualTransform.h | 6 +- .../Visual/src/sofa/component/visual/init.cpp | 2 + Sofa/Component/src/sofa/component/init.cpp | 43 +- Sofa/Component/test/CMakeLists.txt | 37 + Sofa/Component/test/Modules_test.cpp | 25 + .../Component/test/Modules_test.h.in | 13 +- .../Rendering2D/tests/OglLabel_test.cpp | 4 +- Sofa/GL/Component/Rendering3D/CMakeLists.txt | 1 - .../rendering3d/OglCylinderModel.cpp | 163 - .../component/rendering3d/OglCylinderModel.h | 68 +- .../gl/component/rendering3d/OglModel.cpp | 39 +- .../sofa/gl/component/rendering3d/OglModel.h | 4 +- .../sofa/gl/component/rendering3d/init.cpp | 2 - .../Rendering3D/tests/ClipPlane_test.cpp | 6 +- .../Shader/tests/LightManager_test.cpp | 8 +- Sofa/GL/Component/Shader/tests/Light_test.cpp | 6 +- .../ConstraintAttachBodyPerformer.inl | 2 +- .../sofa/gui/qt/GraphListenerQListView.cpp | 7 +- .../Qt/src/sofa/gui/qt/SimpleDataWidget.cpp | 4 +- Sofa/framework/Config/CMakeLists.txt | 5 +- .../Config/cmake/SofaMacrosUtils.cmake | 8 +- Sofa/framework/Config/src/sofa/Modules.h | 179 + Sofa/framework/Core/CMakeLists.txt | 11 +- .../Core/src/sofa/core/IntrusiveObject.cpp | 26 +- .../Core/src/sofa/core/IntrusiveObject.h | 68 +- .../Core/src/sofa/core/ObjectFactory.cpp | 7 +- .../Core/src/sofa/core/ObjectFactory.h | 4 +- .../sofa/core/behavior/BaseConstraintSet.h | 4 +- .../sofa/core/behavior/BaseMechanicalState.h | 4 +- Sofa/framework/Core/src/sofa/core/config.h.in | 2 +- .../Core/src/sofa/core/objectmodel/Base.cpp | 15 +- .../Core/src/sofa/core/objectmodel/Base.h | 20 +- .../src/sofa/core/objectmodel/BaseContext.h | 2 +- .../Core/src/sofa/core/objectmodel/BaseNode.h | 2 + .../{ => lifecycle}/DeprecatedData.cpp | 2 +- .../{ => lifecycle}/DeprecatedData.h | 0 .../objectmodel/{ => lifecycle}/RemovedData.h | 2 +- .../objectmodel/{ => lifecycle}/RenamedData.h | 2 +- .../sofa/core/topology/BaseMeshTopology.cpp | 1 - .../src/sofa/core/topology/BaseMeshTopology.h | 3 + .../src/sofa/core/visual/BaseVisualStyle.h | 69 +- .../Core/src/sofa/core/visual/VisualState.h | 2 +- Sofa/framework/Core/test/DataEngine_test.cpp | 2 +- Sofa/framework/Core/test/Engine_test.cpp | 2 +- .../Core/test/IntrusiveObject_test.cpp | 73 + .../Core/test/ObjectFactoryJson_test.cpp | 3 +- Sofa/framework/Core/test/TrackedData_test.cpp | 2 +- Sofa/framework/Core/test/VecId_test.cpp | 4 + .../BaseObjectDescription_test.cpp | 4 +- .../test/objectmodel/DataFileName_test.cpp | 2 +- .../Core/test/objectmodel/DataLink_test.cpp | 4 +- .../test/objectmodel/RemovedData_test.cpp | 2 +- .../Core/test/objectmodel/SingleLink_test.cpp | 2 +- .../src/sofa/defaulttype/RigidTypes.h | 7 + .../src/sofa/defaulttype/VecTypes.h | 13 + .../DefaultType/src/sofa/defaulttype/fwd.h | 9 - Sofa/framework/Helper/CMakeLists.txt | 22 +- .../Helper/simutest/AdvancedTimer_test.cpp | 2 +- .../src/sofa/helper/ComponentChange.cpp | 864 +- .../Helper/src/sofa/helper/OptionsGroup.h | 9 +- .../Helper/src/sofa/helper/SelectableItem.h | 35 +- .../src/sofa/helper/accessor/ReadAccessor.h | 9 +- .../helper/accessor/ReadAccessorFixedArray.h | 2 +- .../sofa/helper/accessor/ReadAccessorVector.h | 2 +- .../src/sofa/helper/accessor/WriteAccessor.h | 9 +- .../helper/accessor/WriteAccessorFixedArray.h | 2 +- .../helper/accessor/WriteAccessorVector.h | 3 +- .../sofa/helper/accessor/WriteOnlyAccessor.h | 5 +- .../src/sofa/helper/system/FileRepository.cpp | 4 +- .../src/sofa/helper/system/PluginManager.cpp | 96 +- .../framework/Helper/test/io/MeshOBJ_test.cpp | 4 +- .../Helper/test/io/STBImage_test.cpp | 4 +- .../Helper/test/io/XspLoader_test.cpp | 4 +- .../Helper/test/system/PluginManager_test.cpp | 22 +- .../BaseMatrix_test.h | 4 +- ...essedRowSparseMatrixConstraintEigenUtils.h | 2 +- .../CompressedRowSparseMatrixMechanical.h | 2 +- .../SimpleApi/test/SimpleApi_test.cpp | 4 +- .../Core/simutest/NodeContext_test.cpp | 4 +- .../sofa/simulation/MechanicalOperations.h | 2 +- .../Core/src/sofa/simulation/Node.cpp | 7 + .../Core/src/sofa/simulation/Node.h | 3 + .../src/sofa/simulation/RequiredPlugin.cpp | 11 +- .../Core/src/sofa/simulation/Simulation.cpp | 3 +- .../src/sofa/simulation/VisualVisitor.cpp | 46 +- .../Core/src/sofa/simulation/VisualVisitor.h | 12 +- .../Core/src/sofa/simulation/config.h.in | 4 +- ...lPropagateOnlyPositionAndVelocityVisitor.h | 2 +- .../MechanicalPropagateOnlyVelocityVisitor.h | 2 +- .../Core/test/RequiredPlugin_test.cpp | 8 +- .../Graph/test/MutationListener_test.cpp | 4 +- .../simutest/parallel_scenes_test.cpp | 71 +- Sofa/framework/Testing/CMakeLists.txt | 2 + .../Testing/src/sofa/testing/BaseTest.cpp | 11 +- .../Testing/src/sofa/testing/BaseTest.h | 17 +- .../Testing/src/sofa/testing/ScopedPlugin.cpp | 60 + .../Testing/src/sofa/testing/ScopedPlugin.h | 68 + .../Testing/src/sofa/testing/config.h.in | 17 + Sofa/framework/Testing/test/CMakeLists.txt | 3 +- .../Testing/test/ScopedPlugin_test.cpp | 59 + .../Type/src/sofa/type/BoundingBox.cpp | 50 +- .../Type/src/sofa/type/BoundingBox.h | 79 +- Sofa/framework/Type/src/sofa/type/MatSym.h | 2 +- Sofa/framework/Type/src/sofa/type/Quat.h | 42 +- Sofa/framework/Type/src/sofa/type/RGBAColor.h | 45 +- Sofa/framework/Type/src/sofa/type/Vec.h | 33 + Sofa/framework/Type/src/sofa/type/config.h.in | 18 + .../Type/src/sofa/type/fixed_array.h | 10 +- .../Type/src/sofa/type/isRigidType.h | 60 +- .../Type/src/sofa/type/trait/Rebind.h | 36 +- .../Type/src/sofa/type/trait/is_container.h | 5 + .../Type/src/sofa/type/trait/is_fixed_array.h | 36 +- .../Type/src/sofa/type/trait/is_vector.h | 36 +- Sofa/framework/Type/test/BoundingBox_test.cpp | 123 + Sofa/framework/Type/test/CMakeLists.txt | 2 + Sofa/framework/Type/test/MatSym_test.cpp | 2 +- Sofa/framework/Type/test/Quater_test.cpp | 10 +- Sofa/framework/Type/test/RGBAColor_test.cpp | 15 + Sofa/framework/Type/test/Rebind_test.cpp | 59 + Sofa/framework/Type/test/StrongType_test.cpp | 1 + Sofa/framework/Type/test/VecTypes_test.cpp | 9 +- Sofa/framework/Type/test/vector_test.cpp | 18 +- .../CImgPlugin_test/ImageCImg_test.cpp | 4 +- applications/plugins/CMakeLists.txt | 5 +- .../response/contact/CapsuleContact.cpp | 13 + .../response/contact/OBBContact.cpp | 7 + .../ExternalProjectConfig.cmake.in | 14 - .../src/MultiThreading/DataExchange.cpp | 34 +- .../src/MultiThreading/MeanComputation.cpp | 16 +- .../AnimationLoopParallelScheduler.cpp | 8 +- .../algorithm/ParallelBVHNarrowPhase.cpp | 27 +- .../ParallelBruteForceBroadPhase.cpp | 10 +- .../iterative/ParallelCGLinearSolver.cpp | 11 +- .../mapping/linear/BeamLinearMapping_mt.cpp | 10 +- .../ParallelHexahedronFEMForceField.cpp | 12 +- .../ParallelTetrahedronFEMForceField.cpp | 10 +- .../ParallelTetrahedronFEMForceField.h | 2 +- .../ParallelTetrahedronFEMForceField.inl | 2 +- .../spring/ParallelMeshSpringForceField.cpp | 11 +- .../spring/ParallelSpringForceField.cpp | 15 +- .../src/MultiThreading/config.h.in | 9 +- .../src/MultiThreading/initMultiThreading.cpp | 70 +- .../ParallelImplementationsRegistry_test.cpp | 12 +- .../SceneCreator_test/SceneCreator_test.cpp | 6 +- .../src/SceneCreator/SceneCreator.cpp | 11 +- .../plugins/SensableEmulation/CMakeLists.txt | 43 - .../SensableEmulation/NewOmniDriverEmu.cpp | 547 - .../SensableEmulation/NewOmniDriverEmu.h | 162 - .../SensableEmulation/OmniDriverEmu.cpp | 589 - .../plugins/SensableEmulation/OmniDriverEmu.h | 173 - .../PluginSensableEmulation.txt | 10 - .../examples/SimpleBox-Method2.scn | 75 - .../examples/SimpleBox-Method2.scn.view | 19 - .../examples/data/mesh/box.obj | 20 - .../examples/data/mesh/dental_instrument.obj | 1194 - .../examples/testOmniDriverEmu.scn | 30 - .../SensableEmulation/pthread/pthread.h | 1368 - .../SensableEmulation/pthread/pthreadVC2.dll | Bin 55808 -> 0 bytes .../SensableEmulation/pthread/pthreadVC2.lib | Bin 30334 -> 0 bytes .../plugins/SensableEmulation/pthread/sched.h | 183 - .../SensableEmulation/pthread/semaphore.h | 169 - applications/plugins/SofaCUDA/CMakeLists.txt | 2 +- .../plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu | 138 - .../SofaCarving_test/SofaCarving_test.cpp | 5 +- .../RegisterModelToCollisionFactory.cpp | 1 + .../plugins/SofaSimpleGUI/CMakeLists.txt | 44 - applications/plugins/SofaSimpleGUI/Camera.cpp | 196 - applications/plugins/SofaSimpleGUI/Camera.h | 86 - .../plugins/SofaSimpleGUI/Interactor.cpp | 35 - .../plugins/SofaSimpleGUI/Interactor.h | 58 - .../plugins/SofaSimpleGUI/PickedPoint.h | 64 - applications/plugins/SofaSimpleGUI/README.txt | 8 - .../plugins/SofaSimpleGUI/SimpleGUI.dox | 45 - applications/plugins/SofaSimpleGUI/SofaGL.cpp | 322 - applications/plugins/SofaSimpleGUI/SofaGL.h | 153 - .../plugins/SofaSimpleGUI/SofaGlutAnt.zip | Bin 5452 -> 0 bytes .../plugins/SofaSimpleGUI/SofaScene.cpp | 154 - .../plugins/SofaSimpleGUI/SofaScene.h | 120 - .../SofaSimpleGUIConfig.cmake.in | 15 - .../SofaSimpleGUI/SpringInteractor.cpp | 68 - .../plugins/SofaSimpleGUI/SpringInteractor.h | 54 - .../SofaSimpleGUI/VisualPickVisitor.cpp | 138 - .../plugins/SofaSimpleGUI/VisualPickVisitor.h | 43 - .../plugins/SofaSimpleGUI/doc/Doxyfile | 1918 -- .../SofaSimpleGUI/doc/DoxygenLayout.xml | 185 - .../plugins/SofaSimpleGUI/doc/SimpleGUI.png | Bin 18862 -> 0 bytes .../plugins/SofaSimpleGUI/doc/index.html | 154 - .../plugins/SofaSimpleGUI/examples/liver.scn | 42 - .../plugins/SofaSimpleGUI/examples/oneTet.scn | 32 - .../image/image_test/DataImage_test.cpp | 2 +- .../image/image_test/ImageEngine_test.cpp | 2 +- .../SceneChecking/tests/SceneChecker_test.cpp | 9 +- .../SofaPhysicsAPI/SofaPhysicsSimulation.cpp | 15 +- .../runSofa/runSofa_test/runSofa_test.cpp | 4 +- .../LinearVelocityProjectiveConstraint.scn | 70 + .../Forward/EulerSymplecticSolver.scn | 2 +- .../EulerSymplecticSolver_diagonal.scn | 2 +- .../Component/Visual/CylinderVisualModel.scn | 8 + .../Component/Visual/OglCylinderModel.scn | 9 - examples/Demos/SofaWasher.scn | 115 + ...allingBeamAugmentedLagrangianCollision.scn | 92 + .../RegressionStateScenes.regression-tests | 1 + share/mesh/SOFA_collision_center.obj | 331 + share/mesh/SOFA_collision_no_face.obj | 663 + share/mesh/SOFA_surface.obj | 2409 ++ share/mesh/SOFA_volume.vtk | 27110 ++++++++++++++++ .../macos-postinstall-fixup.sh | 8 +- 471 files changed, 36486 insertions(+), 12018 deletions(-) create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.cpp create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.h create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.h create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.inl create mode 100644 Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronAugmentedLagrangianContact.cpp create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.cpp create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.h create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.inl create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianResolution.h create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.h create mode 100644 Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.inl create mode 100644 Sofa/Component/Visual/src/sofa/component/visual/CylinderVisualModel.cpp create mode 100644 Sofa/Component/Visual/src/sofa/component/visual/CylinderVisualModel.h create mode 100644 Sofa/Component/test/CMakeLists.txt create mode 100644 Sofa/Component/test/Modules_test.cpp rename applications/plugins/SofaSimpleGUI/config.h.in => Sofa/Component/test/Modules_test.h.in (86%) delete mode 100644 Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglCylinderModel.cpp create mode 100644 Sofa/framework/Config/src/sofa/Modules.h rename applications/plugins/SensableEmulation/config.h => Sofa/framework/Core/src/sofa/core/IntrusiveObject.cpp (83%) rename applications/plugins/SensableEmulation/initSensableEmulation.cpp => Sofa/framework/Core/src/sofa/core/IntrusiveObject.h (61%) rename Sofa/framework/Core/src/sofa/core/objectmodel/{ => lifecycle}/DeprecatedData.cpp (97%) rename Sofa/framework/Core/src/sofa/core/objectmodel/{ => lifecycle}/DeprecatedData.h (100%) rename Sofa/framework/Core/src/sofa/core/objectmodel/{ => lifecycle}/RemovedData.h (97%) rename Sofa/framework/Core/src/sofa/core/objectmodel/{ => lifecycle}/RenamedData.h (99%) rename applications/plugins/SofaSimpleGUI/initSimpleGUI.cpp => Sofa/framework/Core/src/sofa/core/visual/BaseVisualStyle.h (58%) create mode 100644 Sofa/framework/Core/test/IntrusiveObject_test.cpp create mode 100644 Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.cpp create mode 100644 Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.h create mode 100644 Sofa/framework/Testing/test/ScopedPlugin_test.cpp create mode 100644 Sofa/framework/Type/test/BoundingBox_test.cpp create mode 100644 Sofa/framework/Type/test/Rebind_test.cpp delete mode 100644 applications/plugins/InvertibleFVM/ExternalProjectConfig.cmake.in delete mode 100644 applications/plugins/SensableEmulation/CMakeLists.txt delete mode 100644 applications/plugins/SensableEmulation/NewOmniDriverEmu.cpp delete mode 100644 applications/plugins/SensableEmulation/NewOmniDriverEmu.h delete mode 100644 applications/plugins/SensableEmulation/OmniDriverEmu.cpp delete mode 100644 applications/plugins/SensableEmulation/OmniDriverEmu.h delete mode 100644 applications/plugins/SensableEmulation/PluginSensableEmulation.txt delete mode 100644 applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn delete mode 100644 applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn.view delete mode 100644 applications/plugins/SensableEmulation/examples/data/mesh/box.obj delete mode 100644 applications/plugins/SensableEmulation/examples/data/mesh/dental_instrument.obj delete mode 100644 applications/plugins/SensableEmulation/examples/testOmniDriverEmu.scn delete mode 100644 applications/plugins/SensableEmulation/pthread/pthread.h delete mode 100644 applications/plugins/SensableEmulation/pthread/pthreadVC2.dll delete mode 100644 applications/plugins/SensableEmulation/pthread/pthreadVC2.lib delete mode 100644 applications/plugins/SensableEmulation/pthread/sched.h delete mode 100644 applications/plugins/SensableEmulation/pthread/semaphore.h delete mode 100644 applications/plugins/SofaSimpleGUI/CMakeLists.txt delete mode 100644 applications/plugins/SofaSimpleGUI/Camera.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/Camera.h delete mode 100644 applications/plugins/SofaSimpleGUI/Interactor.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/Interactor.h delete mode 100644 applications/plugins/SofaSimpleGUI/PickedPoint.h delete mode 100644 applications/plugins/SofaSimpleGUI/README.txt delete mode 100644 applications/plugins/SofaSimpleGUI/SimpleGUI.dox delete mode 100644 applications/plugins/SofaSimpleGUI/SofaGL.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/SofaGL.h delete mode 100644 applications/plugins/SofaSimpleGUI/SofaGlutAnt.zip delete mode 100644 applications/plugins/SofaSimpleGUI/SofaScene.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/SofaScene.h delete mode 100644 applications/plugins/SofaSimpleGUI/SofaSimpleGUIConfig.cmake.in delete mode 100644 applications/plugins/SofaSimpleGUI/SpringInteractor.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/SpringInteractor.h delete mode 100644 applications/plugins/SofaSimpleGUI/VisualPickVisitor.cpp delete mode 100644 applications/plugins/SofaSimpleGUI/VisualPickVisitor.h delete mode 100644 applications/plugins/SofaSimpleGUI/doc/Doxyfile delete mode 100644 applications/plugins/SofaSimpleGUI/doc/DoxygenLayout.xml delete mode 100644 applications/plugins/SofaSimpleGUI/doc/SimpleGUI.png delete mode 100644 applications/plugins/SofaSimpleGUI/doc/index.html delete mode 100644 applications/plugins/SofaSimpleGUI/examples/liver.scn delete mode 100644 applications/plugins/SofaSimpleGUI/examples/oneTet.scn create mode 100644 examples/Component/Constraint/Projective/LinearVelocityProjectiveConstraint.scn create mode 100644 examples/Component/Visual/CylinderVisualModel.scn delete mode 100644 examples/Component/Visual/OglCylinderModel.scn create mode 100644 examples/Demos/SofaWasher.scn create mode 100644 examples/Demos/fallingBeamAugmentedLagrangianCollision.scn create mode 100644 share/mesh/SOFA_collision_center.obj create mode 100644 share/mesh/SOFA_collision_no_face.obj create mode 100644 share/mesh/SOFA_surface.obj create mode 100644 share/mesh/SOFA_volume.vtk diff --git a/CHANGELOG.md b/CHANGELOG.md index d9da7f731b5..f6dd626aab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,235 @@ # SOFA Changelog + +## [v24.12.00]( https://github.com/sofa-framework/sofa/tree/v24.12.00 ) + +[Full log]( https://github.com/sofa-framework/sofa/compare/v24.06..v24.12 ) + +### Highlighted contributions + +- [All] ObjectFactory: Explicit components registration [#4429](https://github.com/sofa-framework/sofa/pull/4429) +- [Mapping.NonLinear] Introduce AreaMapping [#4898](https://github.com/sofa-framework/sofa/pull/4898) +- [Mapping.NonLinear] Introduce VolumeMapping [#4906](https://github.com/sofa-framework/sofa/pull/4906) +- [Constraint.Lagrangian] Add augmented lagrangians [#5003](https://github.com/sofa-framework/sofa/pull/5003) +- [all] Various changes relative to the constraint matrix [#5017](https://github.com/sofa-framework/sofa/pull/5017) +- [workflow][Nix] initial packaging & flake [#5059](https://github.com/sofa-framework/sofa/pull/5059) + + +### Breaking + +- [Spring] Merging StiffSpringForceField and its parent [#4649](https://github.com/sofa-framework/sofa/pull/4649) +- [Core] Deprecate Compliant API in force fields [#4776](https://github.com/sofa-framework/sofa/pull/4776) +- [FEM.Elastic] Start unification of tetra FF and division of tests [#4778](https://github.com/sofa-framework/sofa/pull/4778) +- [Core] Factorize two variables with the same meaning (constraint id) [#4786](https://github.com/sofa-framework/sofa/pull/4786) +- [Core] Proposition to reduce the number of alias declarations [#4788](https://github.com/sofa-framework/sofa/pull/4788) +- [Sofa.GL] OglModel: Deprecate/Remove isEnabled Data [#4822](https://github.com/sofa-framework/sofa/pull/4822) +- [All] VisualModel: implement NVI for init/updateVisual() [#4827](https://github.com/sofa-framework/sofa/pull/4827) +- [FEM.Elastic] Hexa FEM inherits from BaseLinearElasticityFEMForceField [#4832](https://github.com/sofa-framework/sofa/pull/4832) +- [All] Reduce use of raw pointers [#4838](https://github.com/sofa-framework/sofa/pull/4838) +- [Component.Engine.Select] Refactoring of ROI classes [#4839](https://github.com/sofa-framework/sofa/pull/4839) +- [GUI.Qt] Add find or fetch for qgl viewer [#4840](https://github.com/sofa-framework/sofa/pull/4840) +- [All] Add way to disable windeppack [#4842](https://github.com/sofa-framework/sofa/pull/4842) +- [FEM.Elastic] Some FEM inherits from BaseLinearElasticityFEMForceField [#4852](https://github.com/sofa-framework/sofa/pull/4852) +- [Collision.Detection.Intersection] Delete compat layer for intersection [#4916](https://github.com/sofa-framework/sofa/pull/4916) +- [FEM] Components override the template API instead of the generic one [#4982](https://github.com/sofa-framework/sofa/pull/4982) +- [Mapping.Linear] Use links instead of raw pointers [#4996](https://github.com/sofa-framework/sofa/pull/4996) +- [Mapping.NonLinear] A base class for (almost) all non linear mappings [#5006](https://github.com/sofa-framework/sofa/pull/5006) +- [Core] Constexprification of VecId [#5082](https://github.com/sofa-framework/sofa/pull/5082) +- [Helper] Add Accessors for Array types [#5114](https://github.com/sofa-framework/sofa/pull/5114) + + +### Improvements + +- [Core] Dump ObjectFactory in json [#4775](https://github.com/sofa-framework/sofa/pull/4775) +- [Core] Introduce category for LinearSystem [#4784](https://github.com/sofa-framework/sofa/pull/4784) +- [GUI.Component] ConstraintAttachBodyPerformer: Add RigidType support [#4801](https://github.com/sofa-framework/sofa/pull/4801) +- [Config] Add CMake option for memory sanitizer [#4847](https://github.com/sofa-framework/sofa/pull/4847) +- [AnimationLoop] Apply new factory registration mechanism [#4858](https://github.com/sofa-framework/sofa/pull/4858) +- [Plugin] Add Cosserat as a fetchable plugin [#4859](https://github.com/sofa-framework/sofa/pull/4859) +- [SofaCUDA] Add constructor based on initializer_list [#4868](https://github.com/sofa-framework/sofa/pull/4868) +- [Helper] Retrieve the current user local configuration directory [#4875](https://github.com/sofa-framework/sofa/pull/4875) +- [GitHub] Update sofa-dev action to check timezone [#4877](https://github.com/sofa-framework/sofa/pull/4877) +- [GUI] Improve Error Handling in createPerformer [#4880](https://github.com/sofa-framework/sofa/pull/4880) +- [Core] Add filtering for unloaded plugins in ObjectFactory::getAllEntries [#4885](https://github.com/sofa-framework/sofa/pull/4885) +- [examples] Change rendering option in the TetrahedronFEMForceField.scn [#4922](https://github.com/sofa-framework/sofa/pull/4922) +- [Visual] Apply new factory registration mechanism [#4930](https://github.com/sofa-framework/sofa/pull/4930) +- [Setting] Apply new factory registration mechanism [#4931](https://github.com/sofa-framework/sofa/pull/4931) +- [SceneUtility] Apply new factory registration mechanism [#4932](https://github.com/sofa-framework/sofa/pull/4932) +- [Playback] Apply new factory registration mechanism [#4933](https://github.com/sofa-framework/sofa/pull/4933) +- [Engine] Add draw method in NearestPointROI [#4944](https://github.com/sofa-framework/sofa/pull/4944) +- [FEM] Add method computeVonMisesStress in TetrahedralCorotationalForceField and option to draw them [#4945](https://github.com/sofa-framework/sofa/pull/4945) +- [Engine.Select] Clean, extend and test MeshSubsetEngine [#4958](https://github.com/sofa-framework/sofa/pull/4958) +- [ODESolver] Apply new factory registration mechanism [#4975](https://github.com/sofa-framework/sofa/pull/4975) +- [IO] Apply new factory registration mechanism [#4976](https://github.com/sofa-framework/sofa/pull/4976) +- [Controller, Haptics, Diffusion] Apply new factory registration mechanism [#4977](https://github.com/sofa-framework/sofa/pull/4977) +- [LinearSystem] Apply new factory registration mechanism [#4981](https://github.com/sofa-framework/sofa/pull/4981) +- [MechanicalLoad] Apply new factory registration mechanism [#4983](https://github.com/sofa-framework/sofa/pull/4983) +- [Engine] Apply new factory registration mechanism [#5010](https://github.com/sofa-framework/sofa/pull/5010) +- [LinearSolver] Apply new factory registration mechanism [#5011](https://github.com/sofa-framework/sofa/pull/5011) +- [Topology] Apply new factory registration mechanism [#5012](https://github.com/sofa-framework/sofa/pull/5012) +- [SolidMechanics] Apply new factory registration mechanism [#5027](https://github.com/sofa-framework/sofa/pull/5027) +- [Collision] Apply new factory registration mechanism [#5033](https://github.com/sofa-framework/sofa/pull/5033) +- [examples] Update example scene of RungeKutta to make it stable [#5036](https://github.com/sofa-framework/sofa/pull/5036) +- [Constraint] Apply new factory registration mechanism [#5052](https://github.com/sofa-framework/sofa/pull/5052) +- [Mapping] Apply new factory registration mechanism [#5053](https://github.com/sofa-framework/sofa/pull/5053) +- [Mass] Apply new factory registration mechanism [#5055](https://github.com/sofa-framework/sofa/pull/5055) +- [all] Compatibility with C++20 [#5056](https://github.com/sofa-framework/sofa/pull/5056) +- [Helper] A static alternative to OptionsGroup: SelectableItem [#5062](https://github.com/sofa-framework/sofa/pull/5062) +- [Core] Support component included in multiple component change maps [#5074](https://github.com/sofa-framework/sofa/pull/5074) +- [runSofa] App name instead of empty string [#5076](https://github.com/sofa-framework/sofa/pull/5076) +- [GL, GUI] Apply new factory registration mechanism [#5097](https://github.com/sofa-framework/sofa/pull/5097) +- [Simulation.Core] Apply new factory registration mechanism [#5098](https://github.com/sofa-framework/sofa/pull/5098) +- [Core] Introduction of strong types [#5104](https://github.com/sofa-framework/sofa/pull/5104) +- [Type] Consistent string to color conversion [#5121](https://github.com/sofa-framework/sofa/pull/5121) +- [example] Update scene to display colors representing triangle areas [#5122](https://github.com/sofa-framework/sofa/pull/5122) + + +### Bug Fixes + +- [Core] Add topology subset indices test [#4738](https://github.com/sofa-framework/sofa/pull/4738) +- [MechanicalLoad] Update TrianglePressureForceField to remove plan selection and add callback on Data pressure and triangleList [#4743](https://github.com/sofa-framework/sofa/pull/4743) +- [FEM.Elastic] Fix small deformation in TriangleFEMForceField [#4780](https://github.com/sofa-framework/sofa/pull/4780) +- [Simulation.Core] Fix assert due to #4776 [#4792](https://github.com/sofa-framework/sofa/pull/4792) +- [GUI] initialize pointer to nullptr to avoid crash [#4793](https://github.com/sofa-framework/sofa/pull/4793) +- [SolidMechanics] Fix type declaration in deprecated data [#4807](https://github.com/sofa-framework/sofa/pull/4807) +- [Core] Add RenamedData component for data symbol renaming [#4814](https://github.com/sofa-framework/sofa/pull/4814) +- [Core] Explicit type instead of calling function with side effect [#4816](https://github.com/sofa-framework/sofa/pull/4816) +- [Collision] Secure pointers dereferences [#4819](https://github.com/sofa-framework/sofa/pull/4819) +- [FEM.Elastic] Fix dynamic symbols [#4831](https://github.com/sofa-framework/sofa/pull/4831) +- [CMake] Add QGLViewer2 name in FindQGLViewer.cmake [#4841](https://github.com/sofa-framework/sofa/pull/4841) +- [Topology.Dynamic] Fix wrong deprecation [#4843](https://github.com/sofa-framework/sofa/pull/4843) +- [CMake] Allow the out-of-tree for Sofa.GL Gui.Qt and runSofa [#4844](https://github.com/sofa-framework/sofa/pull/4844) +- [ODESOlver] Fix RHS computation of the backward Euler implicit solver [#4848](https://github.com/sofa-framework/sofa/pull/4848) +- [Core] Fix string comparison in factory [#4854](https://github.com/sofa-framework/sofa/pull/4854) +- [Helper] Fix deprecation warning for BackgroundSetting component [#4860](https://github.com/sofa-framework/sofa/pull/4860) +- [Constraint.Projective] Fix internal data allocation [#4865](https://github.com/sofa-framework/sofa/pull/4865) +- [SofaCUDA] Apply rename of some Data [#4866](https://github.com/sofa-framework/sofa/pull/4866) +- [all] Fix type of renamed Data [#4869](https://github.com/sofa-framework/sofa/pull/4869) +- [Qt] Register objects when loading from Qt [#4872](https://github.com/sofa-framework/sofa/pull/4872) +- [VolumetricRendering.CUDA] Fix compilation after SOFA changes [#4879](https://github.com/sofa-framework/sofa/pull/4879) +- [Mapping] Fix draw in DistanceMultiMapping [#4881](https://github.com/sofa-framework/sofa/pull/4881) +- [FEM.Elastic] remove static variable [#4883](https://github.com/sofa-framework/sofa/pull/4883) +- [Visual] BaseCamera: Fix return value when saving a view file [#4884](https://github.com/sofa-framework/sofa/pull/4884) +- [Topology.Dynamic] GeometryAlgoritims: disable lighting when drawing topologies [#4887](https://github.com/sofa-framework/sofa/pull/4887) +- [Visual] Camera: do not export/import lookat info [#4888](https://github.com/sofa-framework/sofa/pull/4888) +- [Core] Fix compilation warnings with addClambda [#4889](https://github.com/sofa-framework/sofa/pull/4889) +- [FEM] Remove duplicated Link to topology [#4890](https://github.com/sofa-framework/sofa/pull/4890) +- [Mapping.NonLinear] Fix rigid types in SquareDistanceMapping [#4891](https://github.com/sofa-framework/sofa/pull/4891) +- [VolumetricRendering] Fix target name in OglTetrahedralModel [#4893](https://github.com/sofa-framework/sofa/pull/4893) +- [Core] Secure json dump [#4894](https://github.com/sofa-framework/sofa/pull/4894) +- [SolidMechanics.FEM.Elastic] Fix compilation on clang{12, 13} [#4899](https://github.com/sofa-framework/sofa/pull/4899) +- [Core] Replace non-utf8 chars by special char with error message [#4900](https://github.com/sofa-framework/sofa/pull/4900) +- [image] convert unsigned char to int when streaming [#4901](https://github.com/sofa-framework/sofa/pull/4901) +- [Core] Revert thread local changes on exec params [#4902](https://github.com/sofa-framework/sofa/pull/4902) +- [Type] Fix wrong use of std::empty [#4903](https://github.com/sofa-framework/sofa/pull/4903) +- [Core] pointer checking [#4904](https://github.com/sofa-framework/sofa/pull/4904) +- [Core] Fix check and use of componentState in SingleStateAccessor [#4917](https://github.com/sofa-framework/sofa/pull/4917) +- [Playback] Fix WriteStateCreator to pass period only if it has a value. Because WriteState use isSet value... [#4919](https://github.com/sofa-framework/sofa/pull/4919) +- [Spring] Enable spring by default if Data enabled is not set [#4946](https://github.com/sofa-framework/sofa/pull/4946) +- [GUI.Common] ArgumentParser: catch exceptions when same options are added [#4947](https://github.com/sofa-framework/sofa/pull/4947) +- [Config] Use cmake-generator-expression to set cxx and c flags [#4990](https://github.com/sofa-framework/sofa/pull/4990) +- [LinearSolver.Direct] Fix packaging [#4999](https://github.com/sofa-framework/sofa/pull/4999) +- [FrameSpringForceField] Fix invalid data field's name [#5002](https://github.com/sofa-framework/sofa/pull/5002) +- [DefaultType] Fix RigidDeriv name [#5015](https://github.com/sofa-framework/sofa/pull/5015) +- [Constraint.Projective] Make LinearVelocityProjectiveConstraint work with FreeMotionAL [#5025](https://github.com/sofa-framework/sofa/pull/5025) +- [LinearAlgebra] Add CompressedRowSparseMatrixConstraint tests [#5037](https://github.com/sofa-framework/sofa/pull/5037) +- [tools] Deactivate all plugin containing CUDA in its name [#5044](https://github.com/sofa-framework/sofa/pull/5044) +- [Engine.Select] Fix MeshSubsetEngine compilation [#5046](https://github.com/sofa-framework/sofa/pull/5046) +- [Core.Collision] NarrowPhaseDetection: disable lighting when displaying detection outputs [#5048](https://github.com/sofa-framework/sofa/pull/5048) +- [Core] ForceField: print only once about missing kfactor usage [#5050](https://github.com/sofa-framework/sofa/pull/5050) +- [GitHub] Fix python dependencies in Actions [#5061](https://github.com/sofa-framework/sofa/pull/5061) +- [GitHub] Use python venv in Actions [#5066](https://github.com/sofa-framework/sofa/pull/5066) +- [Core] Test for nullptr in force field creation [#5075](https://github.com/sofa-framework/sofa/pull/5075) +- [Core] Fix isSet flag when setting a link to a not-yet created data [#5081](https://github.com/sofa-framework/sofa/pull/5081) +- [LinearAlgebra] CompressedRowSparseMatrixConstraint: make consistent the serialization/deserialization process [#5087](https://github.com/sofa-framework/sofa/pull/5087) +- [Gl.Component] Swap data description in OglColorMap [#5118](https://github.com/sofa-framework/sofa/pull/5118) +- [GL.Component] Fix min max computation in DataDisplay [#5120](https://github.com/sofa-framework/sofa/pull/5120) +- [Mapping] Fix debug compilation [#5134](https://github.com/sofa-framework/sofa/pull/5134) +- [Helper] Fix warning unexpected tokens following preprocessor directive [#5137](https://github.com/sofa-framework/sofa/pull/5137) +- [Backward] Fix typo [#5146](https://github.com/sofa-framework/sofa/pull/5146) +- [CollisionOBBCapsule] Fix Capsule destructor [#5147](https://github.com/sofa-framework/sofa/pull/5147) +- [All] Fix visualisation [#5152](https://github.com/sofa-framework/sofa/pull/5152) + + +### Cleaning + +- [Mass] Replace doUpdateInternal by callback: UniformMass [#3927](https://github.com/sofa-framework/sofa/pull/3927) +- [Core,Helper] Prevent to create objects from unloaded plugins [#4722](https://github.com/sofa-framework/sofa/pull/4722) +- [Topology.Container] Various clean in TriangleSetGeometryAlgorithms [#4746](https://github.com/sofa-framework/sofa/pull/4746) +- [all] Update data comments [#4751](https://github.com/sofa-framework/sofa/pull/4751) +- [Lagrangian.Model] Use base class Data instead of protected class member for constraint id [#4763](https://github.com/sofa-framework/sofa/pull/4763) +- [Mapping.NonLinear] Cleaning of DistanceMapping [#4777](https://github.com/sofa-framework/sofa/pull/4777) +- [FEM.Elastic] Remove addKToMatrix override as it is duplicated from base class [#4779](https://github.com/sofa-framework/sofa/pull/4779) +- [SofaAssump] Fix shadow variable in SceneColladaLoader [#4785](https://github.com/sofa-framework/sofa/pull/4785) +- [Project] Start dev phase v24.12 [#4787](https://github.com/sofa-framework/sofa/pull/4787) +- [All] Plugins: Deprecate entrypoint getModuleComponentList() [#4795](https://github.com/sofa-framework/sofa/pull/4795) +- [GUI] Fix typo in comments [#4797](https://github.com/sofa-framework/sofa/pull/4797) +- [All] Remove compat layer for Intersection methods [#4802](https://github.com/sofa-framework/sofa/pull/4802) +- [all] Clean some warnings [#4805](https://github.com/sofa-framework/sofa/pull/4805) +- [GUI] Clean warning from GUI at start [#4811](https://github.com/sofa-framework/sofa/pull/4811) +- [All] CMake: Remove deprecated settings [#4812](https://github.com/sofa-framework/sofa/pull/4812) +- [All] Remove SOFA_ENABLE_LEGACY_HEADERS usage [#4813](https://github.com/sofa-framework/sofa/pull/4813) +- [Core] Deprecate typeName with parameter [#4817](https://github.com/sofa-framework/sofa/pull/4817) +- [All] Reduce includes to helper/set.h [#4820](https://github.com/sofa-framework/sofa/pull/4820) +- [Projective] FixedProjectiveConstraint: Remove draw specializations and compute bbox [#4823](https://github.com/sofa-framework/sofa/pull/4823) +- [FEM.Elastic] Remove unused methods [#4824](https://github.com/sofa-framework/sofa/pull/4824) +- [Helper] Added cleanup callback [#4828](https://github.com/sofa-framework/sofa/pull/4828) +- [FEM.Elastic] Example of using structured binding [#4835](https://github.com/sofa-framework/sofa/pull/4835) +- [Helper] Move string utils from Utils to StringUtils [#4837](https://github.com/sofa-framework/sofa/pull/4837) +- [Core] Remove m_cId deprecation warning spam [#4846](https://github.com/sofa-framework/sofa/pull/4846) +- [CMake] Change CMake version in preset [#4849](https://github.com/sofa-framework/sofa/pull/4849) +- [Helper, AnimationLoop] ComponentChange: add Dealiased state [#4863](https://github.com/sofa-framework/sofa/pull/4863) +- [all] Rename lifecycle names for HEADER [#4882](https://github.com/sofa-framework/sofa/pull/4882) +- [CMake] Update all cmake_minimum_required in plugins [#4886](https://github.com/sofa-framework/sofa/pull/4886) +- [Core] ObjectFactory: fix typo when an object is not found [#4908](https://github.com/sofa-framework/sofa/pull/4908) +- [all] Fix various summer warnings [#4909](https://github.com/sofa-framework/sofa/pull/4909) +- [runSofa] Removed obsolete options [#4925](https://github.com/sofa-framework/sofa/pull/4925) +- [Sofa.GUI, Plugins] Pluginize HeadlessRecorder [#4928](https://github.com/sofa-framework/sofa/pull/4928) +- [All] Add scoped timers for tracy profiler [#4957](https://github.com/sofa-framework/sofa/pull/4957) +- [GUI] Minor cleaning in GUIManager [#4967](https://github.com/sofa-framework/sofa/pull/4967) +- [all] Cleanings on debug symbols [#4971](https://github.com/sofa-framework/sofa/pull/4971) +- [OpenCL] Update OpenCLProgram.cpp remove unused variable [#4973](https://github.com/sofa-framework/sofa/pull/4973) +- [FEM.Elastic] missing override keyword [#4980](https://github.com/sofa-framework/sofa/pull/4980) +- [Core] Move DevBaseMonitor in SofaValidation [#4985](https://github.com/sofa-framework/sofa/pull/4985) +- [all] Use isComponentStateValid [#4995](https://github.com/sofa-framework/sofa/pull/4995) +- [LinearAlgebra] Rename class MatrixSubstraction to MatrixSubtraction [#5016](https://github.com/sofa-framework/sofa/pull/5016) +- [ODESolver] Rename files to match class name [#5034](https://github.com/sofa-framework/sofa/pull/5034) +- [examples] Remove old tutorials [#5035](https://github.com/sofa-framework/sofa/pull/5035) +- [VolumetricRendering] Initialize SOFACuda [#5039](https://github.com/sofa-framework/sofa/pull/5039) +- [All] Clean collision detection in FreeMotionAnimationLoop [#5042](https://github.com/sofa-framework/sofa/pull/5042) +- [DefaultAnimationLoop] Add timer for collision begin and collision end [#5043](https://github.com/sofa-framework/sofa/pull/5043) +- [GenericConstraintSolver] FIX Generic constraint solver timer [#5045](https://github.com/sofa-framework/sofa/pull/5045) +- [all] Fix warnings [#5054](https://github.com/sofa-framework/sofa/pull/5054) +- [all] Run codespell on the code base + config file [#5064](https://github.com/sofa-framework/sofa/pull/5064) +- [Mapping] Deprecate module Sofa.Component.Mapping.MappedMatrix [#5070](https://github.com/sofa-framework/sofa/pull/5070) +- [examples] Run PluginFinder [#5072](https://github.com/sofa-framework/sofa/pull/5072) +- [Helper] Ensure exactly one directory separator [#5073](https://github.com/sofa-framework/sofa/pull/5073) +- [CUDA] Update CudaHexahedronTLEDForceField.cpp [#5085](https://github.com/sofa-framework/sofa/pull/5085) +- [Config] Minor cleaning of config.h [#5103](https://github.com/sofa-framework/sofa/pull/5103) +- [Constraint] Clean BilateralLagrangianConstraint [#5109](https://github.com/sofa-framework/sofa/pull/5109) +- [Mapping.Linear] Cleaning of SubsetMultiMapping [#5115](https://github.com/sofa-framework/sofa/pull/5115) +- [Visual] Move, rename and clean OglCylinderModel [#5124](https://github.com/sofa-framework/sofa/pull/5124) +- [all] Minor esthetic changes [#5129](https://github.com/sofa-framework/sofa/pull/5129) +- [Spring] Add warning when user tries to override MeshSpringForcefield indices [#5136](https://github.com/sofa-framework/sofa/pull/5136) +- [LinearSolver] Renamed ShewchuckPCGLinearSolver by removing the Shewchuck [#5139](https://github.com/sofa-framework/sofa/pull/5139) +- [Core, Simulation.Core] Registration: (re)enable deprecation warnings [#5155](https://github.com/sofa-framework/sofa/pull/5155) +- [All] Remove spam warnings [#5156](https://github.com/sofa-framework/sofa/pull/5156) + + +### Refactoring + +- [Component] Rename Data [#4771](https://github.com/sofa-framework/sofa/pull/4771) +- [SofaTest] Rename deprecated data [#4804](https://github.com/sofa-framework/sofa/pull/4804) +- [SofaCUDA] Simplify definition of CudaVector type [#4864](https://github.com/sofa-framework/sofa/pull/4864) +- [SofaCUDA,SofaDistanceGrid] Move DistanceGrid CUDA files in a SofaDistanceGrid extension [#4878](https://github.com/sofa-framework/sofa/pull/4878) +- [All] Apply renamed data on codebase [#4927](https://github.com/sofa-framework/sofa/pull/4927) +- [Test] Refactor Mapping_test [#5079](https://github.com/sofa-framework/sofa/pull/5079) +- [GitHub] Remove dev meeting action [#5107](https://github.com/sofa-framework/sofa/pull/5107) + + + + ## [v24.06.00]( https://github.com/sofa-framework/sofa/tree/v24.06.00 ) [Full log]( https://github.com/sofa-framework/sofa/compare/v23.12..v24.06 ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85160f7960f..3cf20738699 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ project(Sofa include(CMakeDependentOption) # Manually define VERSION -set(Sofa_VERSION_MAJOR 24) -set(Sofa_VERSION_MINOR 12) +set(Sofa_VERSION_MAJOR 25) +set(Sofa_VERSION_MINOR 06) set(Sofa_VERSION_PATCH 99) set(Sofa_VERSION ${Sofa_VERSION_MAJOR}.${Sofa_VERSION_MINOR}.${Sofa_VERSION_PATCH}) diff --git a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.h b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.h index c377ece2a55..10347815e02 100644 --- a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.h +++ b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace sofa::core::behavior { @@ -45,7 +45,7 @@ class SOFA_COMPONENT_ANIMATIONLOOP_API FreeMotionAnimationLoop : public sofa::si SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ANIMATIONLOOP() - sofa::core::objectmodel::RenamedData m_solveVelocityConstraintFirst; + sofa::core::objectmodel::lifecycle::RenamedData m_solveVelocityConstraintFirst; Data d_solveVelocityConstraintFirst; ///< solve separately velocity constraint violations before position constraint violations Data d_threadSafeVisitor; ///< If true, do not use realloc and free visitors in fwdInteractionForceField. diff --git a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/MultiStepAnimationLoop.h b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/MultiStepAnimationLoop.h index 84545c3eeb1..62c2a5e6ad8 100644 --- a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/MultiStepAnimationLoop.h +++ b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/MultiStepAnimationLoop.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::animationloop { @@ -43,10 +43,10 @@ class SOFA_COMPONENT_ANIMATIONLOOP_API MultiStepAnimationLoop : public sofa::sim void step (const sofa::core::ExecParams* params, SReal dt) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ANIMATIONLOOP() - sofa::core::objectmodel::RenamedData collisionSteps; + sofa::core::objectmodel::lifecycle::RenamedData collisionSteps; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ANIMATIONLOOP() - sofa::core::objectmodel::RenamedData integrationSteps; + sofa::core::objectmodel::lifecycle::RenamedData integrationSteps; Data d_collisionSteps; ///< number of collision steps between each frame rendering Data d_integrationSteps; ///< number of integration steps between each collision detection diff --git a/Sofa/Component/CMakeLists.txt b/Sofa/Component/CMakeLists.txt index 264fbcc8e2d..dbd5d4a4fb3 100644 --- a/Sofa/Component/CMakeLists.txt +++ b/Sofa/Component/CMakeLists.txt @@ -49,3 +49,10 @@ sofa_create_package_with_targets( INCLUDE_SOURCE_DIR "src" INCLUDE_INSTALL_DIR "${PROJECT_NAME}" ) + +# Tests +# If SOFA_BUILD_TESTS exists and is OFF, then these tests will be auto-disabled +cmake_dependent_option(SOFA_COMPONENT_BUILD_TESTS "Compile the automatic tests" ON "SOFA_BUILD_TESTS OR NOT DEFINED SOFA_BUILD_TESTS" OFF) +if(SOFA_COMPONENT_BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BruteForceBroadPhase.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BruteForceBroadPhase.h index 9c1460d219f..ba8fe667fed 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BruteForceBroadPhase.h +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BruteForceBroadPhase.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace sofa::component::collision::detection::algorithm { @@ -51,7 +51,7 @@ class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API BruteForceBroadPhase : pu private: ///< if not empty, objects that do not intersect this bounding-box will be ignored SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_ALGORITHM() - sofa::core::objectmodel::RenamedData > box; + sofa::core::objectmodel::lifecycle::RenamedData > box; Data > d_box; ///< if not empty, objects that do not intersect this bounding-box will be ignored diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/IncrSAP.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/IncrSAP.h index 3a787ff9059..aff6b8b8b6d 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/IncrSAP.h +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/IncrSAP.h @@ -42,7 +42,7 @@ #include #include -#include +#include namespace sofa::component::collision::detection::algorithm @@ -215,7 +215,7 @@ class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API IncrSAP : core::objectmodel::lifecycle::DeprecatedData bDraw {this, "v24.06", "v24.12", "draw", "This Data was not used"}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_ALGORITHM() - sofa::core::objectmodel::RenamedData< type::fixed_array > box; ///< if not empty, objects that do not intersect this bounding-box will be ignored + sofa::core::objectmodel::lifecycle::RenamedData< type::fixed_array > box; ///< if not empty, objects that do not intersect this bounding-box will be ignored Data< type::fixed_array > d_box; ///< if not empty, objects that do not intersect this bounding-box will be ignored diff --git a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp index 0adc21e696f..e4f11276c8d 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp +++ b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp @@ -74,13 +74,13 @@ class TestCollisionPipeline : public BaseSimulationTest { void checkCollisionPipelineWithMissingContactManager(); int checkCollisionPipelineWithMonkeyValueForDepth(int value); - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Collision"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Collision); } - void TearDown() override + void doTearDown() override { if (root) sofa::simulation::node::unload(root); diff --git a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/BaseProximityIntersection.h b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/BaseProximityIntersection.h index 8dbe24ea612..c7a336c1499 100644 --- a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/BaseProximityIntersection.h +++ b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/BaseProximityIntersection.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::collision::detection::intersection @@ -41,10 +41,10 @@ class SOFA_COMPONENT_COLLISION_DETECTION_INTERSECTION_API BaseProximityIntersect public: SOFA_ABSTRACT_CLASS(BaseProximityIntersection,DiscreteIntersection); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData alarmDistance; + sofa::core::objectmodel::lifecycle::RenamedData alarmDistance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData contactDistance; + sofa::core::objectmodel::lifecycle::RenamedData contactDistance; Data d_alarmDistance; ///< Distance above which the intersection computations ignores the proximity pair. This distance can also be used in some broad phase algorithms to reduce the search area diff --git a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/LocalMinDistance.h b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/LocalMinDistance.h index eb3bc43afac..38f5709cbac 100644 --- a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/LocalMinDistance.h +++ b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/LocalMinDistance.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace sofa::component::collision::detection::intersection { @@ -64,16 +64,16 @@ class SOFA_COMPONENT_COLLISION_DETECTION_INTERSECTION_API LocalMinDistance : pub typedef core::collision::IntersectorFactory IntersectorFactory; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData filterIntersection; + sofa::core::objectmodel::lifecycle::RenamedData filterIntersection; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData angleCone; + sofa::core::objectmodel::lifecycle::RenamedData angleCone; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData coneFactor; + sofa::core::objectmodel::lifecycle::RenamedData coneFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useLMDFilters; + sofa::core::objectmodel::lifecycle::RenamedData useLMDFilters; Data d_filterIntersection; ///< Activate LMD filter diff --git a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/MinProximityIntersection.h b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/MinProximityIntersection.h index 2aa9bfc3295..144587cde24 100644 --- a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/MinProximityIntersection.h +++ b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/MinProximityIntersection.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::collision::detection::intersection { @@ -57,19 +57,19 @@ class SOFA_COMPONENT_COLLISION_DETECTION_INTERSECTION_API MinProximityIntersecti public: SOFA_CLASS(MinProximityIntersection,BaseProximityIntersection); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useSphereTriangle; + sofa::core::objectmodel::lifecycle::RenamedData useSphereTriangle; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData usePointPoint; + sofa::core::objectmodel::lifecycle::RenamedData usePointPoint; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useSurfaceNormals; + sofa::core::objectmodel::lifecycle::RenamedData useSurfaceNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useLinePoint; + sofa::core::objectmodel::lifecycle::RenamedData useLinePoint; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useLineLine; + sofa::core::objectmodel::lifecycle::RenamedData useLineLine; diff --git a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/NewProximityIntersection.h b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/NewProximityIntersection.h index 84e1f701fbe..3464e87c33b 100644 --- a/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/NewProximityIntersection.h +++ b/Sofa/Component/Collision/Detection/Intersection/src/sofa/component/collision/detection/intersection/NewProximityIntersection.h @@ -26,7 +26,7 @@ #include -#include +#include namespace sofa::component::collision::detection::intersection { @@ -58,7 +58,7 @@ class SOFA_COMPONENT_COLLISION_DETECTION_INTERSECTION_API NewProximityIntersecti public: SOFA_CLASS(NewProximityIntersection,BaseProximityIntersection); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_DETECTION_INTERSECTION() - sofa::core::objectmodel::RenamedData useLineLine; + sofa::core::objectmodel::lifecycle::RenamedData useLineLine; Data d_useLineLine; ///< Line-line collision detection enabled diff --git a/Sofa/Component/Collision/Detection/Intersection/tests/LocalMinDistance_test.cpp b/Sofa/Component/Collision/Detection/Intersection/tests/LocalMinDistance_test.cpp index c432f420552..80fd33fa464 100644 --- a/Sofa/Component/Collision/Detection/Intersection/tests/LocalMinDistance_test.cpp +++ b/Sofa/Component/Collision/Detection/Intersection/tests/LocalMinDistance_test.cpp @@ -54,12 +54,12 @@ namespace { struct TestLocalMinDistance : public BaseSimulationTest { - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Collision.Detection.Intersection"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Detection.Intersection); } - void TearDown() override + void doTearDown() override { } diff --git a/Sofa/Component/Collision/Detection/src/sofa/component/collision/detection/init.cpp b/Sofa/Component/Collision/Detection/src/sofa/component/collision/detection/init.cpp index 387d165aa7f..e7e10ae60ce 100644 --- a/Sofa/Component/Collision/Detection/src/sofa/component/collision/detection/init.cpp +++ b/Sofa/Component/Collision/Detection/src/sofa/component/collision/detection/init.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace sofa::component::collision::detection { @@ -54,8 +55,8 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Detection.Algorithm"); - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Detection.Intersection"); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Detection.Algorithm); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Detection.Intersection); } void init() diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineModel.h index 8b72e6d71ce..8b40670354a 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineModel.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::collision::geometry @@ -145,7 +145,7 @@ public : int getLineFlags(sofa::Index i); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData bothSide; + sofa::core::objectmodel::lifecycle::RenamedData bothSide; Data d_bothSide; ///< activate collision on both side of the line model (when surface normals are defined on these lines) @@ -172,7 +172,7 @@ public : void computeBBox(const core::ExecParams* params, bool onlyVisible) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData m_displayFreePosition; + sofa::core::objectmodel::lifecycle::RenamedData m_displayFreePosition; Data d_displayFreePosition; ///< Display Collision Model Points free position(in green) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointModel.h index 84cbf118004..bd22bf85fb4 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointModel.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::collision::geometry { @@ -104,7 +104,7 @@ class PointCollisionModel : public core::CollisionModel const Deriv& velocity(sofa::Index index) const; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData bothSide; + sofa::core::objectmodel::lifecycle::RenamedData bothSide; Data d_bothSide; ///< activate collision on both side of the point model (when surface normals are defined on these points) @@ -136,10 +136,10 @@ class PointCollisionModel : public core::CollisionModel core::behavior::MechanicalState* mstate; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData computeNormals; + sofa::core::objectmodel::lifecycle::RenamedData computeNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData m_displayFreePosition; + sofa::core::objectmodel::lifecycle::RenamedData m_displayFreePosition; Data d_computeNormals; ///< activate computation of normal vectors (required for some collision detection algorithms) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayModel.h index a6a42b69339..75387b7df3c 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayModel.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::collision::response::contact { @@ -96,7 +96,7 @@ class SOFA_COMPONENT_COLLISION_GEOMETRY_API RayCollisionModel : public core::Col sofa::type::vector direction; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData defaultLength; + sofa::core::objectmodel::lifecycle::RenamedData defaultLength; diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereModel.h index ef5b8031204..a5f54206f4b 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereModel.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::collision::geometry { @@ -165,10 +165,10 @@ class SphereCollisionModel : public core::CollisionModel } SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData< VecReal > radius; + sofa::core::objectmodel::lifecycle::RenamedData< VecReal > radius; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_GEOMETRY() - sofa::core::objectmodel::RenamedData defaultRadius; + sofa::core::objectmodel::lifecycle::RenamedData defaultRadius; Data< VecReal > d_radius; ///< Radius of each sphere Data< SReal > d_defaultRadius; ///< Default radius diff --git a/Sofa/Component/Collision/Geometry/tests/Sphere_test.cpp b/Sofa/Component/Collision/Geometry/tests/Sphere_test.cpp index 35f2199ebe8..03caeae5d99 100644 --- a/Sofa/Component/Collision/Geometry/tests/Sphere_test.cpp +++ b/Sofa/Component/Collision/Geometry/tests/Sphere_test.cpp @@ -70,16 +70,16 @@ namespace sofa { struct TestSphere : public BaseSimulationTest { - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Collision.Geometry"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Geometry); m_proxIntersection = sofa::core::objectmodel::New(); m_proxIntersection->setAlarmDistance(1.0); m_proxIntersection->setContactDistance(1.0); } - void TearDown() override + void doTearDown() override { } diff --git a/Sofa/Component/Collision/Geometry/tests/Triangle_test.cpp b/Sofa/Component/Collision/Geometry/tests/Triangle_test.cpp index 7355c123372..e6f8567a262 100644 --- a/Sofa/Component/Collision/Geometry/tests/Triangle_test.cpp +++ b/Sofa/Component/Collision/Geometry/tests/Triangle_test.cpp @@ -56,10 +56,10 @@ namespace sofa { struct TestTriangle : public BaseTest { - void SetUp() override + void doSetUp() override { } - void TearDown() override + void doTearDown() override { } diff --git a/Sofa/Component/Collision/Response/Contact/CMakeLists.txt b/Sofa/Component/Collision/Response/Contact/CMakeLists.txt index 3b6e2a38162..9ea5c096b4d 100644 --- a/Sofa/Component/Collision/Response/Contact/CMakeLists.txt +++ b/Sofa/Component/Collision/Response/Contact/CMakeLists.txt @@ -6,6 +6,10 @@ set(SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR "src/sofa/component/collisi set(HEADER_FILES ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/config.h.in ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/init.h + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/AugmentedLagrangianResponse.h + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/AugmentedLagrangianResponse.inl + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BaseUnilateralContactResponse.h + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BaseUnilateralContactResponse.inl ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BarycentricPenalityContact.h ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BarycentricPenalityContact.inl ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BarycentricStickContact.h @@ -26,6 +30,7 @@ set(HEADER_FILES set(SOURCE_FILES ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/init.cpp + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/AugmentedLagrangianResponse.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BarycentricPenalityContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/BarycentricStickContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/CollisionResponse.cpp @@ -36,6 +41,7 @@ set(SOURCE_FILES ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/RayContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/RuleBasedContactManager.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/StickContactConstraint.cpp + ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/TetrahedronAugmentedLagrangianContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/TetrahedronBarycentricPenalityContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/TetrahedronFrictionContact.cpp ${SOFACOMPONENTCOLLISIONRESPONSECONTACT_SOURCE_DIR}/TetrahedronRayContact.cpp diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.cpp b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.cpp new file mode 100644 index 00000000000..18a25ba3871 --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.cpp @@ -0,0 +1,85 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include + +#include +#include + +namespace sofa::component::collision::response::contact +{ + +using namespace defaulttype; +using namespace sofa::helper; +using namespace sofa::component::collision::geometry; +using simulation::Node; + +Creator, PointCollisionModel> > PointPointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, SphereCollisionModel> > LineSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, PointCollisionModel> > LinePointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, LineCollisionModel> > LineLineAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, SphereCollisionModel> > TriangleSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, PointCollisionModel> > TrianglePointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, LineCollisionModel> > TriangleLineAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, TriangleCollisionModel> > TriangleTriangleAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, SphereCollisionModel> > SphereSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, PointCollisionModel> > SpherePointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator > RigidSphereRigidSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, RigidSphereModel> > SphereRigidSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, RigidSphereModel> > LineRigidSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator, RigidSphereModel> > TriangleRigidSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > RigidSpherePointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); + +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, LineCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, LineCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, TriangleCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; + +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, PointCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, SphereCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, PointCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, LineCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, SphereCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, PointCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, LineCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, TriangleCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, SphereCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, PointCollisionModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, RigidSphereModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, RigidSphereModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse, RigidSphereModel>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API AugmentedLagrangianResponse>; + +} //namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.h new file mode 100644 index 00000000000..0d5d96101d9 --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.h @@ -0,0 +1,67 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace sofa::component::collision::response::contact +{ +//Work inspired by: Zimmerman BK, Ateshian GA. "A Surface-to-Surface Finite Element Algorithm for Large Deformation Frictional Contact in febio." +// J Biomech Eng. 2018 Aug 1;140(8):0810131–08101315. doi: 10.1115/1.4040497. PMID: 30003262; PMCID: PMC6056201. +template +class AugmentedLagrangianResponse : public BaseUnilateralContactResponse +{ +public: + SOFA_CLASS(SOFA_TEMPLATE3(AugmentedLagrangianResponse, TCollisionModel1, TCollisionModel2, ResponseDataTypes), SOFA_TEMPLATE4(BaseUnilateralContactResponse, TCollisionModel1, TCollisionModel2,constraint::lagrangian::model::AugmentedLagrangianContactParameters, ResponseDataTypes)); + + typedef typename Inherit1::DataTypes1 DataTypes1; + typedef typename Inherit1::DataTypes2 DataTypes2; + typedef typename Inherit1::CollisionModel1 CollisionModel1; + typedef typename Inherit1::CollisionModel2 CollisionModel2; + typedef typename Inherit1::Intersection Intersection; + + typedef core::behavior::MechanicalState MechanicalState1; + typedef core::behavior::MechanicalState MechanicalState2; + + Data d_mu; ///< friction parameter + Data d_epsilon; ///< Penalty parameter + + AugmentedLagrangianResponse(); + AugmentedLagrangianResponse(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod); + + virtual ~AugmentedLagrangianResponse() = default; + + virtual constraint::lagrangian::model::AugmentedLagrangianContactParameters getParameterFromDatas() const override; + virtual void setupConstraint(MechanicalState1 *,MechanicalState2 *) override; + +}; + +} // namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl new file mode 100644 index 00000000000..f49fedf5602 --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl @@ -0,0 +1,65 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sofa::component::collision::response::contact +{ + +template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > +AugmentedLagrangianResponse::AugmentedLagrangianResponse() + : AugmentedLagrangianResponse(nullptr, nullptr, nullptr) +{ +} + + +template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > +AugmentedLagrangianResponse::AugmentedLagrangianResponse(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod) + : BaseUnilateralContactResponse(model1,model2,intersectionMethod) + , d_mu (initData(&d_mu, 0.0, "mu", "Friction coefficient (0 for frictionless contacts)")) + , d_epsilon (initData(&d_epsilon, 0.0, "epsilon", "Penalty parameter. It can be think of as a proportional controller, the Lagrange multiplier is augmented by the violation multiplied by this factor at each solving iteration.")) +{ + +} + +template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > +constraint::lagrangian::model::AugmentedLagrangianContactParameters AugmentedLagrangianResponse::getParameterFromDatas() const +{ + return {d_mu.getValue(),d_epsilon.getValue()}; +} + + +template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > +void AugmentedLagrangianResponse::setupConstraint(MechanicalState1 * mmodel1,MechanicalState2 * mmodel2) +{ + this->m_constraint = sofa::core::objectmodel::New >(mmodel1, mmodel2); +} + + +} //namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BarycentricStickContact.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BarycentricStickContact.h index 3b101a9c160..cb1347fc327 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BarycentricStickContact.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BarycentricStickContact.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::collision::response::contact { @@ -74,7 +74,7 @@ class BarycentricStickContact : public core::collision::Contact public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData f_keepAlive; + sofa::core::objectmodel::lifecycle::RenamedData f_keepAlive; Data d_keepAlive; ///< set to true to keep this contact alive even after collisions are no longer detected diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.h new file mode 100644 index 00000000000..cc1fcefa01f --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.h @@ -0,0 +1,101 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace sofa::component::collision::response::contact +{ +template +class BaseUnilateralContactResponse : public core::collision::Contact, public ContactIdentifier +{ +public: + SOFA_CLASS(SOFA_TEMPLATE4(BaseUnilateralContactResponse, TCollisionModel1, TCollisionModel2,ConstraintParameters, ResponseDataTypes), core::collision::Contact); + typedef TCollisionModel1 CollisionModel1; + typedef TCollisionModel2 CollisionModel2; + typedef core::collision::Intersection Intersection; + typedef typename TCollisionModel1::DataTypes::CPos TVec1; + typedef typename TCollisionModel1::DataTypes::CPos TVec2; + typedef sofa::defaulttype::StdVectorTypes DataTypes1; + typedef sofa::defaulttype::StdVectorTypes DataTypes2; + + typedef core::behavior::MechanicalState MechanicalState1; + typedef core::behavior::MechanicalState MechanicalState2; + typedef typename CollisionModel1::Element CollisionElement1; + typedef typename CollisionModel2::Element CollisionElement2; + typedef core::collision::DetectionOutputVector OutputVector; + typedef core::collision::TDetectionOutputVector TOutputVector; + +protected: + CollisionModel1* model1; + CollisionModel2* model2; + Intersection* intersectionMethod; + bool selfCollision; ///< true if model1==model2 (in this case, only mapper1 is used) + mapper::ContactMapper mapper1; + mapper::ContactMapper mapper2; + + typename constraint::lagrangian::model::BaseContactLagrangianConstraint::SPtr m_constraint; + core::objectmodel::BaseContext* parent; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() + sofa::core::objectmodel::lifecycle::RenamedData mu; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() + sofa::core::objectmodel::lifecycle::RenamedData tol; + + Data d_tol; ///< tolerance for the constraints resolution (0 for default tolerance) + std::vector< sofa::core::collision::DetectionOutput* > contacts; + std::vector< std::pair< std::pair, double > > mappedContacts; + + virtual void activateMappers(); + + void setInteractionTags(MechanicalState1* mstate1, MechanicalState2* mstate2); + + BaseUnilateralContactResponse(); + BaseUnilateralContactResponse(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod); + + ~BaseUnilateralContactResponse() override; +public: + void cleanup() override; + + std::pair getCollisionModels() override { return std::make_pair(model1,model2); } + + void setDetectionOutputs(OutputVector* outputs) override; + + void createResponse(core::objectmodel::BaseContext* group) override; + + void removeResponse() override; + + virtual ConstraintParameters getParameterFromDatas() const = 0; + virtual void setupConstraint(MechanicalState1 *,MechanicalState2 *) = 0; +}; + +} // namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.inl b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.inl new file mode 100644 index 00000000000..31b2199f8c0 --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/BaseUnilateralContactResponse.inl @@ -0,0 +1,271 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sofa::component::collision::response::contact +{ + +template +BaseUnilateralContactResponse::BaseUnilateralContactResponse() + : BaseUnilateralContactResponse(nullptr, nullptr, nullptr) +{ +} + + +template +BaseUnilateralContactResponse::BaseUnilateralContactResponse(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod) + : model1(model1) + , model2(model2) + , intersectionMethod(intersectionMethod) + , m_constraint(nullptr) + , parent(nullptr) + , d_tol (initData(&d_tol, 0.0, "tol", "tolerance for the constraints resolution (0 for default tolerance)")) +{ + selfCollision = ((core::CollisionModel*)model1 == (core::CollisionModel*)model2); + mapper1.setCollisionModel(model1); + if (!selfCollision) mapper2.setCollisionModel(model2); + contacts.clear(); + mappedContacts.clear(); + + tol.setOriginalData(&d_tol); + +} + +template +BaseUnilateralContactResponse::~BaseUnilateralContactResponse() +{ +} + +template +void BaseUnilateralContactResponse::cleanup() +{ + if (m_constraint) + { + m_constraint->cleanup(); + + if (parent != nullptr) + parent->removeObject(m_constraint); + + parent = nullptr; + m_constraint.reset(); + + mapper1.cleanup(); + + if (!selfCollision) + mapper2.cleanup(); + } + + contacts.clear(); + mappedContacts.clear(); +} + + +template +void BaseUnilateralContactResponse::setDetectionOutputs(OutputVector* o) +{ + TOutputVector& outputs = *static_cast(o); + // We need to remove duplicate contacts + constexpr double minDist2 = 0.00000001f; + + contacts.clear(); + + if (model1->getContactStiffness(0) == 0 || model2->getContactStiffness(0) == 0) + { + msg_error() << "Disabled BaseUnilateralContactResponse with " << (outputs.size()) << " collision points."; + return; + } + + contacts.reserve(outputs.size()); + + const int SIZE = outputs.size(); + + // the following procedure cancels the duplicated detection outputs + for (int cpt=0; cptpoint[0]-p->point[0]).norm2()+(detectionOutput->point[1]-p->point[1]).norm2() < minDist2) + found = true; + } + + if (!found) + contacts.push_back(detectionOutput); + } + + // DUPLICATED CONTACTS FOUND + msg_info_when(contacts.size() +void BaseUnilateralContactResponse::activateMappers() +{ + if (!m_constraint) + { + // Get the mechanical model from mapper1 to fill the constraint vector + MechanicalState1* mmodel1 = mapper1.createMapping(getName().c_str()); + // Get the mechanical model from mapper2 to fill the constraints vector + MechanicalState2* mmodel2; + if (selfCollision) + { + mmodel2 = mmodel1; + } + else + { + mmodel2 = mapper2.createMapping(getName().c_str()); + } + setupConstraint(mmodel1,mmodel2); + m_constraint->setName( getName() ); + setInteractionTags(mmodel1, mmodel2); + m_constraint->setCustomTolerance(d_tol.getValue() ); + } + + int size = contacts.size(); + m_constraint->clear(size); + if (selfCollision) + mapper1.resize(2*size); + else + { + mapper1.resize(size); + mapper2.resize(size); + } + int i = 0; + const double d0 = intersectionMethod->getContactDistance() + model1->getProximity() + model2->getProximity(); // - 0.001; + + mappedContacts.resize(contacts.size()); + for (std::vector::const_iterator it = contacts.begin(); it!=contacts.end(); it++, i++) + { + sofa::core::collision::DetectionOutput* o = *it; + CollisionElement1 elem1(o->elem.first); + CollisionElement2 elem2(o->elem.second); + int index1 = elem1.getIndex(); + int index2 = elem2.getIndex(); + + typename DataTypes1::Real r1 = 0.; + typename DataTypes2::Real r2 = 0.; + + // Create mapping for first point + index1 = mapper1.addPointB(o->point[0], index1, r1); + // Create mapping for second point + if (selfCollision) + { + index2 = mapper1.addPointB(o->point[1], index2, r2); + } + else + { + index2 = mapper2.addPointB(o->point[1], index2, r2); + } + const double distance = d0 + r1 + r2; + + mappedContacts[i].first.first = index1; + mappedContacts[i].first.second = index2; + mappedContacts[i].second = distance; + } + + // Update mappings + mapper1.update(); + mapper1.updateXfree(); + if (!selfCollision) mapper2.update(); + if (!selfCollision) mapper2.updateXfree(); +} + +template +void BaseUnilateralContactResponse::createResponse(core::objectmodel::BaseContext* group) +{ + + activateMappers(); + + if (m_constraint) + { + int i=0; + for (std::vector::const_iterator it = contacts.begin(); it!=contacts.end(); it++, i++) + { + const sofa::core::collision::DetectionOutput* o = *it; + const int index1 = mappedContacts[i].first.first; + const int index2 = mappedContacts[i].first.second; + const double distance = mappedContacts[i].second; + + // Polynome de Cantor de NxN sur N bijectif f(x,y)=((x+y)^2+3x+y)/2 + const long index = cantorPolynomia(o->id /*cantorPolynomia(index1, index2)*/,id); + + const ConstraintParameters params = getParameterFromDatas(); + + // Add contact in unilateral constraint + m_constraint->addContact(params, o->normal, distance, index1, index2, index, o->id); + } + + if (parent!=nullptr) + { + parent->removeObject(this); + parent->removeObject(m_constraint); + } + + parent = group; + if (parent!=nullptr) + { + parent->addObject(this); + parent->addObject(m_constraint); + } + } +} + +template +void BaseUnilateralContactResponse::removeResponse() +{ + if (m_constraint) + { + mapper1.resize(0); + mapper2.resize(0); + if (parent!=nullptr) + { + parent->removeObject(this); + parent->removeObject(m_constraint); + } + parent = nullptr; + } +} + +template +void BaseUnilateralContactResponse::setInteractionTags(MechanicalState1* mstate1, MechanicalState2* mstate2) +{ + sofa::core::objectmodel::TagSet tagsm1 = mstate1->getTags(); + sofa::core::objectmodel::TagSet tagsm2 = mstate2->getTags(); + sofa::core::objectmodel::TagSet::iterator it; + for(it=tagsm1.begin(); it != tagsm1.end(); it++) + m_constraint->addTag(*it); + for(it=tagsm2.begin(); it!=tagsm2.end(); it++) + m_constraint->addTag(*it); +} + +} //namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/CollisionResponse.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/CollisionResponse.h index 15780754ae8..3d86715d815 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/CollisionResponse.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/CollisionResponse.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::collision::response::contact { @@ -38,10 +38,10 @@ public : SOFA_CLASS(CollisionResponse,sofa::core::collision::ContactManager); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData response; + sofa::core::objectmodel::lifecycle::RenamedData response; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData responseParams; + sofa::core::objectmodel::lifecycle::RenamedData responseParams; Data d_response; ///< contact response class diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.cpp b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.cpp index e405e4ff362..a3734fd4d83 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.cpp +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.cpp @@ -19,8 +19,12 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ +#include +#include +#include #include + #include #include @@ -32,6 +36,7 @@ using namespace sofa::helper; using namespace sofa::component::collision::geometry; using simulation::Node; + Creator, PointCollisionModel> > PointPointFrictionContactClass("FrictionContactConstraint",true); Creator, SphereCollisionModel> > LineSphereFrictionContactClass("FrictionContactConstraint",true); Creator, PointCollisionModel> > LinePointFrictionContactClass("FrictionContactConstraint",true); @@ -48,6 +53,23 @@ Creator, RigidSphereModel> > TriangleRigidSphereFrictionContactClass("FrictionContactConstraint",true); Creator> > RigidSpherePointFrictionContactClass("FrictionContactConstraint",true); + +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, LineCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, LineCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, TriangleCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, SphereCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, PointCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse, RigidSphereModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; + template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API FrictionContact, PointCollisionModel>; template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API FrictionContact, SphereCollisionModel>; template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API FrictionContact, PointCollisionModel>; diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h index cebd6506a02..9c9869e53d5 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h @@ -27,73 +27,38 @@ #include #include #include -#include +#include #include -#include +#include namespace sofa::component::collision::response::contact { template -class FrictionContact : public core::collision::Contact, public ContactIdentifier +class FrictionContact : public BaseUnilateralContactResponse { -public: - SOFA_CLASS(SOFA_TEMPLATE3(FrictionContact, TCollisionModel1, TCollisionModel2, ResponseDataTypes), core::collision::Contact); - typedef TCollisionModel1 CollisionModel1; - typedef TCollisionModel2 CollisionModel2; - typedef core::collision::Intersection Intersection; - typedef typename TCollisionModel1::DataTypes::CPos TVec1; - typedef typename TCollisionModel1::DataTypes::CPos TVec2; - typedef sofa::defaulttype::StdVectorTypes DataTypes1; - typedef sofa::defaulttype::StdVectorTypes DataTypes2; + public: + SOFA_CLASS(SOFA_TEMPLATE3(FrictionContact, TCollisionModel1, TCollisionModel2, ResponseDataTypes), SOFA_TEMPLATE4(BaseUnilateralContactResponse, TCollisionModel1, TCollisionModel2,constraint::lagrangian::model::UnilateralLagrangianContactParameters, ResponseDataTypes)); + + typedef typename Inherit1::DataTypes1 DataTypes1; + typedef typename Inherit1::DataTypes2 DataTypes2; + typedef typename Inherit1::CollisionModel1 CollisionModel1; + typedef typename Inherit1::CollisionModel2 CollisionModel2; + typedef typename Inherit1::Intersection Intersection; typedef core::behavior::MechanicalState MechanicalState1; typedef core::behavior::MechanicalState MechanicalState2; - typedef typename CollisionModel1::Element CollisionElement1; - typedef typename CollisionModel2::Element CollisionElement2; - typedef core::collision::DetectionOutputVector OutputVector; - typedef core::collision::TDetectionOutputVector TOutputVector; - -protected: - CollisionModel1* model1; - CollisionModel2* model2; - Intersection* intersectionMethod; - bool selfCollision; ///< true if model1==model2 (in this case, only mapper1 is used) - mapper::ContactMapper mapper1; - mapper::ContactMapper mapper2; - - constraint::lagrangian::model::UnilateralLagrangianConstraint::SPtr m_constraint; - core::objectmodel::BaseContext* parent; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData mu; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData tol; - Data d_mu; ///< friction coefficient (0 for frictionless contacts) - Data d_tol; ///< tolerance for the constraints resolution (0 for default tolerance) - std::vector< sofa::core::collision::DetectionOutput* > contacts; - std::vector< std::pair< std::pair, double > > mappedContacts; - - virtual void activateMappers(); - - void setInteractionTags(MechanicalState1* mstate1, MechanicalState2* mstate2); + Data d_mu; ///< friction parameter FrictionContact(); FrictionContact(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod); - ~FrictionContact() override; -public: - void cleanup() override; - - std::pair getCollisionModels() override { return std::make_pair(model1,model2); } - - void setDetectionOutputs(OutputVector* outputs) override; + virtual ~FrictionContact() = default; - void createResponse(core::objectmodel::BaseContext* group) override; + virtual constraint::lagrangian::model::UnilateralLagrangianContactParameters getParameterFromDatas() const override; + virtual void setupConstraint(MechanicalState1 *,MechanicalState2 *) override; - void removeResponse() override; }; } // namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl index a7fdd1fcce1..0d2d1b43cb0 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl @@ -41,235 +41,24 @@ FrictionContact::FrictionCo template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > FrictionContact::FrictionContact(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod) - : model1(model1) - , model2(model2) - , intersectionMethod(intersectionMethod) - , m_constraint(nullptr) - , parent(nullptr) - , d_mu (initData(&d_mu, 0.8, "mu", "friction coefficient (0 for frictionless contacts)")) - , d_tol (initData(&d_tol, 0.0, "tol", "tolerance for the constraints resolution (0 for default tolerance)")) + : BaseUnilateralContactResponse(model1,model2,intersectionMethod) + , d_mu (initData(&d_mu, 0.8, "mu", "Friction coefficient (0 for frictionless contacts)")) { - selfCollision = ((core::CollisionModel*)model1 == (core::CollisionModel*)model2); - mapper1.setCollisionModel(model1); - if (!selfCollision) mapper2.setCollisionModel(model2); - contacts.clear(); - mappedContacts.clear(); - mu.setOriginalData(&d_mu); - tol.setOriginalData(&d_tol); - -} - -template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -FrictionContact::~FrictionContact() -{ -} - -template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -void FrictionContact::cleanup() -{ - if (m_constraint) - { - m_constraint->cleanup(); - - if (parent != nullptr) - parent->removeObject(m_constraint); - - parent = nullptr; - m_constraint.reset(); - - mapper1.cleanup(); - - if (!selfCollision) - mapper2.cleanup(); - } - - contacts.clear(); - mappedContacts.clear(); -} - - -template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -void FrictionContact::setDetectionOutputs(OutputVector* o) -{ - TOutputVector& outputs = *static_cast(o); - // We need to remove duplicate contacts - constexpr double minDist2 = 0.00000001f; - - contacts.clear(); - - if (model1->getContactStiffness(0) == 0 || model2->getContactStiffness(0) == 0) - { - msg_error() << "Disabled FrictionContact with " << (outputs.size()) << " collision points."; - return; - } - - contacts.reserve(outputs.size()); - - const int SIZE = outputs.size(); - - // the following procedure cancels the duplicated detection outputs - for (int cpt=0; cptpoint[0]-p->point[0]).norm2()+(detectionOutput->point[1]-p->point[1]).norm2() < minDist2) - found = true; - } - - if (!found) - contacts.push_back(detectionOutput); - } - - // DUPLICATED CONTACTS FOUND - msg_info_when(contacts.size() -void FrictionContact::activateMappers() +constraint::lagrangian::model::UnilateralLagrangianContactParameters FrictionContact::getParameterFromDatas() const { - if (!m_constraint) - { - // Get the mechanical model from mapper1 to fill the constraint vector - MechanicalState1* mmodel1 = mapper1.createMapping(getName().c_str()); - // Get the mechanical model from mapper2 to fill the constraints vector - MechanicalState2* mmodel2; - if (selfCollision) - { - mmodel2 = mmodel1; - } - else - { - mmodel2 = mapper2.createMapping(getName().c_str()); - } - m_constraint = sofa::core::objectmodel::New >(mmodel1, mmodel2); - m_constraint->setName( getName() ); - setInteractionTags(mmodel1, mmodel2); - m_constraint->setCustomTolerance(d_tol.getValue() ); - } - - int size = contacts.size(); - m_constraint->clear(size); - if (selfCollision) - mapper1.resize(2*size); - else - { - mapper1.resize(size); - mapper2.resize(size); - } - int i = 0; - const double d0 = intersectionMethod->getContactDistance() + model1->getProximity() + model2->getProximity(); // - 0.001; - - mappedContacts.resize(contacts.size()); - for (std::vector::const_iterator it = contacts.begin(); it!=contacts.end(); it++, i++) - { - sofa::core::collision::DetectionOutput* o = *it; - CollisionElement1 elem1(o->elem.first); - CollisionElement2 elem2(o->elem.second); - int index1 = elem1.getIndex(); - int index2 = elem2.getIndex(); - - typename DataTypes1::Real r1 = 0.; - typename DataTypes2::Real r2 = 0.; - - // Create mapping for first point - index1 = mapper1.addPointB(o->point[0], index1, r1); - // Create mapping for second point - if (selfCollision) - { - index2 = mapper1.addPointB(o->point[1], index2, r2); - } - else - { - index2 = mapper2.addPointB(o->point[1], index2, r2); - } - const double distance = d0 + r1 + r2; - - mappedContacts[i].first.first = index1; - mappedContacts[i].first.second = index2; - mappedContacts[i].second = distance; - } - - // Update mappings - mapper1.update(); - mapper1.updateXfree(); - if (!selfCollision) mapper2.update(); - if (!selfCollision) mapper2.updateXfree(); + return {d_mu.getValue()}; } -template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -void FrictionContact::createResponse(core::objectmodel::BaseContext* group) -{ - - activateMappers(); - const double mu_ = this->d_mu.getValue(); - // Checks if friction is considered - if ( mu_ < 0.0 ) - msg_error() << "mu has to take positive values"; - - if (m_constraint) - { - int i=0; - for (std::vector::const_iterator it = contacts.begin(); it!=contacts.end(); it++, i++) - { - const sofa::core::collision::DetectionOutput* o = *it; - const int index1 = mappedContacts[i].first.first; - const int index2 = mappedContacts[i].first.second; - const double distance = mappedContacts[i].second; - - // Polynome de Cantor de NxN sur N bijectif f(x,y)=((x+y)^2+3x+y)/2 - const long index = cantorPolynomia(o->id /*cantorPolynomia(index1, index2)*/,id); - - // Add contact in unilateral constraint - m_constraint->addContact(mu_, o->normal, distance, index1, index2, index, o->id); - } - - if (parent!=nullptr) - { - parent->removeObject(this); - parent->removeObject(m_constraint); - } - - parent = group; - if (parent!=nullptr) - { - parent->addObject(this); - parent->addObject(m_constraint); - } - } -} template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -void FrictionContact::removeResponse() +void FrictionContact::setupConstraint(MechanicalState1 * mmodel1,MechanicalState2 * mmodel2) { - if (m_constraint) - { - mapper1.resize(0); - mapper2.resize(0); - if (parent!=nullptr) - { - parent->removeObject(this); - parent->removeObject(m_constraint); - } - parent = nullptr; - } + this->m_constraint = sofa::core::objectmodel::New >(mmodel1, mmodel2); } -template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > -void FrictionContact::setInteractionTags(MechanicalState1* mstate1, MechanicalState2* mstate2) -{ - sofa::core::objectmodel::TagSet tagsm1 = mstate1->getTags(); - sofa::core::objectmodel::TagSet tagsm2 = mstate2->getTags(); - sofa::core::objectmodel::TagSet::iterator it; - for(it=tagsm1.begin(); it != tagsm1.end(); it++) - m_constraint->addTag(*it); - for(it=tagsm2.begin(); it!=tagsm2.end(); it++) - m_constraint->addTag(*it); -} } //namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/RuleBasedContactManager.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/RuleBasedContactManager.h index 76afa084d0d..c88b084da9b 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/RuleBasedContactManager.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/RuleBasedContactManager.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace sofa::component::collision::response::contact { @@ -104,7 +104,7 @@ class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API RuleBasedContactManager : pu }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData< type::vector > rules; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > rules; diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/StickContactConstraint.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/StickContactConstraint.h index d23b57efc94..cea3442ec71 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/StickContactConstraint.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/StickContactConstraint.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace sofa::component::collision::response::contact { @@ -73,7 +73,7 @@ class StickContactConstraint : public core::collision::Contact, public ContactId ~StickContactConstraint() override; public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_COLLISION_RESPONSE_CONTACT() - sofa::core::objectmodel::RenamedData f_keepAlive; + sofa::core::objectmodel::lifecycle::RenamedData f_keepAlive; Data d_keepAlive; ///< set to true to keep this contact alive even after collisions are no longer detected diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronAugmentedLagrangianContact.cpp b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronAugmentedLagrangianContact.cpp new file mode 100644 index 00000000000..d5fe12ce865 --- /dev/null +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronAugmentedLagrangianContact.cpp @@ -0,0 +1,60 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include +#include +#include +#include + +using namespace sofa::core::collision; + +namespace sofa::component::collision::response::contact +{ + +using namespace sofa::component::collision::geometry; + +Creator> > TetrahedronSphereAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronPointAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronLineAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronTriangleAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator > TetrahedronTetrahedronAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); + +Creator> > TetrahedronSpherePenalityAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronPointPenalityAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronLinePenalityAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator> > TetrahedronTrianglePenalityAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); +Creator > TetrahedronTetrahedronPenalityAugmentedLagrangianResponseClass("AugmentedLagrangianResponseConstraint",true); + +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::AugmentedLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse; + +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::AugmentedLagrangianResponse>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::AugmentedLagrangianResponse>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::AugmentedLagrangianResponse>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::AugmentedLagrangianResponse>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::AugmentedLagrangianResponse; + +} // namespace sofa::component::collision::response::contact diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronFrictionContact.cpp b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronFrictionContact.cpp index 3f20f87b676..53d5265d7bc 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronFrictionContact.cpp +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/TetrahedronFrictionContact.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace sofa::core::collision; @@ -44,6 +45,12 @@ Creator> > TetrahedronTrianglePenalityFrictionContactClass("FrictionContactConstraint",true); Creator > TetrahedronTetrahedronPenalityFrictionContactClass("FrictionContactConstraint",true); +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::BaseUnilateralContactResponse; + template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::FrictionContact>; template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::FrictionContact>; template class SOFA_COMPONENT_COLLISION_RESPONSE_CONTACT_API response::contact::FrictionContact>; diff --git a/Sofa/Component/Collision/Response/Contact/tests/CMakeLists.txt b/Sofa/Component/Collision/Response/Contact/tests/CMakeLists.txt index 73c983810c6..8da60705f95 100644 --- a/Sofa/Component/Collision/Response/Contact/tests/CMakeLists.txt +++ b/Sofa/Component/Collision/Response/Contact/tests/CMakeLists.txt @@ -6,7 +6,8 @@ set(SOURCE_FILES PenalityContactForceField_test.cpp ) + add_executable(${PROJECT_NAME} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} Sofa.Testing Sofa.Component.Collision.Testing Sofa.Component.SolidMechanics.Testing) -target_link_libraries(${PROJECT_NAME} Sofa.Component.Collision.Response.Contact) +target_link_libraries(${PROJECT_NAME} Sofa.Component.Collision.Response.Contact Sofa.Component.Constraint.Lagrangian) add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) diff --git a/Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp b/Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp index 562f561e99c..ae377f44842 100644 --- a/Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp +++ b/Sofa/Component/Collision/Response/Mapper/src/sofa/component/collision/response/mapper/init.cpp @@ -51,6 +51,7 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { // this library does not register any component in the Factory + SOFA_UNUSED(factory); } void init() diff --git a/Sofa/Component/Collision/Response/src/sofa/component/collision/response/init.cpp b/Sofa/Component/Collision/Response/src/sofa/component/collision/response/init.cpp index 1f530ac7e92..79fd36c7bd4 100644 --- a/Sofa/Component/Collision/Response/src/sofa/component/collision/response/init.cpp +++ b/Sofa/Component/Collision/Response/src/sofa/component/collision/response/init.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace sofa::component::collision::response { @@ -54,8 +55,8 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Response.Mapper"); - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Response.Contact"); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Response.Mapper); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Response.Contact); } void init() diff --git a/Sofa/Component/Collision/src/sofa/component/collision/init.cpp b/Sofa/Component/Collision/src/sofa/component/collision/init.cpp index 7fa133efb29..1423e912ea0 100644 --- a/Sofa/Component/Collision/src/sofa/component/collision/init.cpp +++ b/Sofa/Component/Collision/src/sofa/component/collision/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::collision { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Geometry"); - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Detection"); - factory->registerObjectsFromPlugin("Sofa.Component.Collision.Response"); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Geometry); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Detection); + factory->registerObjectsFromPlugin(Sofa.Component.Collision.Response); } void init() diff --git a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/PrecomputedConstraintCorrection.h b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/PrecomputedConstraintCorrection.h index 2a296bc9b8c..f075378651d 100644 --- a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/PrecomputedConstraintCorrection.h +++ b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/PrecomputedConstraintCorrection.h @@ -30,7 +30,7 @@ #include #include -#include +#include namespace sofa::component::constraint::lagrangian::correction { @@ -61,22 +61,22 @@ class PrecomputedConstraintCorrection : public sofa::core::behavior::ConstraintC typedef sofa::type::MatNoInit<3, 3, Real> Transformation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData m_rotations; + sofa::core::objectmodel::lifecycle::RenamedData m_rotations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData m_restRotations; + sofa::core::objectmodel::lifecycle::RenamedData m_restRotations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData recompute; + sofa::core::objectmodel::lifecycle::RenamedData recompute; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData debugViewFrameScale; + sofa::core::objectmodel::lifecycle::RenamedData debugViewFrameScale; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData f_fileCompliance; + sofa::core::objectmodel::lifecycle::RenamedData f_fileCompliance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData fileDir; + sofa::core::objectmodel::lifecycle::RenamedData fileDir; Data d_rotations; Data d_restRotations; diff --git a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.h b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.h index 0954dbefcec..4ee8641eb7d 100644 --- a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.h +++ b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::constraint::lagrangian::correction { @@ -113,13 +113,13 @@ class UncoupledConstraintCorrection : public sofa::core::behavior::ConstraintCor SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData< VecReal > compliance; + sofa::core::objectmodel::lifecycle::RenamedData< VecReal > compliance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData defaultCompliance; + sofa::core::objectmodel::lifecycle::RenamedData defaultCompliance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_CORRECTION() - sofa::core::objectmodel::RenamedData f_verbose; + sofa::core::objectmodel::lifecycle::RenamedData f_verbose; core::topology::PointData< VecReal > d_compliance; ///< Compliance value on each dof. If Rigid compliance (7 values): 1st value for translations, 6 others for upper-triangular part of symmetric 3x3 rotation compliance matrix diff --git a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.inl b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.inl index bffe28596b2..ebe49bd83c2 100644 --- a/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.inl +++ b/Sofa/Component/Constraint/Lagrangian/Correction/src/sofa/component/constraint/lagrangian/correction/UncoupledConstraintCorrection.inl @@ -128,7 +128,7 @@ UncoupledConstraintCorrection::UncoupledConstraintCorrection(sofa::co else { // Case: soft body - if constexpr (!sofa::type::isRigidType()) + if constexpr (!sofa::type::isRigidType) { const VecReal &comp = d_compliance.getValue(); if (std::any_of(comp.begin(), comp.end(), [](const Real c) { return c == 0; })) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/CMakeLists.txt b/Sofa/Component/Constraint/Lagrangian/Model/CMakeLists.txt index 05559157449..07cfdad10db 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/CMakeLists.txt +++ b/Sofa/Component/Constraint/Lagrangian/Model/CMakeLists.txt @@ -19,6 +19,11 @@ set(HEADER_FILES ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/UnilateralInteractionConstraint.h ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/UnilateralInteractionConstraint.inl + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/AugmentedLagrangianResolution.h + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/AugmentedLagrangianConstraint.h + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/AugmentedLagrangianConstraint.inl + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/BaseContactLagrangianConstraint.h + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/BaseContactLagrangianConstraint.inl ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/BilateralLagrangianConstraint.h ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/BilateralLagrangianConstraint.inl ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/FixedLagrangianConstraint.h @@ -35,6 +40,7 @@ set(HEADER_FILES set(SOURCE_FILES ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/init.cpp + ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/AugmentedLagrangianConstraint.cpp ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/BilateralLagrangianConstraint.cpp ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/FixedLagrangianConstraint.cpp ${SOFACOMPONENTCONSTRAINTLAGRANGIANMODEL_SOURCE_DIR}/SlidingLagrangianConstraint.cpp diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.cpp b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.cpp new file mode 100644 index 00000000000..e3970402ce7 --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.cpp @@ -0,0 +1,109 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#define SOFA_COMPONENT_CONSTRAINTSET_AugmentedLagrangianConstraint_CPP +#include +#include +#include +#include + +namespace sofa::component::constraint::lagrangian::model +{ + +using namespace sofa::defaulttype; +using namespace sofa::helper; + +void registerAugmentedLagrangianConstraint(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("AugmentedLagrangianConstraint") + .add< AugmentedLagrangianConstraint >()); +} + +template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API BaseContactLagrangianConstraint; +template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API AugmentedLagrangianConstraint; + + + +void AugmentedLagrangianResolutionWithFriction::init(int line, SReal** w, SReal* force) +{ + _W[0]=w[line ][line ]; + _W[1]=w[line ][line+1]; + _W[2]=w[line ][line+2]; + _W[3]=w[line+1][line+1]; + _W[4]=w[line+1][line+2]; + _W[5]=w[line+2][line+2]; + + ////////////////// christian : the following does not work ! ///////// + if(_prev) + { + force[line] = _prev->popForce(); + force[line+1] = _prev->popForce(); + force[line+2] = _prev->popForce(); + } + +} + +void AugmentedLagrangianResolutionWithFriction::resolution(int line, SReal** /*w*/, SReal* d, SReal* force, SReal * /*dfree*/) +{ + force[line] -= d[line] * _epsilon; + + if(force[line] < 0) + { + force[line]=0; force[line+1]=0; force[line+2]=0; + return; + } + + const SReal f_t_0 = force[line + 1] - d[line+ 1] * _epsilon; + const SReal f_t_1 = force[line + 2] - d[line+ 2] * _epsilon; + + const SReal criteria = sqrt(pow(f_t_0,2.0) + pow(f_t_1,2.0)) - _mu * fabs(force[line]); + + if(criteria<0) + { + force[line+1] = f_t_0 ; + force[line+2] = f_t_1 ; + } + else + { + const SReal norm_s = sqrt(pow(d[line+ 1],2.0) + pow(d[line+ 2],2.0)); + force[line+1] -= _mu * d[line] * _epsilon * d[line+ 1]/norm_s; + force[line+2] -= _mu * d[line] * _epsilon * d[line+ 2]/norm_s; + } +} + +void AugmentedLagrangianResolutionWithFriction::store(int line, SReal* force, bool /*convergence*/) +{ + if(_prev) + { + _prev->pushForce(force[line]); + _prev->pushForce(force[line+1]); + _prev->pushForce(force[line+2]); + } + + if(_active) + { + *_active = (force[line] != 0); + _active = nullptr; // Won't be used in the haptic thread + } +} + + +} //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.h new file mode 100644 index 00000000000..46dab0e3a63 --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.h @@ -0,0 +1,87 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sofa::component::constraint::lagrangian::model +{ + +struct AugmentedLagrangianContactParameters final : public BaseContactParams +{ + AugmentedLagrangianContactParameters() : mu(0.0), epsilon(0.0) {}; + AugmentedLagrangianContactParameters(SReal _mu, SReal _epsilon) : mu(_mu), epsilon(_epsilon) {}; + + virtual bool hasTangentialComponent() const override + { + return mu>0.0; + } + + SReal mu; + SReal epsilon; +}; + +template +class AugmentedLagrangianConstraint : public BaseContactLagrangianConstraint +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(AugmentedLagrangianConstraint,DataTypes), SOFA_TEMPLATE2(BaseContactLagrangianConstraint,DataTypes,AugmentedLagrangianContactParameters)); + typedef BaseContactLagrangianConstraint Inherit; + typedef typename Inherit::MechanicalState MechanicalState; + typedef typename Inherit::Contact Contact; + +protected: + AugmentedLagrangianConstraint(MechanicalState* object1=nullptr, MechanicalState* object2=nullptr); + virtual ~AugmentedLagrangianConstraint() = default; + +public: + virtual void getConstraintResolution(const core::ConstraintParams *,std::vector& resTab, unsigned int& offset) override; + + virtual type::vector getUnilateralInteractionIdentifiers() override final + { + type::vector ids = getAugmentedLagrangianIdentifiers(); + ids.push_back("Augmented"); + return ids; + } + + virtual type::vector getAugmentedLagrangianIdentifiers() {return {};} + + +}; + + +#if !defined(SOFA_COMPONENT_CONSTRAINTSET_AugmentedLagrangianConstraint_CPP) + extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API BaseContactLagrangianConstraint; + extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API AugmentedLagrangianConstraint; +#endif + + +} //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.inl b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.inl new file mode 100644 index 00000000000..914c64f6a3a --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianConstraint.inl @@ -0,0 +1,70 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include + +namespace sofa::component::constraint::lagrangian::model +{ + +template +AugmentedLagrangianConstraint::AugmentedLagrangianConstraint(MechanicalState* object1, MechanicalState* object2) + : Inherit(object1, object2) +{ +} + +template +void AugmentedLagrangianConstraint::getConstraintResolution(const core::ConstraintParams *, std::vector& resTab, unsigned int& offset) +{ + if(this->contactsStatus) + { + delete[] this->contactsStatus; + this->contactsStatus = nullptr; + } + + if (this->contacts.size() > 0) + { + this->contactsStatus = new bool[this->contacts.size()]; + memset(this->contactsStatus, 0, sizeof(bool)*this->contacts.size()); + } + + for(unsigned int i=0; icontacts.size(); i++) + { + Contact& c = this->contacts[i]; + if(c.parameters.hasTangentialComponent()) + { + AugmentedLagrangianResolutionWithFriction* ucrwf = new AugmentedLagrangianResolutionWithFriction(c.parameters.mu,c.parameters.epsilon, nullptr, &(this->contactsStatus[i])); + ucrwf->setTolerance(this->customTolerance); + resTab[offset] = ucrwf; + + // NOTE: this method of storing forces may not work well with 2 threads when using haptics + offset += 3; + } + else + resTab[offset++] = new AugmentedLagrangianResolution(c.parameters.epsilon); + } +} + +} //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianResolution.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianResolution.h new file mode 100644 index 00000000000..78ff8d7bb73 --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/AugmentedLagrangianResolution.h @@ -0,0 +1,74 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include + + +namespace sofa::component::constraint::lagrangian::model +{ + +class AugmentedLagrangianResolution : public core::behavior::ConstraintResolution +{ + public: + AugmentedLagrangianResolution(SReal epsilon) : core::behavior::ConstraintResolution(1), m_epsilon(epsilon) {} + + void resolution(int line, SReal** w, SReal* d, SReal* force, SReal* dfree) override + { + SOFA_UNUSED(dfree); + force[line] -= d[line] / w[line][line]; + if (force[line] < 0) force[line] = 0.0; + } +private: + SReal m_epsilon; +}; + + +class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API AugmentedLagrangianResolutionWithFriction + : public core::behavior::ConstraintResolution +{ + public: + AugmentedLagrangianResolutionWithFriction(SReal mu, SReal epsilon, PreviousForcesContainer* prev = nullptr, + bool* active = nullptr) + : core::behavior::ConstraintResolution(3), _mu(mu), _epsilon(epsilon), _prev(prev), _active(active) + { + } + + void init(int line, SReal** w, SReal* force) override; + void resolution(int line, SReal** w, SReal* d, SReal* force, SReal* dFree) override; + void store(int line, SReal* force, bool /*convergence*/) override; + + protected: + SReal _mu; + SReal _epsilon; + SReal _W[6]; + PreviousForcesContainer* _prev; + bool* _active; // Will set this after the resolution +}; + +} \ No newline at end of file diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.h new file mode 100644 index 00000000000..512a06ebd5b --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.h @@ -0,0 +1,160 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sofa::component::constraint::lagrangian::model +{ + + +//TODO(Paul) C++20: add concept for ContactParams +// Every ContactParams should implement hasTangentialComponent +struct BaseContactParams +{ + virtual bool hasTangentialComponent() const = 0; +}; + +template +class BaseContactLagrangianConstraint : public core::behavior::PairInteractionConstraint +{ +public: + SOFA_CLASS(SOFA_TEMPLATE2(BaseContactLagrangianConstraint,DataTypes,ContactParams), SOFA_TEMPLATE(core::behavior::PairInteractionConstraint,DataTypes)); + + typedef typename DataTypes::VecCoord VecCoord; + typedef typename DataTypes::VecDeriv VecDeriv; + typedef typename DataTypes::MatrixDeriv MatrixDeriv; + typedef typename DataTypes::MatrixDeriv::RowConstIterator MatrixDerivRowConstIterator; + typedef typename DataTypes::MatrixDeriv::ColConstIterator MatrixDerivColConstIterator; + typedef typename DataTypes::MatrixDeriv::RowIterator MatrixDerivRowIterator; + typedef typename DataTypes::MatrixDeriv::ColIterator MatrixDerivColIterator; + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::Deriv Deriv; + typedef typename Coord::value_type Real; + typedef typename core::behavior::MechanicalState MechanicalState; + + typedef core::behavior::BaseConstraint::ConstraintBlockInfo ConstraintBlockInfo; + typedef core::behavior::BaseConstraint::PersistentID PersistentID; + typedef core::behavior::BaseConstraint::ConstCoord ConstCoord; + + typedef core::behavior::BaseConstraint::VecConstraintBlockInfo VecConstraintBlockInfo; + typedef core::behavior::BaseConstraint::VecPersistentID VecPersistentID; + typedef core::behavior::BaseConstraint::VecConstCoord VecConstCoord; + typedef core::behavior::BaseConstraint::VecConstDeriv VecConstDeriv; + typedef core::behavior::BaseConstraint::VecConstArea VecConstArea; + + typedef core::objectmodel::Data DataVecCoord; + typedef core::objectmodel::Data DataVecDeriv; + typedef core::objectmodel::Data DataMatrixDeriv; + + typedef typename core::behavior::PairInteractionConstraint Inherit; + +protected: + + struct Contact + { + int m1, m2; ///< the two extremities of the spring: masses m1 and m2 + Deriv norm; ///< contact normal, from m1 to m2 + Deriv t; ///< added for friction + Deriv s; ///< added for friction + Real contactDistance; + + unsigned int id; + long contactId; + PersistentID localId; + ContactParams parameters; + + Coord P, Q; + + mutable Real dfree; + }; + + sofa::type::vector contacts; + bool yetIntegrated; + SReal customTolerance; + + bool* contactsStatus; + + /// Computes constraint violation in position and stores it into resolution global vector + /// + /// @param v Global resolution vector + virtual void getPositionViolation(linearalgebra::BaseVector *v); + + ///Computes constraint violation in velocity and stores it into resolution global vector + /// + /// @param v Global resolution vector + virtual void getVelocityViolation(linearalgebra::BaseVector *v); + +public: + + unsigned int constraintId; +protected: + + virtual type::vector getUnilateralInteractionIdentifiers() {return {};} + + virtual type::vector getPairInteractionIdentifiers() override final + { + type::vector ids = getUnilateralInteractionIdentifiers(); + ids.push_back("Unilateral"); + return ids; + } + + + BaseContactLagrangianConstraint(MechanicalState* object1=nullptr, MechanicalState* object2=nullptr); + virtual ~BaseContactLagrangianConstraint(); + +public: + void setCustomTolerance(SReal tol) { customTolerance = tol; } + + void clear(int reserve=0); + + + void addContact(const ContactParams& parameters, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id=0, PersistentID localid=0); + void addContact(const ContactParams& parameters, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, long id=0, PersistentID localid=0); + void addContact(const ContactParams& parameters, Deriv norm, Real contactDistance, int m1, int m2, long id=0, PersistentID localid=0); + + void buildConstraintMatrix(const core::ConstraintParams* cParams, DataMatrixDeriv &c1, DataMatrixDeriv &c2, unsigned int &cIndex + , const DataVecCoord &x1, const DataVecCoord &x2) override; + + void getConstraintViolation(const core::ConstraintParams* cParams, linearalgebra::BaseVector *v, const DataVecCoord &x1, const DataVecCoord &x2 + , const DataVecDeriv &v1, const DataVecDeriv &v2) override; + + + void getConstraintInfo(const core::ConstraintParams* cParams, VecConstraintBlockInfo& blocks, VecPersistentID& ids, VecConstCoord& positions, VecConstDeriv& directions, VecConstArea& areas) override; + + virtual void getConstraintResolution(const core::ConstraintParams *,std::vector& resTab, unsigned int& offset) =0; + bool isActive() const override; + + void draw(const core::visual::VisualParams* vparams) override; +}; + + +} //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.inl b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.inl new file mode 100644 index 00000000000..27263e58dc1 --- /dev/null +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BaseContactLagrangianConstraint.inl @@ -0,0 +1,386 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include + +namespace sofa::component::constraint::lagrangian::model +{ + +template +BaseContactLagrangianConstraint::BaseContactLagrangianConstraint(MechanicalState* object1, MechanicalState* object2) + : Inherit(object1, object2) + , yetIntegrated(false) + , customTolerance(0.0) + , contactsStatus(nullptr) +{ +} + +template +BaseContactLagrangianConstraint::~BaseContactLagrangianConstraint() +{ + if(contactsStatus) + delete[] contactsStatus; +} + +template +void BaseContactLagrangianConstraint::clear(int reserve) +{ + contacts.clear(); + if (reserve) + contacts.reserve(reserve); +} + +template +void BaseContactLagrangianConstraint::addContact(const ContactParams& parameters, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, long id, PersistentID localid) +{ + addContact(parameters, norm, P, Q, contactDistance, m1, m2, + this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue()[m2], + this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue()[m1], + id, localid); +} + +template +void BaseContactLagrangianConstraint::addContact(const ContactParams& parameters, Deriv norm, Real contactDistance, int m1, int m2, long id, PersistentID localid) +{ + addContact(parameters, norm, + this->getMState2()->read(core::vec_id::read_access::position)->getValue()[m2], + this->getMState1()->read(core::vec_id::read_access::position)->getValue()[m1], + contactDistance, m1, m2, + this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue()[m2], + this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue()[m1], + id, localid); +} + +template +void BaseContactLagrangianConstraint::addContact(const ContactParams& parameters, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord /*Pfree*/, Coord /*Qfree*/, long id, PersistentID localid) +{ + contacts.resize(contacts.size() + 1); + Contact &c = contacts.back(); + + c.P = P; + c.Q = Q; + c.m1 = m1; + c.m2 = m2; + c.norm = norm; + c.t = Deriv(norm.z(), norm.x(), norm.y()); + c.s = cross(norm, c.t); + c.s = c.s / c.s.norm(); + c.t = cross((-norm), c.s); + c.parameters= parameters; + c.contactId = id; + c.localId = localid; + c.contactDistance = contactDistance; +} + + +template +void BaseContactLagrangianConstraint::buildConstraintMatrix(const core::ConstraintParams *, DataMatrixDeriv &c1_d, DataMatrixDeriv &c2_d, unsigned int &contactId + , const DataVecCoord &, const DataVecCoord &) +{ + assert(this->mstate1); + assert(this->mstate2); + + if (this->mstate1 == this->mstate2) + { + helper::WriteAccessor c1 = c1_d; + + + for (unsigned int i = 0; i < contacts.size(); i++) + { + Contact& c = contacts[i]; + + c.id = contactId++; + + MatrixDerivRowIterator c1_it = c1->writeLine(c.id); + + c1_it.addCol(c.m1, -c.norm); + c1_it.addCol(c.m2, c.norm); + + if (c.parameters.hasTangentialComponent()) + { + c1_it = c1->writeLine(c.id + 1); + c1_it.setCol(c.m1, -c.t); + c1_it.setCol(c.m2, c.t); + + c1_it = c1->writeLine(c.id + 2); + c1_it.setCol(c.m1, -c.s); + c1_it.setCol(c.m2, c.s); + + contactId += 2; + } + } + + } + else + { + helper::WriteAccessor c1 = c1_d; + helper::WriteAccessor c2 = c2_d; + + for (unsigned int i = 0; i < contacts.size(); i++) + { + Contact& c = contacts[i]; + + c.id = contactId++; + + MatrixDerivRowIterator c1_it = c1->writeLine(c.id); + c1_it.addCol(c.m1, -c.norm); + + MatrixDerivRowIterator c2_it = c2->writeLine(c.id); + c2_it.addCol(c.m2, c.norm); + + if (c.parameters.hasTangentialComponent()) + { + c1_it = c1->writeLine(c.id + 1); + c1_it.setCol(c.m1, -c.t); + + c1_it = c1->writeLine(c.id + 2); + c1_it.setCol(c.m1, -c.s); + + c2_it = c2->writeLine(c.id + 1); + c2_it.setCol(c.m2, c.t); + + c2_it = c2->writeLine(c.id + 2); + c2_it.setCol(c.m2, c.s); + + contactId += 2; + } + } + + } +} + + +template +void BaseContactLagrangianConstraint::getPositionViolation(linearalgebra::BaseVector *v) +{ + const VecCoord &PfreeVec = this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue(); + const VecCoord &QfreeVec = this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue(); + + Real dfree = (Real)0.0; + Real dfree_t = (Real)0.0; + Real dfree_s = (Real)0.0; + + const unsigned int cSize = contacts.size(); + + for (unsigned int i = 0; i < cSize; i++) + { + const Contact& c = contacts[i]; + + // Compute dfree, dfree_t and d_free_s + + const Coord &Pfree = PfreeVec[c.m2]; + const Coord &Qfree = QfreeVec[c.m1]; + + const Coord PPfree = Pfree - c.P; + const Coord QQfree = Qfree - c.Q; + + const Real ref_dist = PPfree.norm() + QQfree.norm(); + + dfree = dot(Pfree - Qfree, c.norm) - c.contactDistance; + const Real delta = dot(c.P - c.Q, c.norm) - c.contactDistance; + + if ((helper::rabs(delta) < 0.00001 * ref_dist) && (helper::rabs(dfree) < 0.00001 * ref_dist)) + { + dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); + dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); + } + else if (helper::rabs(delta - dfree) > 0.001 * delta) + { + const Real dt = delta / (delta - dfree); + + if (dt > 0.0 && dt < 1.0) + { + const Coord Pt = c.P * (1 - dt) + Pfree * dt; + const Coord Qt = c.Q * (1 - dt) + Qfree * dt; + const Coord PtPfree = Pfree - Pt; + const Coord QtQfree = Qfree - Qt; + + dfree_t = dot(PtPfree, c.t) - dot(QtQfree, c.t); + dfree_s = dot(PtPfree, c.s) - dot(QtQfree, c.s); + } + else if (dfree < 0.0) + { + dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); + dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); + } + else + { + dfree_t = 0; + dfree_s = 0; + } + } + else + { + dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); + dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); + } + + // Sets dfree in global violation vector + + v->set(c.id, dfree); + + c.dfree = dfree; // PJ : For isActive() method. Don't know if it's still usefull. + + if (c.parameters.hasTangentialComponent()) + { + v->set(c.id + 1, dfree_t); + v->set(c.id + 2, dfree_s); + } + } +} + + +template +void BaseContactLagrangianConstraint::getVelocityViolation(linearalgebra::BaseVector *v) +{ + auto P = this->getMState2()->readPositions(); + auto Q = this->getMState1()->readPositions(); + + const SReal dt = this->getContext()->getDt(); + const SReal invDt = SReal(1.0) / dt; + + const VecDeriv &PvfreeVec = this->getMState2()->read(core::vec_id::read_access::freeVelocity)->getValue(); + const VecDeriv &QvfreeVec = this->getMState1()->read(core::vec_id::read_access::freeVelocity)->getValue(); + + const unsigned int cSize = contacts.size(); + + for (unsigned int i = 0; i < cSize; i++) + { + const Contact& c = contacts[i]; + + const Deriv QP_invDt = (P[c.m2] - Q[c.m1])*invDt; + const Deriv QP_vfree = PvfreeVec[c.m2] - QvfreeVec[c.m1]; + const Deriv dFreeVec = QP_vfree + QP_invDt; + + v->set(c.id, dot(dFreeVec, c.norm) - c.contactDistance*invDt ); // dvfree = 1/dt * [ dot ( P - Q, n) - contactDist ] + dot(v_P - v_Q , n ) ] + + if (c.parameters.hasTangentialComponent()) + { + v->set(c.id + 1, dot(QP_vfree, c.t)); // dfree_t + v->set(c.id + 2, dot(QP_vfree, c.s)); // dfree_s + } + } +} + + +template +void BaseContactLagrangianConstraint::getConstraintViolation(const core::ConstraintParams *cparams, linearalgebra::BaseVector *v, const DataVecCoord &, const DataVecCoord & + , const DataVecDeriv &, const DataVecDeriv &) +{ + switch (cparams->constOrder()) + { + case core::ConstraintOrder::POS_AND_VEL : + case core::ConstraintOrder::POS : + getPositionViolation(v); + break; + + case core::ConstraintOrder::ACC : + case core::ConstraintOrder::VEL : + getVelocityViolation(v); + break; + + default : + msg_error() << "BaseContactLagrangianConstraint doesn't implement " << cparams->getName() << " constraint violation\n"; + break; + } +} + + +template +void BaseContactLagrangianConstraint::getConstraintInfo(const core::ConstraintParams*, VecConstraintBlockInfo& blocks, VecPersistentID& ids, VecConstCoord& /*positions*/, VecConstDeriv& directions, VecConstArea& /*areas*/) +{ + if (contacts.empty()) return; + const bool friction = (contacts[0].parameters.mu > 0.0); /// @todo: can there be both friction-less and friction contacts in the same BaseContactLagrangianConstraint ??? + ConstraintBlockInfo info; + info.parent = this; + info.const0 = contacts[0].id; + info.nbLines = friction ? 3 : 1; + info.hasId = true; + info.offsetId = ids.size(); + info.hasDirection = true; + info.offsetDirection = directions.size(); + info.nbGroups = contacts.size(); + + for (unsigned int i=0; i +bool BaseContactLagrangianConstraint::isActive() const +{ + for(unsigned int i = 0; i < contacts.size(); i++) + if(contacts[i].dfree < 0) + return true; + + return false; +} + +template +void BaseContactLagrangianConstraint::draw(const core::visual::VisualParams* vparams) +{ + if (!vparams->displayFlags().getShowInteractionForceFields()) return; + + const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); + vparams->drawTool()->disableLighting(); + + std::vector redVertices; + std::vector otherVertices; + std::vector otherColors; + + for (unsigned int i=0; idrawTool()->drawLines(otherVertices, 3, otherColors); + + + + +} + +} //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp index a1f07d3db8c..5ba36d4df61 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp @@ -90,7 +90,7 @@ class BilateralLagrangianConstraintSpecialization static void getConstraintResolution(BilateralLagrangianConstraint& self, const ConstraintParams* cParams, std::vector& resTab, - unsigned int& offset, SReal tolerance) + unsigned int& offset) { SOFA_UNUSED(cParams); const unsigned minp = std::min(self.d_m1.getValue().size(), @@ -100,7 +100,6 @@ class BilateralLagrangianConstraintSpecialization resTab[offset] = new BilateralConstraintResolution3Dof(); offset += 3; BilateralConstraintResolution3Dof* temp = new BilateralConstraintResolution3Dof(); - temp->setTolerance(tolerance); // specific (smaller) tolerance for the rotation resTab[offset] = temp; offset += 3; } @@ -276,8 +275,7 @@ void BilateralLagrangianConstraint::getConstraintResolution( unsigned int& offset) { RigidBilateralLagrangianConstraint::getConstraintResolution(*this, - cParams, resTab, offset, - d_numericalTolerance.getValue()); + cParams, resTab, offset); } template <> SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h index abc001ded95..9b693e076e3 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h @@ -35,7 +35,7 @@ #include -#include +#include namespace sofa::component::constraint::lagrangian::model { @@ -98,23 +98,24 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint cid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData > m1; + sofa::core::objectmodel::lifecycle::RenamedData > m1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData > m2; + sofa::core::objectmodel::lifecycle::RenamedData > m2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData restVector; + sofa::core::objectmodel::lifecycle::RenamedData restVector; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData keepOrientDiff; + sofa::core::objectmodel::lifecycle::RenamedData keepOrientDiff; DataSubsetIndices d_m1; ///< index of the constraint on the first model DataSubsetIndices d_m2; ///< index of the constraint on the second model Data d_restVector; ///< Relative position to maintain between attached points (optional) VecCoord initialDifference; - Data d_numericalTolerance; ///< a real value specifying the tolerance during the constraint solving. (default=0.0001 + SOFA_ATTRIBUTE_DEPRECATED__BILATERALREMOVEUNUSEDTOLERANCE() DeprecatedAndRemoved d_numericalTolerance; ///< a real value specifying the tolerance during the constraint solving. (default=0.0001 + Data d_activate; ///< control constraint activation (true by default) Data d_keepOrientDiff; ///< keep the initial difference in orientation (only for rigids) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl index 28e5ddd9d19..18a56f733cd 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl @@ -44,8 +44,6 @@ BilateralLagrangianConstraint::BilateralLagrangianConstraint(Mechanic , d_m1(initData(&d_m1, "first_point","index of the constraint on the first model (object1)")) , d_m2(initData(&d_m2, "second_point","index of the constraint on the second model (object2)")) , d_restVector(initData(&d_restVector, "rest_vector","Relative position to maintain between attached points (optional)")) - , d_numericalTolerance(initData(&d_numericalTolerance, 1e-4_sreal, "numericalTolerance", - "a real value specifying the tolerance during the constraint solving.") ) , d_activate( initData(&d_activate, true, "activate", "control constraint activation (true by default)")) , d_keepOrientDiff(initData(&d_keepOrientDiff, false, "keepOrientationDifference", "keep the initial difference in orientation (only for rigids)")) , l_topology1(initLink("topology1", "link to the first topology container")) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/StopperLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/StopperLagrangianConstraint.h index aeebd35cf94..2b7b3413745 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/StopperLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/StopperLagrangianConstraint.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::constraint::lagrangian::model { @@ -89,13 +89,13 @@ class StopperLagrangianConstraint : public core::behavior::Constraint protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData index; + sofa::core::objectmodel::lifecycle::RenamedData index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData min; + sofa::core::objectmodel::lifecycle::RenamedData min; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() - sofa::core::objectmodel::RenamedData max; + sofa::core::objectmodel::lifecycle::RenamedData max; Data d_index; ///< index of the stop constraint diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.cpp b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.cpp index ab1fa1724c8..5e477574304 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.cpp @@ -20,6 +20,9 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #define SOFA_COMPONENT_CONSTRAINTSET_UNILATERALLAGRANGIANCONSTRAINT_CPP +#include +#include +#include #include #include #include @@ -28,6 +31,8 @@ namespace sofa::component::constraint::lagrangian::model { using namespace sofa::defaulttype; +using namespace sofa::helper; + void registerUnilateralLagrangianConstraint(sofa::core::ObjectFactory* factory) { @@ -35,6 +40,8 @@ void registerUnilateralLagrangianConstraint(sofa::core::ObjectFactory* factory) .add< UnilateralLagrangianConstraint >()); } + +template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API BaseContactLagrangianConstraint; template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API UnilateralLagrangianConstraint; diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.h index f58a0ac1b72..1c888ee0bdd 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,124 +35,41 @@ namespace sofa::component::constraint::lagrangian::model { -template -class UnilateralLagrangianConstraint : public core::behavior::PairInteractionConstraint +struct UnilateralLagrangianContactParameters final : public BaseContactParams { -public: - SOFA_CLASS(SOFA_TEMPLATE(UnilateralLagrangianConstraint,DataTypes), SOFA_TEMPLATE(core::behavior::PairInteractionConstraint,DataTypes)); - - typedef typename DataTypes::VecCoord VecCoord; - typedef typename DataTypes::VecDeriv VecDeriv; - typedef typename DataTypes::MatrixDeriv MatrixDeriv; - typedef typename DataTypes::MatrixDeriv::RowConstIterator MatrixDerivRowConstIterator; - typedef typename DataTypes::MatrixDeriv::ColConstIterator MatrixDerivColConstIterator; - typedef typename DataTypes::MatrixDeriv::RowIterator MatrixDerivRowIterator; - typedef typename DataTypes::MatrixDeriv::ColIterator MatrixDerivColIterator; - typedef typename DataTypes::Coord Coord; - typedef typename DataTypes::Deriv Deriv; - typedef typename Coord::value_type Real; - typedef typename core::behavior::MechanicalState MechanicalState; - - typedef core::behavior::BaseConstraint::ConstraintBlockInfo ConstraintBlockInfo; - typedef core::behavior::BaseConstraint::PersistentID PersistentID; - typedef core::behavior::BaseConstraint::ConstCoord ConstCoord; + UnilateralLagrangianContactParameters() : mu(0.0) {}; + UnilateralLagrangianContactParameters(SReal _mu) : mu(_mu) {}; - typedef core::behavior::BaseConstraint::VecConstraintBlockInfo VecConstraintBlockInfo; - typedef core::behavior::BaseConstraint::VecPersistentID VecPersistentID; - typedef core::behavior::BaseConstraint::VecConstCoord VecConstCoord; - typedef core::behavior::BaseConstraint::VecConstDeriv VecConstDeriv; - typedef core::behavior::BaseConstraint::VecConstArea VecConstArea; - - typedef core::objectmodel::Data DataVecCoord; - typedef core::objectmodel::Data DataVecDeriv; - typedef core::objectmodel::Data DataMatrixDeriv; - - typedef typename core::behavior::PairInteractionConstraint Inherit; - -protected: - - struct Contact + virtual bool hasTangentialComponent() const override { - int m1, m2; ///< the two extremities of the spring: masses m1 and m2 - Deriv norm; ///< contact normal, from m1 to m2 - Deriv t; ///< added for friction - Deriv s; ///< added for friction - Real contactDistance; - - unsigned int id; - long contactId; - PersistentID localId; - SReal mu; ///< angle for friction - - Coord P, Q; - - mutable Real dfree; - }; - - sofa::type::vector contacts; - Real epsilon; - bool yetIntegrated; - SReal customTolerance; - - PreviousForcesContainer prevForces; - bool* contactsStatus; - - /// Computes constraint violation in position and stores it into resolution global vector - /// - /// @param v Global resolution vector - virtual void getPositionViolation(linearalgebra::BaseVector *v); + return mu>0.0; + } - ///Computes constraint violation in velocity and stores it into resolution global vector - /// - /// @param v Global resolution vector - virtual void getVelocityViolation(linearalgebra::BaseVector *v); + SReal mu; +}; +template +class UnilateralLagrangianConstraint : public BaseContactLagrangianConstraint +{ public: + SOFA_CLASS(SOFA_TEMPLATE(UnilateralLagrangianConstraint,DataTypes), SOFA_TEMPLATE2(BaseContactLagrangianConstraint,DataTypes,UnilateralLagrangianContactParameters)); + typedef BaseContactLagrangianConstraint Inherit; + typedef typename Inherit::MechanicalState MechanicalState; + typedef typename Inherit::Contact Contact; - unsigned int constraintId; protected: - - virtual type::vector getUnilateralInteractionIdentifiers() {return {};} - - virtual type::vector getPairInteractionIdentifiers() override final - { - type::vector ids = getUnilateralInteractionIdentifiers(); - ids.push_back("Unilateral"); - return ids; - } - - UnilateralLagrangianConstraint(MechanicalState* object1=nullptr, MechanicalState* object2=nullptr); - virtual ~UnilateralLagrangianConstraint(); + virtual ~UnilateralLagrangianConstraint() = default; public: - void setCustomTolerance(SReal tol) { customTolerance = tol; } - - void clear(int reserve = 0); - - virtual void addContact(SReal mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord Pfree, Coord Qfree, long id=0, PersistentID localid=0); - - void addContact(SReal mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, long id=0, PersistentID localid=0); - void addContact(SReal mu, Deriv norm, Real contactDistance, int m1, int m2, long id=0, PersistentID localid=0); - - void buildConstraintMatrix(const core::ConstraintParams* cParams, DataMatrixDeriv &c1, DataMatrixDeriv &c2, unsigned int &cIndex - , const DataVecCoord &x1, const DataVecCoord &x2) override; - - void getConstraintViolation(const core::ConstraintParams* cParams, linearalgebra::BaseVector *v, const DataVecCoord &x1, const DataVecCoord &x2 - , const DataVecDeriv &v1, const DataVecDeriv &v2) override; - - - void getConstraintInfo(const core::ConstraintParams* cParams, VecConstraintBlockInfo& blocks, VecPersistentID& ids, VecConstCoord& positions, VecConstDeriv& directions, VecConstArea& areas) override; - - void getConstraintResolution(const core::ConstraintParams *,std::vector& resTab, unsigned int& offset) override; - bool isActive() const override; + virtual void getConstraintResolution(const core::ConstraintParams *,std::vector& resTab, unsigned int& offset) override; - void draw(const core::visual::VisualParams* vparams) override; }; #if !defined(SOFA_COMPONENT_CONSTRAINTSET_UNILATERALLAGRANGIANCONSTRAINT_CPP) -extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API UnilateralLagrangianConstraint; + extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API BaseContactLagrangianConstraint; + extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API UnilateralLagrangianConstraint; #endif diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.inl b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.inl index a24d49ce910..f4b4d92ac6e 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.inl +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/UnilateralLagrangianConstraint.inl @@ -32,340 +32,31 @@ namespace sofa::component::constraint::lagrangian::model template UnilateralLagrangianConstraint::UnilateralLagrangianConstraint(MechanicalState* object1, MechanicalState* object2) : Inherit(object1, object2) - , epsilon(Real(0.001)) - , yetIntegrated(false) - , customTolerance(0.0) - , contactsStatus(nullptr) { } -template -UnilateralLagrangianConstraint::~UnilateralLagrangianConstraint() -{ - if(contactsStatus) - delete[] contactsStatus; -} - -template -void UnilateralLagrangianConstraint::clear(int reserve) -{ - contacts.clear(); - if (reserve) - contacts.reserve(reserve); -} - -template -void UnilateralLagrangianConstraint::addContact(SReal mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, long id, PersistentID localid) -{ - addContact(mu, norm, P, Q, contactDistance, m1, m2, - this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue()[m2], - this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue()[m1], - id, localid); -} - -template -void UnilateralLagrangianConstraint::addContact(SReal mu, Deriv norm, Real contactDistance, int m1, int m2, long id, PersistentID localid) -{ - addContact(mu, norm, - this->getMState2()->read(core::vec_id::read_access::position)->getValue()[m2], - this->getMState1()->read(core::vec_id::read_access::position)->getValue()[m1], - contactDistance, m1, m2, - this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue()[m2], - this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue()[m1], - id, localid); -} - -template -void UnilateralLagrangianConstraint::addContact(SReal mu, Deriv norm, Coord P, Coord Q, Real contactDistance, int m1, int m2, Coord /*Pfree*/, Coord /*Qfree*/, long id, PersistentID localid) -{ - contacts.resize(contacts.size() + 1); - Contact &c = contacts.back(); - - c.P = P; - c.Q = Q; - c.m1 = m1; - c.m2 = m2; - c.norm = norm; - c.t = Deriv(norm.z(), norm.x(), norm.y()); - c.s = cross(norm, c.t); - c.s = c.s / c.s.norm(); - c.t = cross((-norm), c.s); - c.mu = mu; - c.contactId = id; - c.localId = localid; - c.contactDistance = contactDistance; -} - - -template -void UnilateralLagrangianConstraint::buildConstraintMatrix(const core::ConstraintParams *, DataMatrixDeriv &c1_d, DataMatrixDeriv &c2_d, unsigned int &contactId - , const DataVecCoord &, const DataVecCoord &) -{ - assert(this->mstate1); - assert(this->mstate2); - - if (this->mstate1 == this->mstate2) - { - MatrixDeriv& c1 = *c1_d.beginEdit(); - - for (unsigned int i = 0; i < contacts.size(); i++) - { - Contact& c = contacts[i]; - - c.id = contactId++; - - MatrixDerivRowIterator c1_it = c1.writeLine(c.id); - - c1_it.addCol(c.m1, -c.norm); - c1_it.addCol(c.m2, c.norm); - - if (c.mu > 0.0) - { - c1_it = c1.writeLine(c.id + 1); - c1_it.setCol(c.m1, -c.t); - c1_it.setCol(c.m2, c.t); - - c1_it = c1.writeLine(c.id + 2); - c1_it.setCol(c.m1, -c.s); - c1_it.setCol(c.m2, c.s); - - contactId += 2; - } - } - - c1_d.endEdit(); - } - else - { - MatrixDeriv& c1 = *c1_d.beginEdit(); - MatrixDeriv& c2 = *c2_d.beginEdit(); - - for (unsigned int i = 0; i < contacts.size(); i++) - { - Contact& c = contacts[i]; - - c.id = contactId++; - - MatrixDerivRowIterator c1_it = c1.writeLine(c.id); - c1_it.addCol(c.m1, -c.norm); - - MatrixDerivRowIterator c2_it = c2.writeLine(c.id); - c2_it.addCol(c.m2, c.norm); - - if (c.mu > 0.0) - { - c1_it = c1.writeLine(c.id + 1); - c1_it.setCol(c.m1, -c.t); - - c1_it = c1.writeLine(c.id + 2); - c1_it.setCol(c.m1, -c.s); - - c2_it = c2.writeLine(c.id + 1); - c2_it.setCol(c.m2, c.t); - - c2_it = c2.writeLine(c.id + 2); - c2_it.setCol(c.m2, c.s); - - contactId += 2; - } - } - - c1_d.endEdit(); - c2_d.endEdit(); - } -} - - -template -void UnilateralLagrangianConstraint::getPositionViolation(linearalgebra::BaseVector *v) -{ - const VecCoord &PfreeVec = this->getMState2()->read(core::vec_id::read_access::freePosition)->getValue(); - const VecCoord &QfreeVec = this->getMState1()->read(core::vec_id::read_access::freePosition)->getValue(); - - Real dfree = (Real)0.0; - Real dfree_t = (Real)0.0; - Real dfree_s = (Real)0.0; - - const unsigned int cSize = contacts.size(); - - for (unsigned int i = 0; i < cSize; i++) - { - const Contact& c = contacts[i]; - - // Compute dfree, dfree_t and d_free_s - - const Coord &Pfree = PfreeVec[c.m2]; - const Coord &Qfree = QfreeVec[c.m1]; - - const Coord PPfree = Pfree - c.P; - const Coord QQfree = Qfree - c.Q; - - const Real ref_dist = PPfree.norm() + QQfree.norm(); - - dfree = dot(Pfree - Qfree, c.norm) - c.contactDistance; - const Real delta = dot(c.P - c.Q, c.norm) - c.contactDistance; - - if ((helper::rabs(delta) < 0.00001 * ref_dist) && (helper::rabs(dfree) < 0.00001 * ref_dist)) - { - dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); - dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); - } - else if (helper::rabs(delta - dfree) > 0.001 * delta) - { - const Real dt = delta / (delta - dfree); - - if (dt > 0.0 && dt < 1.0) - { - const Coord Pt = c.P * (1 - dt) + Pfree * dt; - const Coord Qt = c.Q * (1 - dt) + Qfree * dt; - const Coord PtPfree = Pfree - Pt; - const Coord QtQfree = Qfree - Qt; - - dfree_t = dot(PtPfree, c.t) - dot(QtQfree, c.t); - dfree_s = dot(PtPfree, c.s) - dot(QtQfree, c.s); - } - else if (dfree < 0.0) - { - dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); - dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); - } - else - { - dfree_t = 0; - dfree_s = 0; - } - } - else - { - dfree_t = dot(PPfree, c.t) - dot(QQfree, c.t); - dfree_s = dot(PPfree, c.s) - dot(QQfree, c.s); - } - - // Sets dfree in global violation vector - - v->set(c.id, dfree); - - c.dfree = dfree; // PJ : For isActive() method. Don't know if it's still useful. - - if (c.mu > 0.0) - { - v->set(c.id + 1, dfree_t); - v->set(c.id + 2, dfree_s); - } - } -} - - -template -void UnilateralLagrangianConstraint::getVelocityViolation(linearalgebra::BaseVector *v) -{ - auto P = this->getMState2()->readPositions(); - auto Q = this->getMState1()->readPositions(); - - const SReal dt = this->getContext()->getDt(); - const SReal invDt = SReal(1.0) / dt; - - const VecDeriv &PvfreeVec = this->getMState2()->read(core::vec_id::read_access::freeVelocity)->getValue(); - const VecDeriv &QvfreeVec = this->getMState1()->read(core::vec_id::read_access::freeVelocity)->getValue(); - - const unsigned int cSize = contacts.size(); - - for (unsigned int i = 0; i < cSize; i++) - { - const Contact& c = contacts[i]; - - const Deriv QP_invDt = (P[c.m2] - Q[c.m1])*invDt; - const Deriv QP_vfree = PvfreeVec[c.m2] - QvfreeVec[c.m1]; - const Deriv dFreeVec = QP_vfree + QP_invDt; - - v->set(c.id, dot(dFreeVec, c.norm) - c.contactDistance*invDt ); // dvfree = 1/dt * [ dot ( P - Q, n) - contactDist ] + dot(v_P - v_Q , n ) ] - - if (c.mu > 0.0) - { - v->set(c.id + 1, dot(QP_vfree, c.t)); // dfree_t - v->set(c.id + 2, dot(QP_vfree, c.s)); // dfree_s - } - } -} - - -template -void UnilateralLagrangianConstraint::getConstraintViolation(const core::ConstraintParams *cparams, linearalgebra::BaseVector *v, const DataVecCoord &, const DataVecCoord & - , const DataVecDeriv &, const DataVecDeriv &) -{ - switch (cparams->constOrder()) - { - case core::ConstraintOrder::POS_AND_VEL : - case core::ConstraintOrder::POS : - getPositionViolation(v); - break; - - case core::ConstraintOrder::ACC : - case core::ConstraintOrder::VEL : - getVelocityViolation(v); - break; - - default : - msg_error() << "UnilateralLagrangianConstraint doesn't implement " << cparams->getName() << " constraint violation\n"; - break; - } -} - - -template -void UnilateralLagrangianConstraint::getConstraintInfo(const core::ConstraintParams*, VecConstraintBlockInfo& blocks, VecPersistentID& ids, VecConstCoord& /*positions*/, VecConstDeriv& directions, VecConstArea& /*areas*/) -{ - if (contacts.empty()) return; - const bool friction = (contacts[0].mu > 0.0); /// @todo: can there be both friction-less and friction contacts in the same UnilateralLagrangianConstraint ??? - ConstraintBlockInfo info; - info.parent = this; - info.const0 = contacts[0].id; - info.nbLines = friction ? 3 : 1; - info.hasId = true; - info.offsetId = ids.size(); - info.hasDirection = true; - info.offsetDirection = directions.size(); - info.nbGroups = contacts.size(); - - for (unsigned int i=0; i void UnilateralLagrangianConstraint::getConstraintResolution(const core::ConstraintParams *, std::vector& resTab, unsigned int& offset) { - if(contactsStatus) + if(this->contactsStatus) { - delete[] contactsStatus; - contactsStatus = nullptr; + delete[] this->contactsStatus; + this->contactsStatus = nullptr; } - if (contacts.size() > 0) + if (this->contacts.size() > 0) { - contactsStatus = new bool[contacts.size()]; - memset(contactsStatus, 0, sizeof(bool)*contacts.size()); + this->contactsStatus = new bool[this->contacts.size()]; + memset(this->contactsStatus, 0, sizeof(bool)*this->contacts.size()); } - for(unsigned int i=0; icontacts.size(); i++) { - Contact& c = contacts[i]; - if(c.mu > 0.0) + Contact& c = this->contacts[i]; + if(c.parameters.hasTangentialComponent()) { - UnilateralConstraintResolutionWithFriction* ucrwf = new UnilateralConstraintResolutionWithFriction(c.mu, nullptr, &contactsStatus[i]); - ucrwf->setTolerance(customTolerance); + UnilateralConstraintResolutionWithFriction* ucrwf = new UnilateralConstraintResolutionWithFriction(c.parameters.mu, nullptr, &this->contactsStatus[i]); + ucrwf->setTolerance(this->customTolerance); resTab[offset] = ucrwf; // TODO : cette méthode de stockage des forces peu mal fonctionner avec 2 threads quand on utilise l'haptique @@ -374,48 +65,6 @@ void UnilateralLagrangianConstraint::getConstraintResolution(const co else resTab[offset++] = new UnilateralConstraintResolution(); } -} - -template -bool UnilateralLagrangianConstraint::isActive() const -{ - for(unsigned int i = 0; i < contacts.size(); i++) - if(contacts[i].dfree < 0) - return true; - - return false; -} - -template -void UnilateralLagrangianConstraint::draw(const core::visual::VisualParams* vparams) -{ - if (!vparams->displayFlags().getShowInteractionForceFields()) return; - - const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); - vparams->drawTool()->disableLighting(); - - std::vector redVertices; - std::vector otherVertices; - std::vector otherColors; - - for (unsigned int i=0; idrawTool()->drawLines(otherVertices, 3, otherColors); - - - - } } //namespace sofa::component::constraint::lagrangian::model diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/config.h.in b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/config.h.in index 06c71b9df5f..8d0b5acc531 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/config.h.in +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/config.h.in @@ -44,4 +44,14 @@ namespace sofa::component::constraint::lagrangian::model SOFA_ATTRIBUTE_DEPRECATED( \ "v24.06", "v24.12", \ "Data renamed according to the guidelines") +#endif + + +#ifdef SOFA_BUILD_SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL +#define SOFA_ATTRIBUTE_DEPRECATED__BILATERALREMOVEUNUSEDTOLERANCE() +#else +#define SOFA_ATTRIBUTE_DEPRECATED__BILATERALREMOVEUNUSEDTOLERANCE() \ + SOFA_ATTRIBUTE_DEPRECATED( \ + "v25.06", "v25.12", \ + "Data \'d_numericalTolerance\' has been removed since it was actually not taken into account") #endif \ No newline at end of file diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/init.cpp b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/init.cpp index de09f9f65d9..ba40a5df106 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/init.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/init.cpp @@ -26,6 +26,7 @@ namespace sofa::component::constraint::lagrangian::model { +extern void registerAugmentedLagrangianConstraint(sofa::core::ObjectFactory* factory); extern void registerBilateralLagrangianConstraint(sofa::core::ObjectFactory* factory); extern void registerFixedLagrangianConstraint(sofa::core::ObjectFactory* factory); extern void registerSlidingLagrangianConstraint(sofa::core::ObjectFactory* factory); @@ -57,6 +58,7 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { + registerAugmentedLagrangianConstraint(factory); registerBilateralLagrangianConstraint(factory); registerFixedLagrangianConstraint(factory); registerSlidingLagrangianConstraint(factory); diff --git a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h index cd3c770fd97..f7d35b82e92 100644 --- a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h +++ b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include @@ -71,49 +71,49 @@ class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_SOLVER_API GenericConstraintSolver : Data< ResolutionMethod > d_resolutionMethod; ///< Method used to solve the constraint problem, among: "ProjectedGaussSeidel", "UnbuiltGaussSeidel" or "for NonsmoothNonlinearConjugateGradient" SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData maxIt; + sofa::core::objectmodel::lifecycle::RenamedData maxIt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData tolerance; + sofa::core::objectmodel::lifecycle::RenamedData tolerance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData sor; + sofa::core::objectmodel::lifecycle::RenamedData sor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData scaleTolerance; + sofa::core::objectmodel::lifecycle::RenamedData scaleTolerance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData allVerified; + sofa::core::objectmodel::lifecycle::RenamedData allVerified; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData computeGraphs; + sofa::core::objectmodel::lifecycle::RenamedData computeGraphs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData > > graphErrors; + sofa::core::objectmodel::lifecycle::RenamedData > > graphErrors; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData > > graphConstraints; + sofa::core::objectmodel::lifecycle::RenamedData > > graphConstraints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData > > graphForces; + sofa::core::objectmodel::lifecycle::RenamedData > > graphForces; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData > > graphViolations; + sofa::core::objectmodel::lifecycle::RenamedData > > graphViolations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData currentNumConstraints; + sofa::core::objectmodel::lifecycle::RenamedData currentNumConstraints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData currentNumConstraintGroups; + sofa::core::objectmodel::lifecycle::RenamedData currentNumConstraintGroups; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData currentIterations; + sofa::core::objectmodel::lifecycle::RenamedData currentIterations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData currentError; + sofa::core::objectmodel::lifecycle::RenamedData currentError; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData reverseAccumulateOrder; + sofa::core::objectmodel::lifecycle::RenamedData reverseAccumulateOrder; Data d_maxIt; ///< maximal number of iterations of the Gauss-Seidel algorithm Data d_tolerance; ///< residual error threshold for termination of the Gauss-Seidel algorithm diff --git a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/LCPConstraintSolver.h b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/LCPConstraintSolver.h index d4ba0ee2681..80603d91185 100644 --- a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/LCPConstraintSolver.h +++ b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/LCPConstraintSolver.h @@ -35,7 +35,7 @@ #include #include -#include +#include namespace sofa::component::constraint::lagrangian::solver { @@ -75,61 +75,61 @@ class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_SOLVER_API LCPConstraintSolver : publ void draw(const core::visual::VisualParams* vparams) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData displayDebug; + sofa::core::objectmodel::lifecycle::RenamedData displayDebug; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData initial_guess; + sofa::core::objectmodel::lifecycle::RenamedData initial_guess; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData build_lcp; + sofa::core::objectmodel::lifecycle::RenamedData build_lcp; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData tol; + sofa::core::objectmodel::lifecycle::RenamedData tol; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> maxIt; + sofa::core::objectmodel::lifecycle::RenamedData< int> maxIt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData mu; + sofa::core::objectmodel::lifecycle::RenamedData mu; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData minW; + sofa::core::objectmodel::lifecycle::RenamedData minW; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData maxF; + sofa::core::objectmodel::lifecycle::RenamedData maxF; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData multi_grid; + sofa::core::objectmodel::lifecycle::RenamedData multi_grid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> multi_grid_levels; + sofa::core::objectmodel::lifecycle::RenamedData< int> multi_grid_levels; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> merge_method; + sofa::core::objectmodel::lifecycle::RenamedData< int> merge_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> merge_spatial_step; + sofa::core::objectmodel::lifecycle::RenamedData< int> merge_spatial_step; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> merge_local_levels; + sofa::core::objectmodel::lifecycle::RenamedData< int> merge_local_levels; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData < std::set > constraintGroups; + sofa::core::objectmodel::lifecycle::RenamedData < std::set > constraintGroups; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData > > f_graph; + sofa::core::objectmodel::lifecycle::RenamedData > > f_graph; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData< int> showLevels; + sofa::core::objectmodel::lifecycle::RenamedData< int> showLevels; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData showCellWidth; + sofa::core::objectmodel::lifecycle::RenamedData showCellWidth; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData showTranslation; + sofa::core::objectmodel::lifecycle::RenamedData showTranslation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() - sofa::core::objectmodel::RenamedData showLevelTranslation; + sofa::core::objectmodel::lifecycle::RenamedData showLevelTranslation; Data d_displayDebug; ///< Display debug information. diff --git a/Sofa/Component/Constraint/Lagrangian/src/sofa/component/constraint/lagrangian/init.cpp b/Sofa/Component/Constraint/Lagrangian/src/sofa/component/constraint/lagrangian/init.cpp index b0f8cbd6009..e7adc9e8fe9 100644 --- a/Sofa/Component/Constraint/Lagrangian/src/sofa/component/constraint/lagrangian/init.cpp +++ b/Sofa/Component/Constraint/Lagrangian/src/sofa/component/constraint/lagrangian/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::constraint::lagrangian { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Constraint.Lagrangian.Correction"); - factory->registerObjectsFromPlugin("Sofa.Component.Constraint.Lagrangian.Model"); - factory->registerObjectsFromPlugin("Sofa.Component.Constraint.Lagrangian.Solver"); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint.Lagrangian.Correction); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint.Lagrangian.Model); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint.Lagrangian.Solver); } void init() diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/AffineMovementProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/AffineMovementProjectiveConstraint.h index a35f21fd8f9..6b8ee71a66e 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/AffineMovementProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/AffineMovementProjectiveConstraint.h @@ -34,7 +34,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -82,28 +82,28 @@ class AffineMovementProjectiveConstraint : public core::behavior::ProjectiveCons public : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > m_meshIndices; + sofa::core::objectmodel::lifecycle::RenamedData > m_meshIndices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > m_indices; + sofa::core::objectmodel::lifecycle::RenamedData > m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_beginConstraintTime; + sofa::core::objectmodel::lifecycle::RenamedData m_beginConstraintTime; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_endConstraintTime; + sofa::core::objectmodel::lifecycle::RenamedData m_endConstraintTime; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_rotation; + sofa::core::objectmodel::lifecycle::RenamedData m_rotation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_quaternion; + sofa::core::objectmodel::lifecycle::RenamedData m_quaternion; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_translation; + sofa::core::objectmodel::lifecycle::RenamedData m_translation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_drawConstrainedPoints; + sofa::core::objectmodel::lifecycle::RenamedData m_drawConstrainedPoints; /// indices of the DOFs of the mesh diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/DirectionProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/DirectionProjectiveConstraint.h index 872ae61a5af..a4d357e85ae 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/DirectionProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/DirectionProjectiveConstraint.h @@ -36,7 +36,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -85,13 +85,13 @@ class DirectionProjectiveConstraint : public core::behavior::ProjectiveConstrain public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > f_indices; + sofa::core::objectmodel::lifecycle::RenamedData > f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_drawSize; + sofa::core::objectmodel::lifecycle::RenamedData f_drawSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedDataf_direction; + sofa::core::objectmodel::lifecycle::RenamedDataf_direction; IndexSubsetData d_indices; ///< Indices the particles to project Data d_drawSize; ///< Size of the rendered particles (0 -> point based rendering, >0 -> radius of spheres) diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedRotationProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedRotationProjectiveConstraint.h index 827c65ac1fd..16f09ef7e35 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedRotationProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedRotationProjectiveConstraint.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -68,13 +68,13 @@ class FixedRotationProjectiveConstraint : public core::behavior::ProjectiveConst protected : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< bool > FixedXRotation; + sofa::core::objectmodel::lifecycle::RenamedData< bool > FixedXRotation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< bool > FixedYRotation; + sofa::core::objectmodel::lifecycle::RenamedData< bool > FixedYRotation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< bool > FixedZRotation; + sofa::core::objectmodel::lifecycle::RenamedData< bool > FixedZRotation; Data< bool > d_fixedXRotation; ///< Prevent Rotation around X axis Data< bool > d_fixedYRotation; ///< Prevent Rotation around Y axis diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedTranslationProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedTranslationProjectiveConstraint.h index 2176f0d9d9c..ff9eae16e54 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedTranslationProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/FixedTranslationProjectiveConstraint.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -65,16 +65,16 @@ class FixedTranslationProjectiveConstraint : public core::behavior::ProjectiveCo public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector > f_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_fixAll; + sofa::core::objectmodel::lifecycle::RenamedData f_fixAll; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData _drawSize; + sofa::core::objectmodel::lifecycle::RenamedData _drawSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector > f_coordinates; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > f_coordinates; SetIndex d_indices; ///< Indices of the fixed points Data d_fixAll; ///< filter all the DOF to implement a fixed object diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/HermiteSplineProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/HermiteSplineProjectiveConstraint.h index 6a3f327bc29..3e5e08fcefd 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/HermiteSplineProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/HermiteSplineProjectiveConstraint.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -65,31 +65,31 @@ class HermiteSplineProjectiveConstraint : public core::behavior::ProjectiveConst public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector > m_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_tBegin; + sofa::core::objectmodel::lifecycle::RenamedData m_tBegin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_tEnd; + sofa::core::objectmodel::lifecycle::RenamedData m_tEnd; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_x0; + sofa::core::objectmodel::lifecycle::RenamedData m_x0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_dx0; + sofa::core::objectmodel::lifecycle::RenamedData m_dx0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_x1; + sofa::core::objectmodel::lifecycle::RenamedData m_x1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_dx1; + sofa::core::objectmodel::lifecycle::RenamedData m_dx1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_sx0; + sofa::core::objectmodel::lifecycle::RenamedData m_sx0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_sx1; + sofa::core::objectmodel::lifecycle::RenamedData m_sx1; ///indices of the DOFs constraints SetIndex d_indices; diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LineProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LineProjectiveConstraint.h index 0475832b1bb..3cdcedd43f0 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LineProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LineProjectiveConstraint.h @@ -35,7 +35,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -86,16 +86,16 @@ class LineProjectiveConstraint : public core::behavior::ProjectiveConstraintSet< public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector< sofa::Index > > f_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector< sofa::Index > > f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_drawSize; + sofa::core::objectmodel::lifecycle::RenamedData f_drawSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_origin; + sofa::core::objectmodel::lifecycle::RenamedData f_origin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_direction; + sofa::core::objectmodel::lifecycle::RenamedData f_direction; IndexSubsetData d_indices; ///< the particles to project Data d_drawSize; ///< Size of the rendered particles (0 -> point based rendering, >0 -> radius of spheres) diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearMovementProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearMovementProjectiveConstraint.h index c6434edab57..7a86baae012 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearMovementProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearMovementProjectiveConstraint.h @@ -35,7 +35,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -78,16 +78,16 @@ class LinearMovementProjectiveConstraint : public core::behavior::ProjectiveCons public : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector< sofa::Index> > m_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector< sofa::Index> > m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > m_keyTimes; + sofa::core::objectmodel::lifecycle::RenamedData > m_keyTimes; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_keyMovements; + sofa::core::objectmodel::lifecycle::RenamedData m_keyMovements; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData showMovement; + sofa::core::objectmodel::lifecycle::RenamedData showMovement; /// indices of the DOFs the constraint is applied to SetIndex d_indices; diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.h index 6e3a71e9329..c75c97db7f1 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.h @@ -71,14 +71,17 @@ public : /// the coordinates on which to apply velocities SetIndex d_coordinates; + /// If set to true then the last velocity will still be applied after all the key events + Data d_continueAfterEnd; + /// the key times surrounding the current simulation time (for interpolation) - Real prevT, nextT; + Real m_prevT, m_nextT; ///the velocities corresponding to the surrounding key times - Deriv prevV, nextV; + Deriv m_prevV, m_nextV; ///position at the initial step for constrained DOFs position - VecCoord x0; + VecCoord m_x0; ///position at the previous step for constrained DOFs position - VecCoord xP; + VecCoord m_xP; /// Link to be set to the topology container in the component graph. SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; @@ -109,18 +112,24 @@ public : void projectPosition(const core::MechanicalParams* mparams, DataVecCoord& xData) override; void projectJacobianMatrix(const core::MechanicalParams* mparams, DataMatrixDeriv& cData) override; + void applyConstraint(const core::MechanicalParams* mparams, linearalgebra::BaseVector* vector, const sofa::core::behavior::MultiMatrixAccessor* matrix) override; + void applyConstraint(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix) override; + + void projectMatrix( sofa::linearalgebra::BaseMatrix* /*M*/, unsigned /*offset*/ ) override; + + void applyConstraint(sofa::core::behavior::ZeroDirichletCondition* matrix) override; + void draw(const core::visual::VisualParams* vparams) override; private: - - /// to keep the time corresponding to the key times - Real currentTime; + /// Check if the constraint is still active regarding the current time and the continueAfterEnd data + bool isConstraintActive() const; /// to know if we found the key times - bool finished; + bool m_finished; /// find previous and next time keys - void findKeyTimes(); + bool findKeyTimes(); }; #if !defined(SOFA_COMPONENT_PROJECTIVECONSTRAINTSET_LINEARVELOCITYPROJECTIVECONSTRAINT_CPP) diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.inl b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.inl index 80ff4e51937..c1cdacc363a 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.inl +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/LinearVelocityProjectiveConstraint.inl @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include @@ -40,8 +42,9 @@ LinearVelocityProjectiveConstraint::LinearVelocityProjectiveConstrai , d_keyTimes( initData(&d_keyTimes,"keyTimes","key times for the movements") ) , d_keyVelocities( initData(&d_keyVelocities,"velocities","velocities corresponding to the key times") ) , d_coordinates( initData(&d_coordinates, "coordinates", "coordinates on which to apply velocities") ) + , d_continueAfterEnd( initData(&d_continueAfterEnd, false, "continueAfterEnd", "If set to true then the last velocity will still be applied after all the key events") ) , l_topology(initLink("topology", "link to the topology container")) - , finished(false) + , m_finished(false) { d_indices.beginEdit()->push_back(0); d_indices.endEdit(); @@ -125,39 +128,36 @@ void LinearVelocityProjectiveConstraint::init() msg_info() << "No topology component found at path: " << l_topology.getLinkedPath() << ", nor in current context: " << this->getContext()->name; } - x0.resize(0); - xP.resize(0); - nextV = prevV = Deriv(); + m_x0.resize(0); + m_xP.resize(0); + m_nextV = m_prevV = Deriv(); - currentTime = -1.0; - finished = false; + m_finished = false; } template void LinearVelocityProjectiveConstraint::reset() { - nextT = prevT = 0.0; - nextV = prevV = Deriv(); + m_nextT = m_prevT = 0.0; + m_nextV = m_prevV = Deriv(); - currentTime = -1.0; - finished = false; + m_finished = false; } template void LinearVelocityProjectiveConstraint::projectResponse(const core::MechanicalParams* /*mparams*/, DataVecDeriv& resData) { - helper::WriteAccessor res = resData; - VecDeriv& dx = res.wref(); - - Real cT = (Real) this->getContext()->getTime(); - if ((cT != currentTime) || !finished) + if(!m_finished) { - findKeyTimes(); + m_finished = findKeyTimes(); } - if (finished && nextT != prevT) + if (isConstraintActive()) { + helper::WriteAccessor res = resData; + VecDeriv& dx = res.wref(); + const SetIndexArray & indices = d_indices.getValue(); //set the motion to the Dofs @@ -172,18 +172,24 @@ void LinearVelocityProjectiveConstraint::projectResponse(const core: template void LinearVelocityProjectiveConstraint::projectVelocity(const core::MechanicalParams* /*mparams*/, DataVecDeriv& vData) { - helper::WriteAccessor dx = vData; - Real cT = (Real) this->getContext()->getTime(); - - if ((cT != currentTime) || !finished) + if(!m_finished) { - findKeyTimes(); + m_finished = findKeyTimes(); } - if (finished && nextT != prevT) + if (isConstraintActive()) { + helper::WriteAccessor dx = vData; + Real cT = (Real) this->getContext()->getTime(); + //if we found 2 keyTimes, we have to interpolate a velocity (linear interpolation) - Deriv v = ((nextV - prevV)*((cT - prevT)/(nextT - prevT))) + prevV; + Deriv v = ((m_nextV - m_prevV)*((cT - m_prevT)/(m_nextT - m_prevT))) + m_prevV; + + //If we finished the key times but continue after end is on + if(m_finished) + { + v = m_prevV; + } const SetIndexArray & indices = d_indices.getValue(); const SetIndexArray & coordinates = d_coordinates.getValue(); @@ -213,36 +219,40 @@ void LinearVelocityProjectiveConstraint::projectVelocity(const core: template void LinearVelocityProjectiveConstraint::projectPosition(const core::MechanicalParams* /*mparams*/, DataVecCoord& xData) { + helper::WriteAccessor x = xData; //initialize initial Dofs positions, if it's not done - if (x0.size() == 0) + if (m_x0.size() == 0) { const SetIndexArray & indices = d_indices.getValue(); - x0.resize( x.size() ); - xP.resize( x.size() ); + m_x0.resize( x.size() ); + m_xP.resize( x.size() ); for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it) { - x0[*it] = x[*it]; - xP[*it] = x0[*it]; + m_x0[*it] = x[*it]; + m_xP[*it] = m_x0[*it]; } } - Real cT = (Real) this->getContext()->getTime(); - if ((cT != currentTime) || !finished) + if(!m_finished) { - findKeyTimes(); + m_finished = findKeyTimes(); } - - Real dTsimu = (Real) this->getContext()->getDt(); - - - if(finished) + if(isConstraintActive()) { - Real dt = (cT - prevT) / (nextT - prevT); - Deriv m = (nextV-prevV)*dt + prevV; + const Real cT = (Real) this->getContext()->getTime(); + const Real dTsimu = (Real) this->getContext()->getDt(); + const Real dt = (cT - m_prevT) / (m_nextT - m_prevT); + Deriv m = (m_nextV-m_prevV)*dt + m_prevV; + + //If we finished the key times but continue after end is on + if(m_finished) + { + m = m_prevV; + } const SetIndexArray & indices = d_indices.getValue(); const SetIndexArray & coordinates = d_coordinates.getValue(); @@ -252,8 +262,8 @@ void LinearVelocityProjectiveConstraint::projectPosition(const core: //set the motion to the Dofs for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it) { - x[*it] = xP[*it] + m*dTsimu; - xP[*it] = x[*it]; + x[*it] = m_xP[*it] + m*dTsimu; + m_xP[*it] = x[*it]; } } else @@ -262,8 +272,8 @@ void LinearVelocityProjectiveConstraint::projectPosition(const core: { for(SetIndexArray::const_iterator itInd = coordinates.begin(); itInd != coordinates.end(); ++itInd) { - x[*it][*itInd] = xP[*it][*itInd] + m[*itInd]*dTsimu; - xP[*it] = x[*it]; + x[*it][*itInd] = m_xP[*it][*itInd] + m[*itInd]*dTsimu; + m_xP[*it] = x[*it]; } } } @@ -271,38 +281,51 @@ void LinearVelocityProjectiveConstraint::projectPosition(const core: } template -void LinearVelocityProjectiveConstraint::findKeyTimes() +bool LinearVelocityProjectiveConstraint::isConstraintActive() const +{ + return (!m_finished || d_continueAfterEnd.getValue()) && (m_nextT != m_prevT); +} + +template +bool LinearVelocityProjectiveConstraint::findKeyTimes() { - Real cT = (Real) this->getContext()->getTime(); - finished = false; + const Real cT = (Real) this->getContext()->getTime(); + + if(cT > *d_keyTimes.getValue().rbegin()) + { + m_prevV = m_nextV; + m_nextT = INFINITY; + return true; + } if(d_keyTimes.getValue().size() != 0 && cT >= *d_keyTimes.getValue().begin() && cT <= *d_keyTimes.getValue().rbegin()) { - nextT = *d_keyTimes.getValue().begin(); - prevT = nextT; + m_nextT = *d_keyTimes.getValue().begin(); + m_prevT = m_nextT; typename type::vector::const_iterator it_t = d_keyTimes.getValue().begin(); typename VecDeriv::const_iterator it_v = d_keyVelocities.getValue().begin(); //WARNING : we consider that the key-events are in chronological order //here we search between which keyTimes we are, to know which are the motion to interpolate - while( it_t != d_keyTimes.getValue().end() && !finished) + while( it_t != d_keyTimes.getValue().end()) { if( *it_t <= cT) { - prevT = *it_t; - prevV = *it_v; + m_prevT = *it_t; + m_prevV = *it_v; } else { - nextT = *it_t; - nextV = *it_v; - finished = true; + m_nextT = *it_t; + m_nextV = *it_v; + return false; } ++it_t; ++it_v; } } + return false; }// LinearVelocityProjectiveConstraint::findKeyTimes template @@ -311,6 +334,97 @@ void LinearVelocityProjectiveConstraint::projectJacobianMatrix(const } +template +void LinearVelocityProjectiveConstraint::applyConstraint(const core::MechanicalParams* mparams, linearalgebra::BaseVector* vector, const sofa::core::behavior::MultiMatrixAccessor* matrix) +{ + SOFA_UNUSED(mparams); + + if(isConstraintActive()) + { + const int o = matrix->getGlobalOffset(this->mstate.get()); + if (o >= 0) + { + unsigned int offset = (unsigned int)o; + constexpr unsigned int N = Deriv::size(); + + const SetIndexArray& indices = this->d_indices.getValue(); + for (const unsigned int index : indices) + { + for (unsigned int c = 0; c < N; ++c) + { + vector->clear(offset + N * index + c); + } + } + } + } +} + +template +void LinearVelocityProjectiveConstraint::applyConstraint(const core::MechanicalParams* mparams, const sofa::core::behavior::MultiMatrixAccessor* matrix) +{ + SOFA_UNUSED(mparams); + if(isConstraintActive()) + { + if (const core::behavior::MultiMatrixAccessor::MatrixRef r = + matrix->getMatrix(this->mstate.get())) + { + constexpr unsigned int N = Deriv::size(); + const SetIndexArray& indices = this->d_indices.getValue(); + + for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it) + { + // Reset Fixed Row and Col + for (unsigned int c = 0; c < N; ++c) + { + r.matrix->clearRowCol(r.offset + N * (*it) + c); + } + // Set Fixed Vertex + for (unsigned int c = 0; c < N; ++c) + { + r.matrix->set(r.offset + N * (*it) + c, r.offset + N * (*it) + c, 1.0); + } + } + } + } +} + +template +void LinearVelocityProjectiveConstraint::projectMatrix( sofa::linearalgebra::BaseMatrix* M, unsigned offset ) +{ + static const unsigned blockSize = DataTypes::deriv_total_size; + + if(isConstraintActive()) + { + const SetIndexArray & indices = this->d_indices.getValue(); + for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it) + { + for (unsigned int c = 0; c < blockSize; ++c) + { + M->clearRowCol( offset + (*it) * blockSize + c); + } + } + } +} + +template +void LinearVelocityProjectiveConstraint::applyConstraint( + sofa::core::behavior::ZeroDirichletCondition* matrix) +{ + static constexpr unsigned int N = Deriv::size(); + if(isConstraintActive()) + { + const SetIndexArray& indices = this->d_indices.getValue(); + + for (const auto index : indices) + { + for (unsigned int c = 0; c < N; ++c) + { + matrix->discardRowCol(N * index + c, N * index + c); + } + } + } +} + //display the path the constrained dofs will go through template void LinearVelocityProjectiveConstraint::draw(const core::visual::VisualParams* vparams) @@ -328,8 +442,8 @@ void LinearVelocityProjectiveConstraint::draw(const core::visual::Vi { for(const auto index : indices) { - const auto p0 = x0[index]+keyVelocities[i]; - const auto p1 = x0[index]+keyVelocities[i+1]; + const auto p0 = m_x0[index]+keyVelocities[i]; + const auto p1 = m_x0[index]+keyVelocities[i+1]; const typename DataTypes::CPos& cpos0 = DataTypes::getCPos(p0); const typename DataTypes::CPos& cpos1 = DataTypes::getCPos(p1); diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/OscillatorProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/OscillatorProjectiveConstraint.h index 5114ce41668..124e97dbcec 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/OscillatorProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/OscillatorProjectiveConstraint.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -83,7 +83,7 @@ class OscillatorProjectiveConstraint : public core::behavior::ProjectiveConstrai }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< type::vector< Oscillator > > constraints; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector< Oscillator > > constraints; Data< type::vector< Oscillator > > d_constraints; ///< Define a sequence of oscillating particules: [index, Mean(x,y,z), amplitude(x,y,z), pulsation, phase] diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/ParabolicProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/ParabolicProjectiveConstraint.h index 8c079c99960..6ed3727da2e 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/ParabolicProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/ParabolicProjectiveConstraint.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -60,22 +60,22 @@ class ParabolicProjectiveConstraint : public core::behavior::ProjectiveConstrain protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector > m_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_P1; + sofa::core::objectmodel::lifecycle::RenamedData m_P1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_P2; + sofa::core::objectmodel::lifecycle::RenamedData m_P2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_P3; + sofa::core::objectmodel::lifecycle::RenamedData m_P3; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_tBegin; + sofa::core::objectmodel::lifecycle::RenamedData m_tBegin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_tEnd; + sofa::core::objectmodel::lifecycle::RenamedData m_tEnd; ///indices of the DOFs constraints SetIndex d_indices; diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PartialLinearMovementProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PartialLinearMovementProjectiveConstraint.h index a2eb576ae4e..cb765b14317 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PartialLinearMovementProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PartialLinearMovementProjectiveConstraint.h @@ -35,7 +35,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -77,40 +77,40 @@ class PartialLinearMovementProjectiveConstraint : public core::behavior::Project public : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > m_indices; + sofa::core::objectmodel::lifecycle::RenamedData > m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData >m_keyTimes; + sofa::core::objectmodel::lifecycle::RenamedData >m_keyTimes; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData m_keyMovements; + sofa::core::objectmodel::lifecycle::RenamedData m_keyMovements; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< bool > showMovement; + sofa::core::objectmodel::lifecycle::RenamedData< bool > showMovement; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData linearMovementBetweenNodesInIndices; + sofa::core::objectmodel::lifecycle::RenamedData linearMovementBetweenNodesInIndices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData mainIndice; + sofa::core::objectmodel::lifecycle::RenamedData mainIndice; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData minDepIndice; + sofa::core::objectmodel::lifecycle::RenamedData minDepIndice; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData maxDepIndice; + sofa::core::objectmodel::lifecycle::RenamedData maxDepIndice; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > m_imposedDisplacmentOnMacroNodes; + sofa::core::objectmodel::lifecycle::RenamedData > m_imposedDisplacmentOnMacroNodes; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData X0; + sofa::core::objectmodel::lifecycle::RenamedData X0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData Y0; + sofa::core::objectmodel::lifecycle::RenamedData Y0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData Z0; + sofa::core::objectmodel::lifecycle::RenamedData Z0; /// indices of the DOFs the constraint is applied to @@ -146,7 +146,7 @@ public : typedef sofa::type::fixed_array VecBool; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData movedDirections; + sofa::core::objectmodel::lifecycle::RenamedData movedDirections; core::objectmodel::Data d_movedDirections; ///< Defines the directions in which the particles are moved: true (or 1) for fixed, false (or 0) for free diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PlaneProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PlaneProjectiveConstraint.h index e7311abd86a..740ef0e65c5 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PlaneProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PlaneProjectiveConstraint.h @@ -35,7 +35,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -85,16 +85,16 @@ class PlaneProjectiveConstraint : public core::behavior::ProjectiveConstraintSet public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< sofa::type::vector< sofa::Index > > f_indices; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector< sofa::Index > > f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_origin; + sofa::core::objectmodel::lifecycle::RenamedData f_origin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_normal; + sofa::core::objectmodel::lifecycle::RenamedData f_normal; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_drawSize; + sofa::core::objectmodel::lifecycle::RenamedData f_drawSize; IndexSubsetData d_indices; ///< the particles to project Data d_origin; ///< A point in the plane diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PointProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PointProjectiveConstraint.h index a843bc0f1fa..3289f2a4762 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PointProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PointProjectiveConstraint.h @@ -33,7 +33,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -79,16 +79,16 @@ class PointProjectiveConstraint : public core::behavior::ProjectiveConstraintSet public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData> f_indices; + sofa::core::objectmodel::lifecycle::RenamedData> f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_point; + sofa::core::objectmodel::lifecycle::RenamedData f_point; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_fixAll; + sofa::core::objectmodel::lifecycle::RenamedData f_fixAll; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData f_drawSize; + sofa::core::objectmodel::lifecycle::RenamedData f_drawSize; SetIndex d_indices; ///< the indices of the points to project to the target diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PositionBasedDynamicsProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PositionBasedDynamicsProjectiveConstraint.h index 7f350a7c256..302f762a888 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PositionBasedDynamicsProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/PositionBasedDynamicsProjectiveConstraint.h @@ -33,7 +33,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -75,16 +75,16 @@ class PositionBasedDynamicsProjectiveConstraint : public core::behavior::Project public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData stiffness; + sofa::core::objectmodel::lifecycle::RenamedData stiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< VecCoord > position; + sofa::core::objectmodel::lifecycle::RenamedData< VecCoord > position; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< VecDeriv > velocity; + sofa::core::objectmodel::lifecycle::RenamedData< VecDeriv > velocity; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData< VecCoord > old_position; + sofa::core::objectmodel::lifecycle::RenamedData< VecCoord > old_position; Data< Real > d_stiffness; ///< Blending between current pos and target pos. Data< VecCoord > d_position; ///< Target positions. diff --git a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/SkeletalMotionProjectiveConstraint.h b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/SkeletalMotionProjectiveConstraint.h index 61ed359d467..f214bcbf850 100644 --- a/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/SkeletalMotionProjectiveConstraint.h +++ b/Sofa/Component/Constraint/Projective/src/sofa/component/constraint/projective/SkeletalMotionProjectiveConstraint.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::constraint::projective { @@ -106,16 +106,16 @@ class SkeletalMotionProjectiveConstraint : public core::behavior::ProjectiveCons protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > > skeletonJoints; + sofa::core::objectmodel::lifecycle::RenamedData > > skeletonJoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData > skeletonBones; + sofa::core::objectmodel::lifecycle::RenamedData > skeletonBones; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData animationSpeed; + sofa::core::objectmodel::lifecycle::RenamedData animationSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_PROJECTIVE() - sofa::core::objectmodel::RenamedData active; + sofa::core::objectmodel::lifecycle::RenamedData active; // every nodes needed in the animation chain diff --git a/Sofa/Component/Constraint/Projective/tests/AffineMovementProjectiveConstraint_test.cpp b/Sofa/Component/Constraint/Projective/tests/AffineMovementProjectiveConstraint_test.cpp index d32ea2d552f..4b4f258cb12 100644 --- a/Sofa/Component/Constraint/Projective/tests/AffineMovementProjectiveConstraint_test.cpp +++ b/Sofa/Component/Constraint/Projective/tests/AffineMovementProjectiveConstraint_test.cpp @@ -70,7 +70,7 @@ struct AffineMovementProjectiveConstraint_test : public BaseSimulationTest, Nume sofa::helper::RandomGenerator randomGenerator; // Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); diff --git a/Sofa/Component/Constraint/Projective/tests/DirectionProjectiveConstraint_test.cpp b/Sofa/Component/Constraint/Projective/tests/DirectionProjectiveConstraint_test.cpp index 39e6f6b3ee3..d599139cb25 100644 --- a/Sofa/Component/Constraint/Projective/tests/DirectionProjectiveConstraint_test.cpp +++ b/Sofa/Component/Constraint/Projective/tests/DirectionProjectiveConstraint_test.cpp @@ -69,7 +69,7 @@ struct DirectionProjectiveConstraint_test : public BaseSimulationTest, NumericTe typename MechanicalObject::SPtr dofs; /// Create the context for the tests. - void SetUp() override + void doSetUp() override { //Init simulation = sofa::simulation::getSimulation(); @@ -219,7 +219,7 @@ struct DirectionProjectiveConstraint_test : public BaseSimulationTest, NumericTe return succeed; } - void TearDown() override + void doTearDown() override { if (root!=nullptr) sofa::simulation::node::unload(root); diff --git a/Sofa/Component/Constraint/Projective/tests/FixedProjectiveConstraint_test.cpp b/Sofa/Component/Constraint/Projective/tests/FixedProjectiveConstraint_test.cpp index adee116e4ec..638b23878cc 100644 --- a/Sofa/Component/Constraint/Projective/tests/FixedProjectiveConstraint_test.cpp +++ b/Sofa/Component/Constraint/Projective/tests/FixedProjectiveConstraint_test.cpp @@ -81,9 +81,9 @@ struct FixedProjectiveConstraint_test : public BaseTest const simulation::Node::SPtr root = simulation->createNewGraph("root"); root->setGravity( type::Vec3(0,0,0) ); - simpleapi::createObject(root , "RequiredPlugin", {{"name", "Sofa.Component.LinearSolver.Direct"}}) ; - simpleapi::createObject(root , "RequiredPlugin", {{"name", "Sofa.Component.ODESolver.Forward"}}) ; - simpleapi::createObject(root , "RequiredPlugin", {{"name", "Sofa.Component.ODESolver.Backward"}}) ; + simpleapi::createObject(root , "RequiredPlugin", {{"name", Sofa.Component.LinearSolver.Direct}}) ; + simpleapi::createObject(root , "RequiredPlugin", {{"name", Sofa.Component.ODESolver.Forward}}) ; + simpleapi::createObject(root , "RequiredPlugin", {{"name", Sofa.Component.ODESolver.Backward}}) ; simulation::Node::SPtr node = createEulerSolverNode(root,"test", integrationScheme); diff --git a/Sofa/Component/Constraint/Projective/tests/LineProjectiveConstraint_test.cpp b/Sofa/Component/Constraint/Projective/tests/LineProjectiveConstraint_test.cpp index 37f7d55f030..07e2dc61dc7 100644 --- a/Sofa/Component/Constraint/Projective/tests/LineProjectiveConstraint_test.cpp +++ b/Sofa/Component/Constraint/Projective/tests/LineProjectiveConstraint_test.cpp @@ -68,7 +68,7 @@ struct LineProjectiveConstraint_test : public BaseSimulationTest, NumericTest #include +#include namespace sofa::component::constraint { @@ -54,8 +55,8 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Constraint.Lagrangian"); - factory->registerObjectsFromPlugin("Sofa.Component.Constraint.Projective"); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint.Lagrangian); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint.Projective); } void init() diff --git a/Sofa/Component/Controller/src/sofa/component/controller/Controller.h b/Sofa/Component/Controller/src/sofa/component/controller/Controller.h index cd4b786665b..65e42a030e6 100644 --- a/Sofa/Component/Controller/src/sofa/component/controller/Controller.h +++ b/Sofa/Component/Controller/src/sofa/component/controller/Controller.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::core::objectmodel { @@ -111,7 +111,7 @@ class SOFA_COMPONENT_CONTROLLER_API Controller : public core::behavior::BaseCont protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONTROLLER() - sofa::core::objectmodel::RenamedData < bool > handleEventTriggersUpdate; + sofa::core::objectmodel::lifecycle::RenamedData < bool > handleEventTriggersUpdate; Data< bool > d_handleEventTriggersUpdate; ///< Event handling frequency controls the controller update frequency diff --git a/Sofa/Component/Controller/src/sofa/component/controller/MechanicalStateController.h b/Sofa/Component/Controller/src/sofa/component/controller/MechanicalStateController.h index 9913eaeb098..aae4eff9d21 100644 --- a/Sofa/Component/Controller/src/sofa/component/controller/MechanicalStateController.h +++ b/Sofa/Component/Controller/src/sofa/component/controller/MechanicalStateController.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::controller { @@ -131,16 +131,16 @@ class MechanicalStateController : public Controller void applyController(void); protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONTROLLER() - sofa::core::objectmodel::RenamedData< unsigned int > index; + sofa::core::objectmodel::lifecycle::RenamedData< unsigned int > index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONTROLLER() - sofa::core::objectmodel::RenamedData< bool > onlyTranslation; + sofa::core::objectmodel::lifecycle::RenamedData< bool > onlyTranslation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONTROLLER() - sofa::core::objectmodel::RenamedData< bool > buttonDeviceState; + sofa::core::objectmodel::lifecycle::RenamedData< bool > buttonDeviceState; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONTROLLER() - sofa::core::objectmodel::RenamedData< sofa::type::Vec<3,Real> > mainDirection; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::Vec<3,Real> > mainDirection; Data< unsigned int > d_index; ///< Index of the controlled DOF Data< bool > d_onlyTranslation; ///< Controlling the DOF only in translation diff --git a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h index d0159ca3e35..2b542f34e16 100644 --- a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h +++ b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/Distances.h @@ -40,7 +40,7 @@ #define TYPE_VORONOI 3 #define TYPE_HARMONIC_STIFFNESS 4 -#include +#include namespace sofa::component::engine::analyze { @@ -79,40 +79,40 @@ class Distances : public core::DataEngine public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showMapIndex; + sofa::core::objectmodel::lifecycle::RenamedData showMapIndex; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showDistanceMap; + sofa::core::objectmodel::lifecycle::RenamedData showDistanceMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showGoalDistanceMap; + sofa::core::objectmodel::lifecycle::RenamedData showGoalDistanceMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showTextScaleFactor; + sofa::core::objectmodel::lifecycle::RenamedData showTextScaleFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showGradientMap; + sofa::core::objectmodel::lifecycle::RenamedData showGradientMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData showGradientsScaleFactor; + sofa::core::objectmodel::lifecycle::RenamedData showGradientsScaleFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData offset; + sofa::core::objectmodel::lifecycle::RenamedData offset; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData distanceType; + sofa::core::objectmodel::lifecycle::RenamedData distanceType; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData initTarget; + sofa::core::objectmodel::lifecycle::RenamedData initTarget; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData initTargetStep; + sofa::core::objectmodel::lifecycle::RenamedData initTargetStep; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData > zonesFramePair; + sofa::core::objectmodel::lifecycle::RenamedData > zonesFramePair; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData harmonicMaxValue; + sofa::core::objectmodel::lifecycle::RenamedData harmonicMaxValue; Data d_showMapIndex; ///< Frame DOF index on which display values. @@ -227,13 +227,13 @@ class Distances : public core::DataEngine private: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData fileDistance; + sofa::core::objectmodel::lifecycle::RenamedData fileDistance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData targetPath; + sofa::core::objectmodel::lifecycle::RenamedData targetPath; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData hexaContainerPath; + sofa::core::objectmodel::lifecycle::RenamedData hexaContainerPath; Data d_fileDistance; ///< file containing the result of the computation of the distances diff --git a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/HausdorffDistance.h b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/HausdorffDistance.h index 9631705ffcb..6f7187b4829 100644 --- a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/HausdorffDistance.h +++ b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/HausdorffDistance.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::engine::analyze { @@ -62,22 +62,22 @@ class HausdorffDistance : public core::DataEngine void doUpdate() override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData f_points_1; + sofa::core::objectmodel::lifecycle::RenamedData f_points_1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData f_points_2; + sofa::core::objectmodel::lifecycle::RenamedData f_points_2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData d12; + sofa::core::objectmodel::lifecycle::RenamedData d12; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData d21; + sofa::core::objectmodel::lifecycle::RenamedData d21; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData max; + sofa::core::objectmodel::lifecycle::RenamedData max; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData f_update; + sofa::core::objectmodel::lifecycle::RenamedData f_update; //Input Data d_points_1; ///< Points belonging to the first point cloud diff --git a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/ShapeMatching.h b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/ShapeMatching.h index 6261365b93c..f11328a5b4f 100644 --- a/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/ShapeMatching.h +++ b/Sofa/Component/Engine/Analyze/src/sofa/component/engine/analyze/ShapeMatching.h @@ -34,7 +34,7 @@ #include #include -#include +#include namespace sofa::component::engine::analyze { @@ -72,28 +72,28 @@ class ShapeMatching : public core::DataEngine, public core::behavior::SingleStat void draw(const core::visual::VisualParams* vparams) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData iterations; + sofa::core::objectmodel::lifecycle::RenamedData iterations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData affineRatio; + sofa::core::objectmodel::lifecycle::RenamedData affineRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData fixedweight; + sofa::core::objectmodel::lifecycle::RenamedData fixedweight; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData fixedPosition0; + sofa::core::objectmodel::lifecycle::RenamedData fixedPosition0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData fixedPosition; + sofa::core::objectmodel::lifecycle::RenamedData fixedPosition; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData position; + sofa::core::objectmodel::lifecycle::RenamedData position; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData< VVI > cluster; + sofa::core::objectmodel::lifecycle::RenamedData< VVI > cluster; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_ANALYZE() - sofa::core::objectmodel::RenamedData targetPosition; + sofa::core::objectmodel::lifecycle::RenamedData targetPosition; Data d_iterations; ///< Number of iterations. diff --git a/Sofa/Component/Engine/Analyze/tests/AverageCoord_test.cpp b/Sofa/Component/Engine/Analyze/tests/AverageCoord_test.cpp index 64d6951acd8..96d9416c4f6 100644 --- a/Sofa/Component/Engine/Analyze/tests/AverageCoord_test.cpp +++ b/Sofa/Component/Engine/Analyze/tests/AverageCoord_test.cpp @@ -57,7 +57,7 @@ struct AverageCoord_test : public BaseSimulationTest, typename MechanicalObject::SPtr m_mecaobject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Analyze/tests/ClusteringEngine_test.cpp b/Sofa/Component/Engine/Analyze/tests/ClusteringEngine_test.cpp index 6e109a7ae48..b57ca438e54 100644 --- a/Sofa/Component/Engine/Analyze/tests/ClusteringEngine_test.cpp +++ b/Sofa/Component/Engine/Analyze/tests/ClusteringEngine_test.cpp @@ -57,7 +57,7 @@ struct ClusteringEngine_test : public BaseSimulationTest, typename MechanicalObject::SPtr m_mecaobject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Generate/src/sofa/component/engine/generate/MeshTetraStuffing.h b/Sofa/Component/Engine/Generate/src/sofa/component/engine/generate/MeshTetraStuffing.h index f67ba6166d3..0b1b8805424 100644 --- a/Sofa/Component/Engine/Generate/src/sofa/component/engine/generate/MeshTetraStuffing.h +++ b/Sofa/Component/Engine/Generate/src/sofa/component/engine/generate/MeshTetraStuffing.h @@ -32,7 +32,7 @@ #include -#include +#include namespace sofa::component::engine::generate { @@ -72,40 +72,40 @@ class SOFA_COMPONENT_ENGINE_GENERATE_API MeshTetraStuffing : public core::DataEn SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData< type::fixed_array > vbbox; + sofa::core::objectmodel::lifecycle::RenamedData< type::fixed_array > vbbox; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData inputPoints; + sofa::core::objectmodel::lifecycle::RenamedData inputPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData inputTriangles; + sofa::core::objectmodel::lifecycle::RenamedData inputTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData inputQuads; + sofa::core::objectmodel::lifecycle::RenamedData inputQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData outputPoints; + sofa::core::objectmodel::lifecycle::RenamedData outputPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData outputTetrahedra; + sofa::core::objectmodel::lifecycle::RenamedData outputTetrahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData< Real > alphaLong; + sofa::core::objectmodel::lifecycle::RenamedData< Real > alphaLong; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData alphaShort; + sofa::core::objectmodel::lifecycle::RenamedData alphaShort; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData bSnapPoints; + sofa::core::objectmodel::lifecycle::RenamedData bSnapPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData< bool > bSplitTetrahedra; + sofa::core::objectmodel::lifecycle::RenamedData< bool > bSplitTetrahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData< bool > bDraw; + sofa::core::objectmodel::lifecycle::RenamedData< bool > bDraw; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_GENERATE() - sofa::core::objectmodel::RenamedData< Real > size; + sofa::core::objectmodel::lifecycle::RenamedData< Real > size; diff --git a/Sofa/Component/Engine/Generate/tests/ExtrudeEdgesAndGenerateQuads_test.cpp b/Sofa/Component/Engine/Generate/tests/ExtrudeEdgesAndGenerateQuads_test.cpp index be297368933..c7a2fdd853c 100644 --- a/Sofa/Component/Engine/Generate/tests/ExtrudeEdgesAndGenerateQuads_test.cpp +++ b/Sofa/Component/Engine/Generate/tests/ExtrudeEdgesAndGenerateQuads_test.cpp @@ -55,7 +55,7 @@ struct ExtrudeEdgesAndGenerateQuads_test : public BaseSimulationTest, Node::SPtr m_node; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Generate/tests/MergePoints_test.cpp b/Sofa/Component/Engine/Generate/tests/MergePoints_test.cpp index 0e101c6440f..5f50d949e1f 100644 --- a/Sofa/Component/Engine/Generate/tests/MergePoints_test.cpp +++ b/Sofa/Component/Engine/Generate/tests/MergePoints_test.cpp @@ -49,7 +49,7 @@ struct MergePoints_test : public BaseSimulationTest, Simulation* m_simu; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/BaseROI.h b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/BaseROI.h index c9c84070c0f..ba9ad625162 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/BaseROI.h +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/BaseROI.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::engine::select { @@ -128,7 +128,7 @@ class BaseROI : public core::DataEngine Data d_doUpdate; ///< If true, updates the selection at the beginning of simulation steps. (default = true) SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData d_X0; + sofa::core::objectmodel::lifecycle::RenamedData d_X0; protected: BaseROI(); ~BaseROI() override = default; diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.h b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.h index 491a0cabd9a..2544903fc1a 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.h +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.h @@ -34,7 +34,7 @@ #include -#include +#include namespace sofa::component::engine::select { @@ -109,11 +109,11 @@ class MeshROI : public BaseROI static bool isPointInIndices(const unsigned int i, const SetIndex& indices); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData d_X0_i; + sofa::core::objectmodel::lifecycle::RenamedData d_X0_i; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData > d_edges_i;; + sofa::core::objectmodel::lifecycle::RenamedData > d_edges_i;; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData > d_triangles_i; + sofa::core::objectmodel::lifecycle::RenamedData > d_triangles_i; }; #if !defined(SOFA_COMPONENT_ENGINE_MESHROI_CPP) diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.inl b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.inl index 1121b696f00..679a9259e20 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.inl +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshROI.inl @@ -501,7 +501,9 @@ void MeshROI::roiComputeBBox(const core::ExecParams* params, type::Bo for (const auto& p : roiPositions) { - bbox.include(DataTypes::getCPos(p)); + Real x, y, z; + DataTypes::get(x, y, z, p); + bbox.include({x, y, z}); } } diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshSubsetEngine.h b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshSubsetEngine.h index 1ebefc40368..94786a04422 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshSubsetEngine.h +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/MeshSubsetEngine.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -72,23 +72,23 @@ class MeshSubsetEngine : public core::DataEngine Data< SeqHexahedra > d_hexahedra; ///< Hexahedra of mesh subset SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData inputPosition; + core::objectmodel::lifecycle::RenamedData inputPosition; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData inputEdges; + core::objectmodel::lifecycle::RenamedData inputEdges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData inputTriangles; + core::objectmodel::lifecycle::RenamedData inputTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData inputQuads; + core::objectmodel::lifecycle::RenamedData inputQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData indices; + core::objectmodel::lifecycle::RenamedData indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData position; + core::objectmodel::lifecycle::RenamedData position; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData edges; + core::objectmodel::lifecycle::RenamedData edges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData triangles; + core::objectmodel::lifecycle::RenamedData triangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - core::objectmodel::RenamedData quads; + core::objectmodel::lifecycle::RenamedData quads; protected: MeshSubsetEngine(); diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/SphereROI.h b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/SphereROI.h index 488aaebcc54..68804f9e49c 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/SphereROI.h +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/SphereROI.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::engine::select { @@ -81,17 +81,17 @@ class SphereROI : public BaseROI Data< Real > d_triAngle; ///< Max angle between the normal of the selected triangle and the specified normal direction SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< type::vector > centers; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > centers; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< type::vector > radii; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > radii; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< type::Vec3 > direction; + sofa::core::objectmodel::lifecycle::RenamedData< type::Vec3 > direction; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< type::Vec3 > normal; + sofa::core::objectmodel::lifecycle::RenamedData< type::Vec3 > normal; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< Real > edgeAngle; + sofa::core::objectmodel::lifecycle::RenamedData< Real > edgeAngle; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ENGINE_SELECT() - sofa::core::objectmodel::RenamedData< Real > triAngle; + sofa::core::objectmodel::lifecycle::RenamedData< Real > triAngle; }; #if !defined(SOFA_COMPONENT_ENGINE_SPHEREROI_CPP) diff --git a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/ValuesFromPositions.inl b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/ValuesFromPositions.inl index be9c929108a..d88b40ed666 100644 --- a/Sofa/Component/Engine/Select/src/sofa/component/engine/select/ValuesFromPositions.inl +++ b/Sofa/Component/Engine/Select/src/sofa/component/engine/select/ValuesFromPositions.inl @@ -430,8 +430,7 @@ void ValuesFromPositions::draw(const core::visual::VisualParams* vpar color[j] = (float)fabs (tetrahedronVectors[i][j]); colors.push_back(color); - colors.push_back(color); - + vertices.push_back(point1); vertices.push_back(point2); } diff --git a/Sofa/Component/Engine/Select/tests/BoxROI_test.cpp b/Sofa/Component/Engine/Select/tests/BoxROI_test.cpp index 6b0d14609ae..08425f2c4cb 100644 --- a/Sofa/Component/Engine/Select/tests/BoxROI_test.cpp +++ b/Sofa/Component/Engine/Select/tests/BoxROI_test.cpp @@ -70,11 +70,12 @@ struct BoxROITest : public sofa::testing::BaseTest Node::SPtr m_node; typename TheBoxROI::SPtr m_boxroi; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Engine.Select"); + this->loadPlugins({ + Sofa.Component.StateContainer, + Sofa.Component.Topology.Container.Dynamic, + Sofa.Component.Engine.Select}); m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); @@ -86,7 +87,7 @@ struct BoxROITest : public sofa::testing::BaseTest m_node->addObject(m_boxroi); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr){ sofa::simulation::node::unload(m_root); diff --git a/Sofa/Component/Engine/Select/tests/ComplementaryROI_test.cpp b/Sofa/Component/Engine/Select/tests/ComplementaryROI_test.cpp index 38b1dcc0057..ec055b0321a 100644 --- a/Sofa/Component/Engine/Select/tests/ComplementaryROI_test.cpp +++ b/Sofa/Component/Engine/Select/tests/ComplementaryROI_test.cpp @@ -55,7 +55,7 @@ struct ComplementaryROI_test : public BaseSimulationTest, typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Select/tests/MeshROI_test.cpp b/Sofa/Component/Engine/Select/tests/MeshROI_test.cpp index aa3e96d8ab6..1ebd9f92505 100644 --- a/Sofa/Component/Engine/Select/tests/MeshROI_test.cpp +++ b/Sofa/Component/Engine/Select/tests/MeshROI_test.cpp @@ -61,11 +61,11 @@ struct MeshROI_test : public BaseSimulationTest, Node::SPtr m_root; ThisClass* m_thisObject; - void SetUp() override + void doSetUp() override { - simpleapi::importPlugin("Sofa.Component.Engine.Select"); - simpleapi::importPlugin("Sofa.Component.Topology.Container.Constant"); - simpleapi::importPlugin("Sofa.Component.IO.Mesh"); + simpleapi::importPlugin(Sofa.Component.Engine.Select); + simpleapi::importPlugin(Sofa.Component.Topology.Container.Constant); + simpleapi::importPlugin(Sofa.Component.IO.Mesh); // SetUp3 const string scene2 = @@ -86,7 +86,7 @@ struct MeshROI_test : public BaseSimulationTest, ASSERT_NE(m_thisObject, nullptr) ; } - void TearDown() override + void doTearDown() override { sofa::simulation::node::unload(m_root) ; } diff --git a/Sofa/Component/Engine/Select/tests/MeshSubsetEngine_test.cpp b/Sofa/Component/Engine/Select/tests/MeshSubsetEngine_test.cpp index 17ed3e5d1ca..4ce112798ff 100644 --- a/Sofa/Component/Engine/Select/tests/MeshSubsetEngine_test.cpp +++ b/Sofa/Component/Engine/Select/tests/MeshSubsetEngine_test.cpp @@ -31,9 +31,9 @@ struct MeshSubsetEngine_test : public testing::BaseSimulationTest sofa::simulation::Node::SPtr m_root; typename component::engine::select::MeshSubsetEngine<_DataTypes>::SPtr m_engine; - void SetUp() override + void doSetUp() override { - simpleapi::importPlugin("Sofa.Component.Engine.Select"); + simpleapi::importPlugin(Sofa.Component.Engine.Select); m_root = simulation::getSimulation()->createNewNode("root"); ASSERT_NE(nullptr, m_root); @@ -44,7 +44,7 @@ struct MeshSubsetEngine_test : public testing::BaseSimulationTest m_root->addObject(m_engine); } - void TearDown() override + void doTearDown() override { sofa::simulation::node::unload(m_root) ; } diff --git a/Sofa/Component/Engine/Select/tests/PlaneROI_test.cpp b/Sofa/Component/Engine/Select/tests/PlaneROI_test.cpp index 8ed1acd210f..628d8b97771 100644 --- a/Sofa/Component/Engine/Select/tests/PlaneROI_test.cpp +++ b/Sofa/Component/Engine/Select/tests/PlaneROI_test.cpp @@ -61,7 +61,7 @@ struct PlaneROI_test : public BaseSimulationTest, Node::SPtr m_node1, m_node2; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { // SetUp1 m_simu = sofa::simulation::getSimulation(); diff --git a/Sofa/Component/Engine/Select/tests/SphereROI_test.cpp b/Sofa/Component/Engine/Select/tests/SphereROI_test.cpp index 3033378429f..0bfb8a12387 100644 --- a/Sofa/Component/Engine/Select/tests/SphereROI_test.cpp +++ b/Sofa/Component/Engine/Select/tests/SphereROI_test.cpp @@ -61,7 +61,7 @@ struct SphereROI_test : public BaseSimulationTest, Node::SPtr m_node; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Transform/tests/DifferenceEngine_test.cpp b/Sofa/Component/Engine/Transform/tests/DifferenceEngine_test.cpp index caf5d3c7bdd..d2f7ecddbbd 100644 --- a/Sofa/Component/Engine/Transform/tests/DifferenceEngine_test.cpp +++ b/Sofa/Component/Engine/Transform/tests/DifferenceEngine_test.cpp @@ -54,7 +54,7 @@ struct DifferenceEngine_test : public BaseSimulationTest, Node::SPtr m_node; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Transform/tests/DilateEngine_test.cpp b/Sofa/Component/Engine/Transform/tests/DilateEngine_test.cpp index f24b09c827c..bbed29b8fa5 100644 --- a/Sofa/Component/Engine/Transform/tests/DilateEngine_test.cpp +++ b/Sofa/Component/Engine/Transform/tests/DilateEngine_test.cpp @@ -52,7 +52,7 @@ struct DilateEngine_test : public BaseSimulationTest, Node::SPtr m_node; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/Transform/tests/SmoothMeshEngine_test.cpp b/Sofa/Component/Engine/Transform/tests/SmoothMeshEngine_test.cpp index 4d05f03fba7..d28d41321e9 100644 --- a/Sofa/Component/Engine/Transform/tests/SmoothMeshEngine_test.cpp +++ b/Sofa/Component/Engine/Transform/tests/SmoothMeshEngine_test.cpp @@ -53,7 +53,7 @@ struct SmoothMeshEngine_test : public BaseSimulationTest, Node::SPtr m_node; typename ThisClass::SPtr m_thisObject; - void SetUp() override + void doSetUp() override { m_simu = sofa::simulation::getSimulation(); ASSERT_NE(m_simu, nullptr); diff --git a/Sofa/Component/Engine/src/sofa/component/engine/init.cpp b/Sofa/Component/Engine/src/sofa/component/engine/init.cpp index 05eeff6cc2b..4ffe472034e 100644 --- a/Sofa/Component/Engine/src/sofa/component/engine/init.cpp +++ b/Sofa/Component/Engine/src/sofa/component/engine/init.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace sofa::component::engine { @@ -56,10 +57,10 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Engine.Analyze"); - factory->registerObjectsFromPlugin("Sofa.Component.Engine.Generate"); - factory->registerObjectsFromPlugin("Sofa.Component.Engine.Select"); - factory->registerObjectsFromPlugin("Sofa.Component.Engine.Transform"); + factory->registerObjectsFromPlugin(Sofa.Component.Engine.Analyze); + factory->registerObjectsFromPlugin(Sofa.Component.Engine.Generate); + factory->registerObjectsFromPlugin(Sofa.Component.Engine.Select); + factory->registerObjectsFromPlugin(Sofa.Component.Engine.Transform); } void init() diff --git a/Sofa/Component/Haptics/src/sofa/component/haptics/LCPForceFeedback.h b/Sofa/Component/Haptics/src/sofa/component/haptics/LCPForceFeedback.h index 3b8494339b8..f6559fef3f7 100644 --- a/Sofa/Component/Haptics/src/sofa/component/haptics/LCPForceFeedback.h +++ b/Sofa/Component/Haptics/src/sofa/component/haptics/LCPForceFeedback.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::haptics { @@ -63,10 +63,10 @@ class LCPForceFeedback : public MechanicalStateForceFeedback } SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_HAPTICS() - sofa::core::objectmodel::RenamedData forceCoef; + sofa::core::objectmodel::lifecycle::RenamedData forceCoef; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_HAPTICS() - sofa::core::objectmodel::RenamedData solverTimeout; + sofa::core::objectmodel::lifecycle::RenamedData solverTimeout; Data< double > d_forceCoef; ///< multiply haptic force by this coef. diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/BlenderExporter.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/BlenderExporter.h index d6d9e614a59..d69c27e7806 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/BlenderExporter.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/BlenderExporter.h @@ -38,7 +38,7 @@ #include -#include +#include namespace sofa::component { @@ -73,19 +73,19 @@ class SOFA_COMPONENT_IO_MESH_API BlenderExporter: public core::objectmodel::Base SOFA_CLASS(SOFA_TEMPLATE(BlenderExporter,T),core::objectmodel::BaseObject); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData path; + sofa::core::objectmodel::lifecycle::RenamedData path; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData baseName; + sofa::core::objectmodel::lifecycle::RenamedData baseName; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData simulationType; + sofa::core::objectmodel::lifecycle::RenamedData simulationType; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData simulationStep; + sofa::core::objectmodel::lifecycle::RenamedData simulationStep; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData nbPtsByHair; + sofa::core::objectmodel::lifecycle::RenamedData nbPtsByHair; Data < std::string > d_path; ///< output path diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/GridMeshCreator.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/GridMeshCreator.h index 91a6a0370b4..f0018ed751a 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/GridMeshCreator.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/GridMeshCreator.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::io::mesh { @@ -44,10 +44,10 @@ class SOFA_COMPONENT_IO_MESH_API GridMeshCreator : public sofa::core::loader::Me bool canLoad() override { return true; } bool doLoad() override; ///< create the grid SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< type::Vec2i > resolution; + sofa::core::objectmodel::lifecycle::RenamedData< type::Vec2i > resolution; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< int > trianglePattern; + sofa::core::objectmodel::lifecycle::RenamedData< int > trianglePattern; diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshSTLLoader.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshSTLLoader.h index 066b26113f1..f896ba79700 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshSTLLoader.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshSTLLoader.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace sofa::component::io::mesh { @@ -51,10 +51,10 @@ class SOFA_COMPONENT_IO_MESH_API MeshSTLLoader : public sofa::core::loader::Mesh public: //Add Data here SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData _forceBinary; + sofa::core::objectmodel::lifecycle::RenamedData _forceBinary; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData _headerSize; + sofa::core::objectmodel::lifecycle::RenamedData _headerSize; diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshTrianLoader.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshTrianLoader.h index 92bd4e6124c..7a9aae5e63f 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshTrianLoader.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/MeshTrianLoader.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::io::mesh { @@ -56,16 +56,16 @@ class SOFA_COMPONENT_IO_MESH_API MeshTrianLoader : public sofa::core::loader::Me public: //Add specific Data here: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData p_trian2; + sofa::core::objectmodel::lifecycle::RenamedData p_trian2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData > > neighborTable; + sofa::core::objectmodel::lifecycle::RenamedData > > neighborTable; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData > > edgesOnBorder; + sofa::core::objectmodel::lifecycle::RenamedData > > edgesOnBorder; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData > trianglesOnBorderList; + sofa::core::objectmodel::lifecycle::RenamedData > trianglesOnBorderList; Data d_trian2; ///< Set to true if the mesh is a trian2 format. Data > > d_neighborTable; ///< Table of neighborhood triangle indices for each triangle. diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/OffSequenceLoader.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/OffSequenceLoader.h index aa8e4d25172..84bda24944a 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/OffSequenceLoader.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/OffSequenceLoader.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::io::mesh { @@ -51,9 +51,9 @@ class SOFA_COMPONENT_IO_MESH_API OffSequenceLoader : public MeshOffLoader private: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData nbFiles; + sofa::core::objectmodel::lifecycle::RenamedData nbFiles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData stepDuration; + sofa::core::objectmodel::lifecycle::RenamedData stepDuration; /// the number of files in the sequences diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/StringMeshCreator.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/StringMeshCreator.h index 8077b3587e2..166bf418493 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/StringMeshCreator.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/StringMeshCreator.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::io::mesh { @@ -39,7 +39,7 @@ class SOFA_COMPONENT_IO_MESH_API StringMeshCreator : public sofa::core::loader:: { public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< unsigned > resolution; + sofa::core::objectmodel::lifecycle::RenamedData< unsigned > resolution; SOFA_CLASS(StringMeshCreator,sofa::core::loader::MeshLoader); virtual std::string type() { return "This object is procedurally created"; } diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VTKExporter.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VTKExporter.h index 2d2c872068d..cc333ca90b5 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VTKExporter.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VTKExporter.h @@ -30,7 +30,7 @@ #include -#include +#include namespace sofa::component::_vtkexporter_ { @@ -60,43 +60,43 @@ class SOFA_COMPONENT_IO_MESH_API VTKExporter : public core::objectmodel::BaseObj sofa::core::objectmodel::DataFileName vtkFilename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > fileFormat; + sofa::core::objectmodel::lifecycle::RenamedData< bool > fileFormat; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData position; + sofa::core::objectmodel::lifecycle::RenamedData position; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > writeEdges; + sofa::core::objectmodel::lifecycle::RenamedData< bool > writeEdges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > writeTriangles; + sofa::core::objectmodel::lifecycle::RenamedData< bool > writeTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > writeQuads; + sofa::core::objectmodel::lifecycle::RenamedData< bool > writeQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > writeTetras; + sofa::core::objectmodel::lifecycle::RenamedData< bool > writeTetras; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > writeHexas; + sofa::core::objectmodel::lifecycle::RenamedData< bool > writeHexas; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData > dPointsDataFields; + sofa::core::objectmodel::lifecycle::RenamedData > dPointsDataFields; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData > dCellsDataFields; + sofa::core::objectmodel::lifecycle::RenamedData > dCellsDataFields; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< unsigned int > exportEveryNbSteps; + sofa::core::objectmodel::lifecycle::RenamedData< unsigned int > exportEveryNbSteps; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > exportAtBegin; + sofa::core::objectmodel::lifecycle::RenamedData< bool > exportAtBegin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > exportAtEnd; + sofa::core::objectmodel::lifecycle::RenamedData< bool > exportAtEnd; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< bool > overwrite; + sofa::core::objectmodel::lifecycle::RenamedData< bool > overwrite; diff --git a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VoxelGridLoader.h b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VoxelGridLoader.h index 0b3e9255038..0921f06daf6 100644 --- a/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VoxelGridLoader.h +++ b/Sofa/Component/IO/Mesh/src/sofa/component/io/mesh/VoxelGridLoader.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::io::mesh { @@ -74,31 +74,31 @@ class SOFA_COMPONENT_IO_MESH_API VoxelGridLoader : public sofa::core::loader::Vo // fill the texture by 'image' only where there is the 'segmentation' of 'd_activeValue' and give the 3D texture sizes void createSegmentation3DTexture( unsigned char **textureData, int& width, int& height, int& depth) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< type::Vec3 > voxelSize; + sofa::core::objectmodel::lifecycle::RenamedData< type::Vec3 > voxelSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< Vec3i > dataResolution; + sofa::core::objectmodel::lifecycle::RenamedData< Vec3i > dataResolution; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< Vec6i > roi; + sofa::core::objectmodel::lifecycle::RenamedData< Vec6i > roi; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< int > headerSize; + sofa::core::objectmodel::lifecycle::RenamedData< int > headerSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< int > segmentationHeaderSize; + sofa::core::objectmodel::lifecycle::RenamedData< int > segmentationHeaderSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< type::vector > idxInRegularGrid; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > idxInRegularGrid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< type::vector > backgroundValue; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > backgroundValue; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData< type::vector > activeValue; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > activeValue; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_IO_MESH() - sofa::core::objectmodel::RenamedData generateHexa; + sofa::core::objectmodel::lifecycle::RenamedData generateHexa; diff --git a/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp index 9c5996dee24..eb0282269cd 100644 --- a/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp @@ -75,13 +75,13 @@ class MeshExporter_test /// remove the file created... std::vector dataPath; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Grid"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); } - void TearDown() override + void doTearDown() override { for (const auto& pathToRemove : dataPath) { diff --git a/Sofa/Component/IO/Mesh/tests/MeshGmshLoader_test.cpp b/Sofa/Component/IO/Mesh/tests/MeshGmshLoader_test.cpp index 93a26d24592..38534751514 100644 --- a/Sofa/Component/IO/Mesh/tests/MeshGmshLoader_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/MeshGmshLoader_test.cpp @@ -51,7 +51,7 @@ namespace meshgmshloader_test /** * Constructor call for each test */ - void SetUp() override {} + void doSetUp() override {} /** * Helper function to check mesh loading. diff --git a/Sofa/Component/IO/Mesh/tests/MeshXspLoader_test.cpp b/Sofa/Component/IO/Mesh/tests/MeshXspLoader_test.cpp index df20ce772a6..3a167422840 100644 --- a/Sofa/Component/IO/Mesh/tests/MeshXspLoader_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/MeshXspLoader_test.cpp @@ -35,7 +35,7 @@ class MeshXspLoader_test : public BaseSimulationTest const Node::SPtr root = sofa::simpleapi::createRootNode(simulation, "root"); sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); - sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name","Sofa.Component.IO.Mesh" } }); + sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name",Sofa.Component.IO.Mesh } }); auto loader = sofa::simpleapi::createObject(root, "MeshXspLoader", {{"filename", std::string(SOFA_COMPONENT_IO_MESH_TEST_FILES_DIR)+"test.xs3"}}); sofa::simulation::node::initRoot(root.get()); diff --git a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp index 55b6be2b8b8..1f8429d1224 100644 --- a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp @@ -65,13 +65,14 @@ class STLExporter_test : public BaseSimulationTest { /// remove the file created... std::vector dataPath ; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Visual"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Visual); + sofa::simpleapi::importPlugin(Sofa.Component.IO.Mesh); } - void TearDown() override + void doTearDown() override { for (const auto& pathToRemove : dataPath) { @@ -98,7 +99,6 @@ class STLExporter_test : public BaseSimulationTest { " \n" " \n" " \n" - " \n" " \n" " \n" " \n" diff --git a/Sofa/Component/IO/Mesh/tests/VisualModelOBJExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/VisualModelOBJExporter_test.cpp index 1010d487118..eeb1810bcd0 100644 --- a/Sofa/Component/IO/Mesh/tests/VisualModelOBJExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/VisualModelOBJExporter_test.cpp @@ -62,11 +62,11 @@ class VisualModelOBJExporter_test : public BaseSimulationTest { /// remove the file created... std::vector dataPath ; - void SetUp() override + void doSetUp() override { } - void TearDown() override + void doTearDown() override { for (const auto& pathToRemove : dataPath) { diff --git a/Sofa/Component/IO/src/sofa/component/io/init.cpp b/Sofa/Component/IO/src/sofa/component/io/init.cpp index 45cfe4d1971..cf13bfd0001 100644 --- a/Sofa/Component/IO/src/sofa/component/io/init.cpp +++ b/Sofa/Component/IO/src/sofa/component/io/init.cpp @@ -25,6 +25,7 @@ #include #include +#include namespace sofa::component::io { @@ -53,7 +54,7 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.IO.Mesh"); + factory->registerObjectsFromPlugin(Sofa.Component.IO.Mesh); } void init() diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/PrecomputedLinearSolver.h b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/PrecomputedLinearSolver.h index 7c8573a083f..118f170edc3 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/PrecomputedLinearSolver.h +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/PrecomputedLinearSolver.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::linearsolver::direct { @@ -83,10 +83,10 @@ class PrecomputedLinearSolver : public sofa::component::linearsolver::MatrixLine typedef typename PrecomputedLinearSolverInternalData::TBaseMatrix TBaseMatrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_DIRECT() - sofa::core::objectmodel::RenamedData jmjt_twostep; + sofa::core::objectmodel::lifecycle::RenamedData jmjt_twostep; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_DIRECT() - sofa::core::objectmodel::RenamedData use_file; + sofa::core::objectmodel::lifecycle::RenamedData use_file; Data d_jmjt_twostep; ///< Use two step algorithm to compute JMinvJt diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SVDLinearSolver.h b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SVDLinearSolver.h index 36a91409e55..f0d619e5467 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SVDLinearSolver.h +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/SVDLinearSolver.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::linearsolver::direct { @@ -51,13 +51,13 @@ class SVDLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver typedef sofa::component::linearsolver::MatrixLinearSolver Inherit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_DIRECT() - sofa::core::objectmodel::RenamedData f_verbose; + sofa::core::objectmodel::lifecycle::RenamedData f_verbose; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_DIRECT() - sofa::core::objectmodel::RenamedData f_minSingularValue; + sofa::core::objectmodel::lifecycle::RenamedData f_minSingularValue; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_DIRECT() - sofa::core::objectmodel::RenamedData f_conditionNumber; + sofa::core::objectmodel::lifecycle::RenamedData f_conditionNumber; Data d_verbose; ///< Dump system state at each iteration diff --git a/Sofa/Component/LinearSolver/Direct/tests/SparseLDLSolver_test.cpp b/Sofa/Component/LinearSolver/Direct/tests/SparseLDLSolver_test.cpp index 6dd556f57b6..3d72df3da06 100644 --- a/Sofa/Component/LinearSolver/Direct/tests/SparseLDLSolver_test.cpp +++ b/Sofa/Component/LinearSolver/Direct/tests/SparseLDLSolver_test.cpp @@ -57,9 +57,10 @@ TEST(SparseLDLSolver, EmptyMState) const sofa::simulation::Node::SPtr root = sofa::simulation::getSimulation()->createNewGraph("root"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Direct"); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + const auto plugins = sofa::testing::makeScopedPlugin({ + Sofa.Component.LinearSolver.Direct, + Sofa.Component.ODESolver.Backward, + Sofa.Component.StateContainer}); sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); sofa::simpleapi::createObject(root, "EulerImplicitSolver"); @@ -83,14 +84,15 @@ TEST(SparseLDLSolver, TopologyChangeEmptyMState) // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; - const sofa::simulation::Node::SPtr root = sofa::simulation::getSimulation()->createNewGraph("root"); + const sofa::simulation::Node::SPtr root = sofa::simulation::getSimulation()->createNewGraph("root"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Direct"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Utility"); + const auto plugins = sofa::testing::makeScopedPlugin({ + Sofa.Component.LinearSolver.Direct, + Sofa.Component.Mass, + Sofa.Component.ODESolver.Backward, + Sofa.Component.StateContainer, + Sofa.Component.Topology.Container.Dynamic, + Sofa.Component.Topology.Utility}); sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); sofa::simpleapi::createObject(root, "EulerImplicitSolver"); diff --git a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h index 1506256becd..50dd8f112fc 100644 --- a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h +++ b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h @@ -28,7 +28,7 @@ #include -#include +#include namespace sofa::component::linearsolver::iterative { @@ -45,22 +45,22 @@ class PCGLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver typedef sofa::component::linearsolver::MatrixLinearSolver Inherit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_maxIter; + sofa::core::objectmodel::lifecycle::RenamedData f_maxIter; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_tolerance; + sofa::core::objectmodel::lifecycle::RenamedData f_tolerance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_use_precond; + sofa::core::objectmodel::lifecycle::RenamedData f_use_precond; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_update_step; + sofa::core::objectmodel::lifecycle::RenamedData f_update_step; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_build_precond; + sofa::core::objectmodel::lifecycle::RenamedData f_build_precond; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData > > f_graph; + sofa::core::objectmodel::lifecycle::RenamedData > > f_graph; Data d_maxIter; ///< Maximum number of iterations after which the iterative descent of the Conjugate Gradient must stop diff --git a/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/PrecomputedWarpPreconditioner.h b/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/PrecomputedWarpPreconditioner.h index 0c92b8e28ad..f3b2bfa187b 100644 --- a/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/PrecomputedWarpPreconditioner.h +++ b/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/PrecomputedWarpPreconditioner.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::linearsolver::preconditioner { @@ -113,19 +113,19 @@ class PrecomputedWarpPreconditioner : public sofa::component::linearsolver::Matr sofa::core::objectmodel::lifecycle::RemovedData f_verbose{this, "v23.12", "v24.06", "verbose", "This Data is no longer used"}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData jmjt_twostep; + sofa::core::objectmodel::lifecycle::RenamedData jmjt_twostep; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData use_file; + sofa::core::objectmodel::lifecycle::RenamedData use_file; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData share_matrix; + sofa::core::objectmodel::lifecycle::RenamedData share_matrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData use_rotations; + sofa::core::objectmodel::lifecycle::RenamedData use_rotations; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData draw_rotations_scale; + sofa::core::objectmodel::lifecycle::RenamedData draw_rotations_scale; Data d_use_file; ///< Dump system matrix in a file diff --git a/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/SSORPreconditioner.h b/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/SSORPreconditioner.h index 2e83259bd01..2dfceedf0e0 100644 --- a/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/SSORPreconditioner.h +++ b/Sofa/Component/LinearSolver/Preconditioner/src/sofa/component/linearsolver/preconditioner/SSORPreconditioner.h @@ -30,7 +30,7 @@ #include -#include +#include namespace sofa::component::linearsolver::preconditioner { @@ -57,7 +57,7 @@ class SSORPreconditioner : public sofa::component::linearsolver::MatrixLinearSol sofa::core::objectmodel::lifecycle::RemovedData f_verbose{this, "v23.12", "v24.06", "verbose", "This Data is no longer used"}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_PRECONDITIONER() - sofa::core::objectmodel::RenamedData f_omega; + sofa::core::objectmodel::lifecycle::RenamedData f_omega; Data d_omega; ///< Omega coefficient protected: diff --git a/Sofa/Component/LinearSolver/src/sofa/component/linearsolver/init.cpp b/Sofa/Component/LinearSolver/src/sofa/component/linearsolver/init.cpp index 3e4a9c37cee..e4f74f3fe12 100644 --- a/Sofa/Component/LinearSolver/src/sofa/component/linearsolver/init.cpp +++ b/Sofa/Component/LinearSolver/src/sofa/component/linearsolver/init.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace sofa::component::linearsolver { @@ -56,10 +57,10 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.LinearSolver.Direct"); - factory->registerObjectsFromPlugin("Sofa.Component.LinearSolver.Iterative"); - factory->registerObjectsFromPlugin("Sofa.Component.LinearSolver.Ordering"); - factory->registerObjectsFromPlugin("Sofa.Component.LinearSolver.Preconditioner"); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSolver.Direct); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSolver.Iterative); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSolver.Ordering); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSolver.Preconditioner); } void init() diff --git a/Sofa/Component/LinearSystem/tests/MappingGraph_test.cpp b/Sofa/Component/LinearSystem/tests/MappingGraph_test.cpp index a8af9b59030..6595defef3a 100644 --- a/Sofa/Component/LinearSystem/tests/MappingGraph_test.cpp +++ b/Sofa/Component/LinearSystem/tests/MappingGraph_test.cpp @@ -176,7 +176,7 @@ TEST(MappingGraph, diamondMapping) sofa::simulation::Node::SPtr root = simulation->createNewGraph("root"); EXPECT_EQ(root->getName(), "root"); - sofa::simpleapi::importPlugin("Sofa.Component.Mapping.Linear"); + sofa::simpleapi::importPlugin(Sofa.Component.Mapping.Linear); const auto top = sofa::core::objectmodel::New >(); root->addObject(top); diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMappingRigid.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMappingRigid.h index 857303b7686..3db305f50d9 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMappingRigid.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/BarycentricMappingRigid.h @@ -37,7 +37,7 @@ #include #include -#include +#include namespace sofa::component::mapping::linear { @@ -70,10 +70,10 @@ class BarycentricMapperTetrahedronSetTopologyRigid : public TopologyBarycentricM protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData> map; + sofa::core::objectmodel::lifecycle::RenamedData> map; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData> mapOrient; + sofa::core::objectmodel::lifecycle::RenamedData> mapOrient; core::topology::PointData< sofa::type::vector > d_map; ///< mapper data core::topology::PointData< sofa::type::vector > d_mapOrient; ///< mapper data for mapped frames diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/DeformableOnRigidFrameMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/DeformableOnRigidFrameMapping.h index aa4fb521355..ba1b963ae58 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/DeformableOnRigidFrameMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/DeformableOnRigidFrameMapping.h @@ -26,7 +26,7 @@ #include -#include +#include namespace sofa::component::mapping::linear { @@ -96,22 +96,22 @@ class DeformableOnRigidFrameMapping : public LinearMulti2Mapping data; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData index; + sofa::core::objectmodel::lifecycle::RenamedData index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData indexFromEnd; + sofa::core::objectmodel::lifecycle::RenamedData indexFromEnd; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData > repartition; + sofa::core::objectmodel::lifecycle::RenamedData > repartition; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData globalToLocalCoords; + sofa::core::objectmodel::lifecycle::RenamedData globalToLocalCoords; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData m_rootAngularForceScaleFactor; + sofa::core::objectmodel::lifecycle::RenamedData m_rootAngularForceScaleFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData m_rootLinearForceScaleFactor; + sofa::core::objectmodel::lifecycle::RenamedData m_rootLinearForceScaleFactor; Data d_index; ///< input DOF index diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SkinningMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SkinningMapping.h index 99090b31c8c..156ffe4f6b3 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SkinningMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SkinningMapping.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::mapping::linear { @@ -78,22 +78,22 @@ class SkinningMapping : public LinearMapping protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_initPos; + sofa::core::objectmodel::lifecycle::RenamedData f_initPos; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData< type::vector > nbRef; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > nbRef; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData > > f_index; + sofa::core::objectmodel::lifecycle::RenamedData > > f_index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData > > weight; + sofa::core::objectmodel::lifecycle::RenamedData > > weight; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData showFromIndex; + sofa::core::objectmodel::lifecycle::RenamedData showFromIndex; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData showWeights; + sofa::core::objectmodel::lifecycle::RenamedData showWeights; Data d_initPos; ///< initial child coordinates in the world reference frame. diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMapping.h index 21d97b01071..3a7d32b9a8e 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMapping.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::mapping::linear { @@ -87,25 +87,25 @@ class SubsetMapping : public LinearMapping typedef sofa::core::topology::PointSubsetData< IndexArray > SetIndex; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_indices; + sofa::core::objectmodel::lifecycle::RenamedData f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_first; + sofa::core::objectmodel::lifecycle::RenamedData f_first; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_last; + sofa::core::objectmodel::lifecycle::RenamedData f_last; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_radius; + sofa::core::objectmodel::lifecycle::RenamedData f_radius; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_handleTopologyChange; + sofa::core::objectmodel::lifecycle::RenamedData f_handleTopologyChange; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_ignoreNotFound; + sofa::core::objectmodel::lifecycle::RenamedData f_ignoreNotFound; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData f_resizeToModel; + sofa::core::objectmodel::lifecycle::RenamedData f_resizeToModel; SetIndex d_indices; diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMultiMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMultiMapping.h index 75fe2fe440c..d80e95eb0ab 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMultiMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/SubsetMultiMapping.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::mapping::linear { @@ -66,7 +66,7 @@ class SubsetMultiMapping : public LinearMultiMapping virtual const type::vector* getJs() override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData< type::vector > indexPairs; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > indexPairs; Data< type::vector > d_indexPairs; ///< list of couples (parent index + index in the parent) diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/TubularMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/TubularMapping.h index 3802eb53063..a834febedfc 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/TubularMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/TubularMapping.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::mapping::linear { @@ -89,13 +89,13 @@ class TubularMapping : public LinearMapping void applyJT ( const core::ConstraintParams* /*cparams*/, InDataMatrixDeriv& dOut, const OutDataMatrixDeriv& dIn ) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData m_nbPointsOnEachCircle; + sofa::core::objectmodel::lifecycle::RenamedData m_nbPointsOnEachCircle; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData m_radius; + sofa::core::objectmodel::lifecycle::RenamedData m_radius; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_LINEAR() - sofa::core::objectmodel::RenamedData m_peak; + sofa::core::objectmodel::lifecycle::RenamedData m_peak; Data d_nbPointsOnEachCircle; ///< Discretization of created circles Data d_radius; ///< Radius of created circles diff --git a/Sofa/Component/Mapping/Linear/tests/BarycentricMapping_test.cpp b/Sofa/Component/Mapping/Linear/tests/BarycentricMapping_test.cpp index 668d3719f58..2f923ea9221 100644 --- a/Sofa/Component/Mapping/Linear/tests/BarycentricMapping_test.cpp +++ b/Sofa/Component/Mapping/Linear/tests/BarycentricMapping_test.cpp @@ -74,7 +74,7 @@ struct BarycentricMapperTriangleSetTopologyTest : public BaseTest, public Baryc typename Out::VecCoord m_out; TriangleSetTopologyContainer::SPtr m_topology; - void SetUp() override + void doSetUp() override { m_in.push_back(Vec3(0.5, 1.5, 0.0)); m_in.push_back(Vec3(1.5, 0.0, 2.5)); diff --git a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceFromTargetMapping.h b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceFromTargetMapping.h index 3731851cd3a..615537ab7c4 100644 --- a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceFromTargetMapping.h +++ b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceFromTargetMapping.h @@ -30,7 +30,7 @@ #include #include -#include +#include namespace sofa::component::mapping::nonlinear { @@ -77,13 +77,13 @@ class DistanceFromTargetMapping : public BaseNonLinearMapping, typedef type::Vec Direction; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData> f_indices; + sofa::core::objectmodel::lifecycle::RenamedData> f_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData f_targetPositions; + sofa::core::objectmodel::lifecycle::RenamedData f_targetPositions; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData> f_restDistances; + sofa::core::objectmodel::lifecycle::RenamedData> f_restDistances; // d_showObjectScale and d_color are already up-to-date with the new naming convention, so they do not require deprecation notices. diff --git a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMapping.h b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMapping.h index df197ab65d9..7f2296efb23 100644 --- a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMapping.h +++ b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMapping.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::mapping::nonlinear { @@ -62,10 +62,10 @@ class DistanceMapping : public BaseNonLinearMapping typedef type::Vec Direction; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData f_computeDistance; + sofa::core::objectmodel::lifecycle::RenamedData f_computeDistance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData> f_restLengths; + sofa::core::objectmodel::lifecycle::RenamedData> f_restLengths; Data d_computeDistance; ///< if 'computeDistance = true', then rest length of each element equal 0, otherwise rest length is the initial length of each of them diff --git a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMultiMapping.h b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMultiMapping.h index fed60bcd234..1f78b1868e2 100644 --- a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMultiMapping.h +++ b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/DistanceMultiMapping.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::mapping::nonlinear { @@ -77,10 +77,10 @@ class DistanceMultiMapping : public core::MultiMapping, public Stabil typedef type::Vec Direction; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData f_computeDistance; + sofa::core::objectmodel::lifecycle::RenamedData f_computeDistance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MAPPING_NONLINEAR() - sofa::core::objectmodel::RenamedData> f_restLengths; + sofa::core::objectmodel::lifecycle::RenamedData> f_restLengths; Data d_computeDistance; ///< if 'computeDistance = true', then rest length of each element equal 0, otherwise rest length is the initial length of each of them Data> d_restLengths; ///< Rest lengths of the connections diff --git a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.inl b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.inl index fa2d0f1911c..195d6803c96 100644 --- a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.inl +++ b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.inl @@ -772,8 +772,11 @@ void RigidMapping::setJMatrixBlock(unsigned outIdx, unsigned inIdx) template void RigidMapping::draw(const core::visual::VisualParams* vparams) { - if (!vparams->displayFlags().getShowMappings() || this->toModel==nullptr ) + if (!vparams->displayFlags().getShowMappings() || !this->toModel ) return; + + [[maybe_unused]] const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); + std::vector points; type::Vec3 point; diff --git a/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp b/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp index 630add17ad0..d18e3bbf623 100644 --- a/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp +++ b/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp @@ -74,7 +74,7 @@ struct RigidMappingTest : public sofa::mapping_test::Mapping_test<_RigidMapping> typedef typename OutMechanicalObject::ReadVecCoord ReadOutVecCoord; typedef typename OutMechanicalObject::ReadVecDeriv ReadOutVecDeriv; - void SetUp() override + void doSetUp() override { } diff --git a/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp b/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp index a837a54366f..f62537fceb7 100644 --- a/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp +++ b/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp @@ -150,11 +150,11 @@ struct SquareDistanceMappingCompare_test : NumericTest simulation::Node::SPtr oneMapping; simulation::Node::SPtr twoMappings; - void onSetUp() override + void doSetUp() override { root = simulation::getSimulation()->createNewNode("root"); - simpleapi::createObject(root, "RequiredPlugin", {{"pluginName", "Sofa.Component"}}); + simpleapi::createObject(root, "RequiredPlugin", {{"pluginName", Sofa.Component}}); simpleapi::createObject(root, "DefaultAnimationLoop"); simpleapi::createObject(root, "StringMeshCreator", {{"name", "loader"}, {"resolution", "3"}}); diff --git a/Sofa/Component/Mapping/src/sofa/component/mapping/init.cpp b/Sofa/Component/Mapping/src/sofa/component/mapping/init.cpp index c3587764b84..82a3fa98dab 100644 --- a/Sofa/Component/Mapping/src/sofa/component/mapping/init.cpp +++ b/Sofa/Component/Mapping/src/sofa/component/mapping/init.cpp @@ -25,6 +25,7 @@ #include #include +#include namespace sofa::component::mapping { @@ -53,8 +54,8 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Mapping.Linear"); - factory->registerObjectsFromPlugin("Sofa.Component.Mapping.NonLinear"); + factory->registerObjectsFromPlugin(Sofa.Component.Mapping.Linear); + factory->registerObjectsFromPlugin(Sofa.Component.Mapping.NonLinear); } void init() diff --git a/Sofa/Component/Mass/tests/DiagonalMass_test.cpp b/Sofa/Component/Mass/tests/DiagonalMass_test.cpp index 2fa55643d95..ca3393caa9c 100644 --- a/Sofa/Component/Mass/tests/DiagonalMass_test.cpp +++ b/Sofa/Component/Mass/tests/DiagonalMass_test.cpp @@ -96,18 +96,18 @@ class DiagonalMass_test : public BaseTest typename MechanicalObject::SPtr mstate; typename DiagonalMass::SPtr mass; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Grid"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); simulation = simulation::getSimulation(); root = simulation::getSimulation()->createNewGraph("root"); } - void TearDown() override + void doTearDown() override { if (root!=nullptr) sofa::simulation::node::unload(root); diff --git a/Sofa/Component/Mass/tests/MeshMatrixMass_test.cpp b/Sofa/Component/Mass/tests/MeshMatrixMass_test.cpp index 024bf21dd13..5084b7eb1b2 100644 --- a/Sofa/Component/Mass/tests/MeshMatrixMass_test.cpp +++ b/Sofa/Component/Mass/tests/MeshMatrixMass_test.cpp @@ -99,18 +99,18 @@ class MeshMatrixMass_test : public BaseTest typename MechanicalObject::SPtr mstate; typename MeshMatrixMass::SPtr mass; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Grid"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); simulation = simulation::getSimulation(); root = simulation::getSimulation()->createNewGraph("root"); } - void TearDown() override + void doTearDown() override { if (root!=nullptr) sofa::simulation::node::unload(root); diff --git a/Sofa/Component/Mass/tests/UniformMass_test.cpp b/Sofa/Component/Mass/tests/UniformMass_test.cpp index ddfa5c0eabb..42243593dca 100644 --- a/Sofa/Component/Mass/tests/UniformMass_test.cpp +++ b/Sofa/Component/Mass/tests/UniformMass_test.cpp @@ -77,17 +77,17 @@ struct UniformMassTest : public BaseTest typename MechanicalObject::SPtr m_mecaobject; bool todo {true} ; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); todo = true ; m_simu = sofa::simulation::getSimulation(); m_root = m_simu->createNewGraph("root"); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr){ sofa::simulation::node::unload(m_root); diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/EdgePressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/EdgePressureForceField.h index 95b8792aced..e6243016b1e 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/EdgePressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/EdgePressureForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -83,37 +83,37 @@ class EdgePressureForceField : public core::behavior::ForceField sofa::core::topology::BaseMeshTopology* _completeTopology{nullptr}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > edgePressureMap; + sofa::core::objectmodel::lifecycle::RenamedData > edgePressureMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData pressure; + sofa::core::objectmodel::lifecycle::RenamedData pressure; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData >edgeIndices; + sofa::core::objectmodel::lifecycle::RenamedData >edgeIndices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > edges; + sofa::core::objectmodel::lifecycle::RenamedData > edges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData normal; + sofa::core::objectmodel::lifecycle::RenamedData normal; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmin; + sofa::core::objectmodel::lifecycle::RenamedData dmin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmax; + sofa::core::objectmodel::lifecycle::RenamedData dmax; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData arrowSizeCoef; + sofa::core::objectmodel::lifecycle::RenamedData arrowSizeCoef; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData< type::vector > p_intensity; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > p_intensity; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_binormal; + sofa::core::objectmodel::lifecycle::RenamedData p_binormal; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_showForces; + sofa::core::objectmodel::lifecycle::RenamedData p_showForces; Data d_pressure; ///< Pressure force per unit area Data > d_edgeIndices; ///< Indices of edges separated with commas where a pressure is applied diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/OscillatingTorsionPressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/OscillatingTorsionPressureForceField.h index 79d1d44fbe6..6328bec72d1 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/OscillatingTorsionPressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/OscillatingTorsionPressureForceField.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -84,34 +84,34 @@ class OscillatingTorsionPressureForceField : public core::behavior::ForceField > trianglePressureMap; + sofa::core::objectmodel::lifecycle::RenamedData > trianglePressureMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData moment; + sofa::core::objectmodel::lifecycle::RenamedData moment; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > triangleList; + sofa::core::objectmodel::lifecycle::RenamedData > triangleList; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData axis; + sofa::core::objectmodel::lifecycle::RenamedData axis; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData center; + sofa::core::objectmodel::lifecycle::RenamedData center; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData penalty; + sofa::core::objectmodel::lifecycle::RenamedData penalty; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData frequency; + sofa::core::objectmodel::lifecycle::RenamedData frequency; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmin; + sofa::core::objectmodel::lifecycle::RenamedData dmin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmax; + sofa::core::objectmodel::lifecycle::RenamedData dmax; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_showForces; + sofa::core::objectmodel::lifecycle::RenamedData p_showForces; sofa::core::topology::TriangleSubsetData > d_trianglePressureMap; ///< Map between triangle indices and their pressure diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/QuadPressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/QuadPressureForceField.h index dbd9bb1acb9..39e42d3c37b 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/QuadPressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/QuadPressureForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -55,22 +55,22 @@ class QuadPressureForceField : public core::behavior::ForceField using Index = sofa::Index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData pressure; + sofa::core::objectmodel::lifecycle::RenamedData pressure; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData> quadList; + sofa::core::objectmodel::lifecycle::RenamedData> quadList; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData normal; + sofa::core::objectmodel::lifecycle::RenamedData normal; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmin; + sofa::core::objectmodel::lifecycle::RenamedData dmin; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData dmax; + sofa::core::objectmodel::lifecycle::RenamedData dmax; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_showForces; + sofa::core::objectmodel::lifecycle::RenamedData p_showForces; Data d_pressure; ///< Pressure force per unit area @@ -119,7 +119,7 @@ class QuadPressureForceField : public core::behavior::ForceField } }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > quadPressureMap; + sofa::core::objectmodel::lifecycle::RenamedData > quadPressureMap; sofa::core::topology::QuadSubsetData > d_quadPressureMap; ///< Map between quad indices and their pressure diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SphereForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SphereForceField.h index 91ab0c73428..993afb57855 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SphereForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SphereForceField.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::mechanicalload { @@ -84,7 +84,7 @@ class SphereForceField : public core::behavior::ForceField }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > contacts; + sofa::core::objectmodel::lifecycle::RenamedData > contacts; Data > d_contacts; ///< Contacts @@ -94,25 +94,25 @@ class SphereForceField : public core::behavior::ForceField SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData sphereCenter; + sofa::core::objectmodel::lifecycle::RenamedData sphereCenter; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData sphereRadius; + sofa::core::objectmodel::lifecycle::RenamedData sphereRadius; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData stiffness; + sofa::core::objectmodel::lifecycle::RenamedData stiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData damping; + sofa::core::objectmodel::lifecycle::RenamedData damping; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData color; + sofa::core::objectmodel::lifecycle::RenamedData color; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData> localRange; + sofa::core::objectmodel::lifecycle::RenamedData> localRange; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData bilateral; + sofa::core::objectmodel::lifecycle::RenamedData bilateral; Data d_sphereCenter; ///< sphere center diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SurfacePressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SurfacePressureForceField.h index 5678ad7474d..b8a17afd690 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SurfacePressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/SurfacePressureForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::core::topology { @@ -71,43 +71,43 @@ class SurfacePressureForceField : public core::behavior::ForceField enum State { INCREASE, DECREASE }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_pressure; + sofa::core::objectmodel::lifecycle::RenamedData m_pressure; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_min; + sofa::core::objectmodel::lifecycle::RenamedData m_min; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_max; + sofa::core::objectmodel::lifecycle::RenamedData m_max; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_triangleIndices; + sofa::core::objectmodel::lifecycle::RenamedData m_triangleIndices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_quadIndices; + sofa::core::objectmodel::lifecycle::RenamedData m_quadIndices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_pulseMode; + sofa::core::objectmodel::lifecycle::RenamedData m_pulseMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_pressureLowerBound; + sofa::core::objectmodel::lifecycle::RenamedData m_pressureLowerBound; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_pressureSpeed; + sofa::core::objectmodel::lifecycle::RenamedData m_pressureSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_volumeConservationMode; + sofa::core::objectmodel::lifecycle::RenamedData m_volumeConservationMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_useTangentStiffness; + sofa::core::objectmodel::lifecycle::RenamedData m_useTangentStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_defaultVolume; + sofa::core::objectmodel::lifecycle::RenamedData m_defaultVolume; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_mainDirection; + sofa::core::objectmodel::lifecycle::RenamedData m_mainDirection; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_drawForceScale; + sofa::core::objectmodel::lifecycle::RenamedData m_drawForceScale; Data d_pressure; ///< Pressure force per unit area Data d_min; ///< Lower bound of the selection box diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TaitSurfacePressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TaitSurfacePressureForceField.h index dc41b36c794..98b4cb8ed60 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TaitSurfacePressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TaitSurfacePressureForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -74,58 +74,58 @@ class TaitSurfacePressureForceField : public core::behavior::ForceField m_p0; + sofa::core::objectmodel::lifecycle::RenamedData m_p0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_B; + sofa::core::objectmodel::lifecycle::RenamedData m_B; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_gamma; + sofa::core::objectmodel::lifecycle::RenamedData m_gamma; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_injectedVolume; + sofa::core::objectmodel::lifecycle::RenamedData m_injectedVolume; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_maxInjectionRate; + sofa::core::objectmodel::lifecycle::RenamedData m_maxInjectionRate; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_initialVolume; + sofa::core::objectmodel::lifecycle::RenamedData m_initialVolume; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_currentInjectedVolume; + sofa::core::objectmodel::lifecycle::RenamedData m_currentInjectedVolume; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_v0; + sofa::core::objectmodel::lifecycle::RenamedData m_v0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_currentVolume; + sofa::core::objectmodel::lifecycle::RenamedData m_currentVolume; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_currentPressure; + sofa::core::objectmodel::lifecycle::RenamedData m_currentPressure; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_currentStiffness; + sofa::core::objectmodel::lifecycle::RenamedData m_currentStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_pressureTriangles; + sofa::core::objectmodel::lifecycle::RenamedData m_pressureTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_initialSurfaceArea; + sofa::core::objectmodel::lifecycle::RenamedData m_initialSurfaceArea; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_currentSurfaceArea; + sofa::core::objectmodel::lifecycle::RenamedData m_currentSurfaceArea; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_drawForceScale; + sofa::core::objectmodel::lifecycle::RenamedData m_drawForceScale; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_drawForceColor; + sofa::core::objectmodel::lifecycle::RenamedData m_drawForceColor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_volumeAfterTC; + sofa::core::objectmodel::lifecycle::RenamedData m_volumeAfterTC; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_surfaceAreaAfterTC; + sofa::core::objectmodel::lifecycle::RenamedData m_surfaceAreaAfterTC; Data< Real > d_p0; ///< IN: Rest pressure when V = V0 diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TorsionForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TorsionForceField.h index d21708b69eb..d727c51636d 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TorsionForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TorsionForceField.h @@ -30,7 +30,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -86,16 +86,16 @@ class TorsionForceField : public ForceField public : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_indices; + sofa::core::objectmodel::lifecycle::RenamedData m_indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_torque; + sofa::core::objectmodel::lifecycle::RenamedData m_torque; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_axis; + sofa::core::objectmodel::lifecycle::RenamedData m_axis; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData m_origin; + sofa::core::objectmodel::lifecycle::RenamedData m_origin; Data d_indices; ///< indices of the selected points Data d_torque; ///< torque to apply diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TrianglePressureForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TrianglePressureForceField.h index 15dc6cebe69..348503e847c 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TrianglePressureForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/TrianglePressureForceField.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::mechanicalload { @@ -52,19 +52,19 @@ class TrianglePressureForceField : public core::behavior::ForceField using Index = sofa::Index; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData pressure; + sofa::core::objectmodel::lifecycle::RenamedData pressure; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData cauchyStress; + sofa::core::objectmodel::lifecycle::RenamedData cauchyStress; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData > triangleList; + sofa::core::objectmodel::lifecycle::RenamedData > triangleList; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_showForces; + sofa::core::objectmodel::lifecycle::RenamedData p_showForces; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData p_useConstantForce; + sofa::core::objectmodel::lifecycle::RenamedData p_useConstantForce; Data d_pressure; ///< Pressure force per unit area diff --git a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/UniformVelocityDampingForceField.h b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/UniformVelocityDampingForceField.h index dc0fdcef2ea..f297f3916c7 100644 --- a/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/UniformVelocityDampingForceField.h +++ b/Sofa/Component/MechanicalLoad/src/sofa/component/mechanicalload/UniformVelocityDampingForceField.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::mechanicalload { @@ -49,7 +49,7 @@ class UniformVelocityDampingForceField : public core::behavior::ForceField DataVecDeriv; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_MECHANICALLOAD() - sofa::core::objectmodel::RenamedData< Real > dampingCoefficient; + sofa::core::objectmodel::lifecycle::RenamedData< Real > dampingCoefficient; /// air drag coefficient. Data< Real > d_dampingCoefficient; diff --git a/Sofa/Component/MechanicalLoad/tests/ConstantForceField_test.cpp b/Sofa/Component/MechanicalLoad/tests/ConstantForceField_test.cpp index a901c1ec931..8785f12c84b 100644 --- a/Sofa/Component/MechanicalLoad/tests/ConstantForceField_test.cpp +++ b/Sofa/Component/MechanicalLoad/tests/ConstantForceField_test.cpp @@ -72,16 +72,16 @@ struct ConstantForceField_test : public BaseSimulationTest, NumericTest TheMechanicalObject; using Real = typename DataTypes::Coord::value_type; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.MechanicalLoad"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.MechanicalLoad); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); } - void TearDown() override {} + void doTearDown() override {} void testSimpleBehavior() { diff --git a/Sofa/Component/MechanicalLoad/tests/PlaneForceField_test.cpp b/Sofa/Component/MechanicalLoad/tests/PlaneForceField_test.cpp index 5459c9291a9..2cad132b962 100644 --- a/Sofa/Component/MechanicalLoad/tests/PlaneForceField_test.cpp +++ b/Sofa/Component/MechanicalLoad/tests/PlaneForceField_test.cpp @@ -116,13 +116,13 @@ struct PlaneForceField_test : public BaseSimulationTest * by the plane force field. * In the special case where : stiffness = 500, damping = 5 and maxForce = 0 (default values) */ - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.MechanicalLoad"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.MechanicalLoad); } - void TearDown() override {} + void doTearDown() override {} void setupDefaultScene() { diff --git a/Sofa/Component/MechanicalLoad/tests/SkeletalMotionConstraint_test.cpp b/Sofa/Component/MechanicalLoad/tests/SkeletalMotionConstraint_test.cpp index 51c8db83051..b91c76a8d01 100644 --- a/Sofa/Component/MechanicalLoad/tests/SkeletalMotionConstraint_test.cpp +++ b/Sofa/Component/MechanicalLoad/tests/SkeletalMotionConstraint_test.cpp @@ -67,7 +67,7 @@ struct SkeletalMotionProjectiveConstraint_test : public BaseSimulationTest, Nume typename MechanicalObject::SPtr dofs; /// Create the context for the tests. - void SetUp() override + void doSetUp() override { simulation = sofa::simulation::getSimulation(); @@ -167,7 +167,7 @@ struct SkeletalMotionProjectiveConstraint_test : public BaseSimulationTest, Nume return succeed; } - void TearDown() override + void doTearDown() override { if (root!=nullptr) sofa::simulation::node::unload(root); diff --git a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h index 3dbece65c3b..ccebff28494 100644 --- a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h +++ b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h @@ -25,7 +25,7 @@ #include -#include +#include namespace sofa::component::odesolver::backward { @@ -104,20 +104,20 @@ class SOFA_COMPONENT_ODESOLVER_BACKWARD_API EulerImplicitSolver : SOFA_CLASS2(EulerImplicitSolver, sofa::core::behavior::OdeSolver, sofa::core::behavior::LinearSolverAccessor); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_rayleighStiffness; + sofa::core::objectmodel::lifecycle::RenamedData f_rayleighStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_rayleighMass; + sofa::core::objectmodel::lifecycle::RenamedData f_rayleighMass; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_velocityDamping; + sofa::core::objectmodel::lifecycle::RenamedData f_velocityDamping; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_firstOrder; + sofa::core::objectmodel::lifecycle::RenamedData f_firstOrder; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_solveConstraint; + sofa::core::objectmodel::lifecycle::RenamedData f_solveConstraint; diff --git a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/VariationalSymplecticSolver.h b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/VariationalSymplecticSolver.h index 8e46bb57664..37e2a66ee6b 100644 --- a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/VariationalSymplecticSolver.h +++ b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/VariationalSymplecticSolver.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::odesolver::backward { @@ -46,34 +46,34 @@ class SOFA_COMPONENT_ODESOLVER_BACKWARD_API VariationalSymplecticSolver SOFA_CLASS2(VariationalSymplecticSolver, sofa::core::behavior::OdeSolver, sofa::core::behavior::LinearSolverAccessor); SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_newtonError; + sofa::core::objectmodel::lifecycle::RenamedData f_newtonError; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_newtonSteps; + sofa::core::objectmodel::lifecycle::RenamedData f_newtonSteps; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_rayleighStiffness; + sofa::core::objectmodel::lifecycle::RenamedData f_rayleighStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_rayleighMass; + sofa::core::objectmodel::lifecycle::RenamedData f_rayleighMass; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_saveEnergyInFile; + sofa::core::objectmodel::lifecycle::RenamedData f_saveEnergyInFile; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_explicit; + sofa::core::objectmodel::lifecycle::RenamedData f_explicit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_fileName; + sofa::core::objectmodel::lifecycle::RenamedData f_fileName; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_computeHamiltonian; + sofa::core::objectmodel::lifecycle::RenamedData f_computeHamiltonian; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_hamiltonianEnergy; + sofa::core::objectmodel::lifecycle::RenamedData f_hamiltonianEnergy; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_BACKWARD() - sofa::core::objectmodel::RenamedData f_useIncrementalPotentialEnergy; + sofa::core::objectmodel::lifecycle::RenamedData f_useIncrementalPotentialEnergy; Data d_newtonError; ///< Error tolerance for Newton iterations Data d_newtonSteps; ///< Maximum number of Newton steps diff --git a/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolverStatic_test.cpp b/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolverStatic_test.cpp index 6d6a88d522d..30c8c945c9d 100644 --- a/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolverStatic_test.cpp +++ b/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolverStatic_test.cpp @@ -103,12 +103,12 @@ struct EulerImplicit_test_2_particles_to_equilibrium : public BaseSimulationTest const simulation::Node::SPtr root = simpleapi::createRootNode(simu, "root"); //******* // begin create scene under the root node - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Projective"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.Spring); // remove warnings simpleapi::createObject(root, "DefaultAnimationLoop", {}); @@ -201,12 +201,12 @@ struct EulerImplicit_test_2_particles_in_different_nodes_to_equilibrium : publi // create scene root->setGravity(Vec3(0,0,0)); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Projective"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.Spring); // remove warnings simpleapi::createObject(root, "DefaultAnimationLoop", {}); simpleapi::createObject(root, "DefaultVisualManagerLoop", {}); diff --git a/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolver_withDamping_test.cpp b/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolver_withDamping_test.cpp index dc1089ed0a7..25f18328d7c 100644 --- a/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolver_withDamping_test.cpp +++ b/Sofa/Component/ODESolver/Backward/tests/EulerImplicitSolver_withDamping_test.cpp @@ -57,11 +57,11 @@ struct EulerImplicit_with_damping_forcefield : public BaseSimulationTest, Numeri //******* // load appropriate modules - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.MechanicalLoad"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.MechanicalLoad); // avoid warnings simpleapi::createObject(root, "DefaultAnimationLoop", {}); diff --git a/Sofa/Component/ODESolver/Backward/tests/SpringSolverDynamic_test.cpp b/Sofa/Component/ODESolver/Backward/tests/SpringSolverDynamic_test.cpp index 1425fb39be1..4a7ae8a587b 100644 --- a/Sofa/Component/ODESolver/Backward/tests/SpringSolverDynamic_test.cpp +++ b/Sofa/Component/ODESolver/Backward/tests/SpringSolverDynamic_test.cpp @@ -60,7 +60,7 @@ struct SpringSolverDynamic_test : public NumericTest /// Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); diff --git a/Sofa/Component/ODESolver/Backward/tests/StaticSolver_test.cpp b/Sofa/Component/ODESolver/Backward/tests/StaticSolver_test.cpp index 510b11bf89a..868b862de62 100644 --- a/Sofa/Component/ODESolver/Backward/tests/StaticSolver_test.cpp +++ b/Sofa/Component/ODESolver/Backward/tests/StaticSolver_test.cpp @@ -51,11 +51,11 @@ static constexpr SReal l = youngModulus * poissonRatio / ((1.0 + poissonRatio) * class StaticSolverTest : public sofa::testing::BaseTest { public: - void onSetUp() override { + void doSetUp() override { root = getSimulation()->createNewNode("root"); - createObject(root, "RequiredPlugin", {{"pluginName", "Sofa.Component"}}); + createObject(root, "RequiredPlugin", {{"pluginName", Sofa.Component}}); createObject(root, "DefaultAnimationLoop"); createObject(root, "RegularGridTopology", {{"name", "grid"}, {"min", "-7.5 -7.5 0"}, {"max", "7.5 7.5 80"}, {"n", "3 3 9"}}); const auto s = createObject(root, "StaticSolver", {{"newton_iterations", "10"}}); @@ -83,7 +83,7 @@ class StaticSolverTest : public sofa::testing::BaseTest solver = dynamic_cast (s.get()); } - void onTearDown() override { + void doTearDown() override { sofa::simulation::node::unload(root); } diff --git a/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/CentralDifferenceSolver.h b/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/CentralDifferenceSolver.h index 62416f6a63d..592bbb2c960 100644 --- a/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/CentralDifferenceSolver.h +++ b/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/CentralDifferenceSolver.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::odesolver::forward { @@ -44,7 +44,7 @@ class SOFA_COMPONENT_ODESOLVER_FORWARD_API CentralDifferenceSolver : public sofa public: void solve (const core::ExecParams* params, SReal dt, sofa::core::MultiVecCoordId xResult, sofa::core::MultiVecDerivId vResult) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_FORWARD() - sofa::core::objectmodel::RenamedData f_rayleighMass; + sofa::core::objectmodel::lifecycle::RenamedData f_rayleighMass; Data d_rayleighMass; ///< Rayleigh damping coefficient related to mass Data d_threadSafeVisitor; ///< If true, do not use realloc and free visitors in fwdInteractionForceField. diff --git a/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/DampVelocitySolver.h b/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/DampVelocitySolver.h index de737b83789..ddfe643f313 100644 --- a/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/DampVelocitySolver.h +++ b/Sofa/Component/ODESolver/Forward/src/sofa/component/odesolver/forward/DampVelocitySolver.h @@ -25,7 +25,7 @@ #include -#include +#include namespace sofa::component::odesolver::forward { @@ -37,10 +37,10 @@ class SOFA_COMPONENT_ODESOLVER_FORWARD_API DampVelocitySolver : public sofa::cor { public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_FORWARD() - sofa::core::objectmodel::RenamedData rate; + sofa::core::objectmodel::lifecycle::RenamedData rate; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_ODESOLVER_FORWARD() - sofa::core::objectmodel::RenamedData threshold; + sofa::core::objectmodel::lifecycle::RenamedData threshold; SOFA_CLASS(DampVelocitySolver, sofa::core::behavior::OdeSolver); diff --git a/Sofa/Component/ODESolver/Testing/src/sofa/component/odesolver/testing/ODESolverSpringTest.h b/Sofa/Component/ODESolver/Testing/src/sofa/component/odesolver/testing/ODESolverSpringTest.h index 8d1cd2c5ad0..d86e90e1d09 100644 --- a/Sofa/Component/ODESolver/Testing/src/sofa/component/odesolver/testing/ODESolverSpringTest.h +++ b/Sofa/Component/ODESolver/Testing/src/sofa/component/odesolver/testing/ODESolverSpringTest.h @@ -21,6 +21,7 @@ ******************************************************************************/ #pragma once +#include #include using sofa::testing::BaseSimulationTest; @@ -43,12 +44,12 @@ struct ODESolverSpringTest : public BaseSimulationTest // Create the scene m_si.root->setGravity({ 0, -10, 0 }); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Projective"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.Spring); // remove warnings simpleapi::createObject(m_si.root, "DefaultAnimationLoop", {}); diff --git a/Sofa/Component/ODESolver/src/sofa/component/odesolver/init.cpp b/Sofa/Component/ODESolver/src/sofa/component/odesolver/init.cpp index 7f06baa6206..4c86bf81b18 100644 --- a/Sofa/Component/ODESolver/src/sofa/component/odesolver/init.cpp +++ b/Sofa/Component/ODESolver/src/sofa/component/odesolver/init.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace sofa::component::odesolver { @@ -54,8 +55,8 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.ODESolver.Backward"); - factory->registerObjectsFromPlugin("Sofa.Component.ODESolver.Forward"); + factory->registerObjectsFromPlugin(Sofa.Component.ODESolver.Backward); + factory->registerObjectsFromPlugin(Sofa.Component.ODESolver.Forward); } void init() diff --git a/Sofa/Component/Playback/src/sofa/component/playback/InputEventReader.h b/Sofa/Component/Playback/src/sofa/component/playback/InputEventReader.h index 6eb0e713c4f..3487ea8ee02 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/InputEventReader.h +++ b/Sofa/Component/Playback/src/sofa/component/playback/InputEventReader.h @@ -32,7 +32,7 @@ #include #endif -#include +#include namespace sofa::component::playback { @@ -78,19 +78,19 @@ class InputEventReader : public core::objectmodel::BaseObject sofa::core::objectmodel::DataFileName filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData inverseSense; + sofa::core::objectmodel::lifecycle::RenamedData inverseSense; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData p_printEvent; + sofa::core::objectmodel::lifecycle::RenamedData p_printEvent; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData p_key1; + sofa::core::objectmodel::lifecycle::RenamedData p_key1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData p_key2; + sofa::core::objectmodel::lifecycle::RenamedData p_key2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData p_writeEvents; + sofa::core::objectmodel::lifecycle::RenamedData p_writeEvents; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() sofa::core::objectmodel::DataFileName p_outputFilename; diff --git a/Sofa/Component/Playback/src/sofa/component/playback/ReadTopology.h b/Sofa/Component/Playback/src/sofa/component/playback/ReadTopology.h index abd7f4e23f4..f3ab73eca18 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/ReadTopology.h +++ b/Sofa/Component/Playback/src/sofa/component/playback/ReadTopology.h @@ -34,7 +34,7 @@ #include #include -#include +#include namespace sofa::component::playback { @@ -50,13 +50,13 @@ class SOFA_COMPONENT_PLAYBACK_API ReadTopology: public core::objectmodel::BaseOb sofa::core::objectmodel::DataFileName f_filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < double > f_interval; + sofa::core::objectmodel::lifecycle::RenamedData < double > f_interval; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < double > f_shift; + sofa::core::objectmodel::lifecycle::RenamedData < double > f_shift; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < bool > f_loop; + sofa::core::objectmodel::lifecycle::RenamedData < bool > f_loop; sofa::core::objectmodel::DataFileName d_filename; Data < double > d_interval; ///< time duration between inputs diff --git a/Sofa/Component/Playback/src/sofa/component/playback/WriteTopology.h b/Sofa/Component/Playback/src/sofa/component/playback/WriteTopology.h index 77706b00a7a..623d33ac0c6 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/WriteTopology.h +++ b/Sofa/Component/Playback/src/sofa/component/playback/WriteTopology.h @@ -38,7 +38,7 @@ #include -#include +#include namespace sofa::component::playback { @@ -61,19 +61,19 @@ class SOFA_COMPONENT_PLAYBACK_API WriteTopology: public core::objectmodel::BaseO sofa::core::objectmodel::DataFileName f_filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < bool > f_writeContainers; + sofa::core::objectmodel::lifecycle::RenamedData < bool > f_writeContainers; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < bool > f_writeShellContainers; + sofa::core::objectmodel::lifecycle::RenamedData < bool > f_writeShellContainers; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < double > f_interval; + sofa::core::objectmodel::lifecycle::RenamedData < double > f_interval; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < type::vector > f_time; + sofa::core::objectmodel::lifecycle::RenamedData < type::vector > f_time; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() - sofa::core::objectmodel::RenamedData < double > f_period; + sofa::core::objectmodel::lifecycle::RenamedData < double > f_period; sofa::core::objectmodel::DataFileName d_filename; diff --git a/Sofa/Component/Playback/tests/ReadState_test.cpp b/Sofa/Component/Playback/tests/ReadState_test.cpp index 67f543ea851..967d7a7579d 100644 --- a/Sofa/Component/Playback/tests/ReadState_test.cpp +++ b/Sofa/Component/Playback/tests/ReadState_test.cpp @@ -37,8 +37,8 @@ class ReadState_test : public BaseSimulationTest const double dt = 0.01; const auto simulation = sofa::simpleapi::createSimulation(); const Node::SPtr root = sofa::simpleapi::createRootNode(simulation, "root"); - sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name","Sofa.Component.Playback" } }); - sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name","Sofa.Component.StateContainer" } }); + sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name",Sofa.Component.Playback } }); + sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name",Sofa.Component.StateContainer } }); /// no need of gravity, the file .data is just read root->setGravity(Vec3(0.0,0.0,0.0)); @@ -68,8 +68,8 @@ class ReadState_test : public BaseSimulationTest { const auto simulation = sofa::simpleapi::createSimulation(); const Node::SPtr root = sofa::simpleapi::createRootNode(simulation, "root"); - sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name","Sofa.Component.Playback" } }); - sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name","Sofa.Component.StateContainer" } }); + sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name",Sofa.Component.Playback } }); + sofa::simpleapi::createObject(root, "RequiredPlugin", { { "name",Sofa.Component.StateContainer } }); auto meca = sofa::simpleapi::createObject(root, "MechanicalObject", {{"size", "1"}}); diff --git a/Sofa/Component/Playback/tests/WriteState_test.cpp b/Sofa/Component/Playback/tests/WriteState_test.cpp index 909a091c983..d0b92f7f4e8 100644 --- a/Sofa/Component/Playback/tests/WriteState_test.cpp +++ b/Sofa/Component/Playback/tests/WriteState_test.cpp @@ -71,7 +71,7 @@ namespace sofa { double final_expected_value=0.0; /// Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation root = simulation::getSimulation()->createNewGraph("root"); @@ -220,7 +220,7 @@ namespace sofa { /// Unload the scene - void TearDown() override + void doTearDown() override { if (root!=nullptr) sofa::simulation::node::unload(root); @@ -237,26 +237,22 @@ namespace sofa { // Test 1 : write position of a particle falling under gravity (required to use SymplecticSolver TYPED_TEST( WriteState_test , test_write_position) { - this->SetUp(); this->createScene(true); this->initScene(); this->runScene(); ASSERT_TRUE( this->simulation_result_test(true) ); ASSERT_TRUE( this->test_export(true) ); - this->TearDown(); } // Test 2 : write velocity of a particle falling under gravity TYPED_TEST( WriteState_test , test_write_velocity) { - this->SetUp(); this->createScene(false); this->initScene(); this->runScene(); ASSERT_TRUE( this->simulation_result_test(false) ); ASSERT_TRUE( this->test_export(false) ); - this->TearDown(); } } diff --git a/Sofa/Component/SceneUtility/tests/AddResourceRepository_test.cpp b/Sofa/Component/SceneUtility/tests/AddResourceRepository_test.cpp index c7bebda42a6..5d8a3d596af 100644 --- a/Sofa/Component/SceneUtility/tests/AddResourceRepository_test.cpp +++ b/Sofa/Component/SceneUtility/tests/AddResourceRepository_test.cpp @@ -44,9 +44,9 @@ struct AddResourceRepository_test : public BaseSimulationTest sofa::simulation::Node::SPtr m_root; std::string m_testRepoDir; - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); + sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); m_testRepoDir = std::string(SOFA_COMPONENT_SCENEUTILITY_TEST_RESOURCES_DIR) + std::string("/repo"); } diff --git a/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp b/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp index e442de84203..552ad09b95a 100644 --- a/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp +++ b/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp @@ -72,7 +72,7 @@ bool inited = doInit(); void perTestInit() { - sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); + sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); theSimulation = sofa::simulation::getSimulation(); diff --git a/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp b/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp index 15aaa483a2f..7a36ee55625 100644 --- a/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp +++ b/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp @@ -72,8 +72,8 @@ bool inited = doInit(); void perTestInit() { - sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); if(defaultHandler==nullptr) defaultHandler=new ConsoleMessageHandler(&RichConsoleStyleMessageFormatter::getInstance()) ; diff --git a/Sofa/Component/SceneUtility/tests/MessageHandlerComponent_test.cpp b/Sofa/Component/SceneUtility/tests/MessageHandlerComponent_test.cpp index 6cf6bbd792f..542ebc512b8 100644 --- a/Sofa/Component/SceneUtility/tests/MessageHandlerComponent_test.cpp +++ b/Sofa/Component/SceneUtility/tests/MessageHandlerComponent_test.cpp @@ -45,7 +45,7 @@ using sofa::helper::logging::MessageDispatcher ; bool perTestInit() { - sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); + sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); /// THE TESTS HERE ARE NOT INHERITING FROM SOFA TEST SO WE NEED TO MANUALLY INSTALL THE HANDLER /// DO NO REMOVE diff --git a/Sofa/Component/Setting/src/sofa/component/setting/BackgroundSetting.h b/Sofa/Component/Setting/src/sofa/component/setting/BackgroundSetting.h index 7a6e255b84e..f59bbb24dbc 100644 --- a/Sofa/Component/Setting/src/sofa/component/setting/BackgroundSetting.h +++ b/Sofa/Component/Setting/src/sofa/component/setting/BackgroundSetting.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::setting { @@ -42,7 +42,7 @@ class SOFA_COMPONENT_SETTING_API BackgroundSetting: public core::objectmodel::Co public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData color; + sofa::core::objectmodel::lifecycle::RenamedData color; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() sofa::core::objectmodel::DataFileName image; ///< Image to be used as background of the viewer. diff --git a/Sofa/Component/Setting/src/sofa/component/setting/MouseButtonSetting.h b/Sofa/Component/Setting/src/sofa/component/setting/MouseButtonSetting.h index 90c6cafb22b..e7df8c36482 100644 --- a/Sofa/Component/Setting/src/sofa/component/setting/MouseButtonSetting.h +++ b/Sofa/Component/Setting/src/sofa/component/setting/MouseButtonSetting.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::setting { @@ -41,7 +41,7 @@ class SOFA_COMPONENT_SETTING_API MouseButtonSetting: public core::objectmodel::C virtual std::string getOperationType()=0; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData button; + sofa::core::objectmodel::lifecycle::RenamedData button; core::objectmodel::Data d_button; ///< Mouse button used diff --git a/Sofa/Component/Setting/src/sofa/component/setting/SofaDefaultPathSetting.h b/Sofa/Component/Setting/src/sofa/component/setting/SofaDefaultPathSetting.h index 363375bd021..83a5e92abaa 100644 --- a/Sofa/Component/Setting/src/sofa/component/setting/SofaDefaultPathSetting.h +++ b/Sofa/Component/Setting/src/sofa/component/setting/SofaDefaultPathSetting.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::setting { @@ -40,7 +40,7 @@ class SOFA_COMPONENT_SETTING_API SofaDefaultPathSetting: public core::objectmode SofaDefaultPathSetting(); /// gnuplotPath; + sofa::core::objectmodel::lifecycle::RenamedData gnuplotPath; sofa::core::objectmodel::Data d_gnuplotPath; ///< Path where will be saved the gnuplot files }; diff --git a/Sofa/Component/Setting/src/sofa/component/setting/StatsSetting.h b/Sofa/Component/Setting/src/sofa/component/setting/StatsSetting.h index 00eaad3abd3..4be75cf01ac 100644 --- a/Sofa/Component/Setting/src/sofa/component/setting/StatsSetting.h +++ b/Sofa/Component/Setting/src/sofa/component/setting/StatsSetting.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::setting { @@ -49,13 +49,13 @@ class SOFA_COMPONENT_SETTING_API StatsSetting: public core::objectmodel::Configu public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData dumpState; + sofa::core::objectmodel::lifecycle::RenamedData dumpState; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData logTime; + sofa::core::objectmodel::lifecycle::RenamedData logTime; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData exportState; + sofa::core::objectmodel::lifecycle::RenamedData exportState; Data d_dumpState; ///< Dump state vectors at each time step of the simulation diff --git a/Sofa/Component/Setting/src/sofa/component/setting/ViewerSetting.h b/Sofa/Component/Setting/src/sofa/component/setting/ViewerSetting.h index b98967183e8..28625d1742d 100644 --- a/Sofa/Component/Setting/src/sofa/component/setting/ViewerSetting.h +++ b/Sofa/Component/Setting/src/sofa/component/setting/ViewerSetting.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::setting { @@ -52,16 +52,16 @@ class SOFA_COMPONENT_SETTING_API ViewerSetting: public sofa::core::objectmodel:: public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData > resolution; + sofa::core::objectmodel::lifecycle::RenamedData > resolution; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData fullscreen; + sofa::core::objectmodel::lifecycle::RenamedData fullscreen; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData cameraMode; + sofa::core::objectmodel::lifecycle::RenamedData cameraMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SETTING() - sofa::core::objectmodel::RenamedData objectPickingMethod; + sofa::core::objectmodel::lifecycle::RenamedData objectPickingMethod; Data > d_resolution; ///< resolution of the Viewer Data d_fullscreen; ///< Fullscreen mode diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.h index 6eba2d3fc3e..29b3f8144cb 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -132,7 +132,7 @@ class BeamFEMForceField : public BaseLinearElasticityFEMForceField }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> m_beamsData; + sofa::core::objectmodel::lifecycle::RenamedData> m_beamsData; EdgeData > d_beamsData; ///< Internal element data diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.inl index d7aa2c49ebc..10e7cb5e22e 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BeamFEMForceField.inl @@ -60,10 +60,7 @@ BeamFEMForceField::BeamFEMForceField(Real poissonRatio, Real youngMod , m_updateStiffnessMatrix(true) { d_radius.setRequired(true); - d_radiusInner.setRequired(true); - m_beamsData.setOriginalData(&d_beamsData); - this->setPoissonRatio(poissonRatio); this->setYoungModulus(youngModulus); } diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h index cc68dbf18a5..0f5fb51e58f 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -117,37 +117,37 @@ class FastTetrahedralCorotationalForceField : public BaseLinearElasticityFEMForc using VecMat3x3 = type::rebind_to; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData pointInfo; + sofa::core::objectmodel::lifecycle::RenamedData pointInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData edgeInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData tetrahedronInfo; + sofa::core::objectmodel::lifecycle::RenamedData tetrahedronInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() SOFA_ATTRIBUTE_DISABLED("", "v24.12", "Use d_youngModulus instead") DeprecatedAndRemoved f_youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_drawing; + sofa::core::objectmodel::lifecycle::RenamedData f_drawing; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor1; + sofa::core::objectmodel::lifecycle::RenamedData drawColor1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor2; + sofa::core::objectmodel::lifecycle::RenamedData drawColor2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor3; + sofa::core::objectmodel::lifecycle::RenamedData drawColor3; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor4; + sofa::core::objectmodel::lifecycle::RenamedData drawColor4; core::topology::PointData d_pointInfo; ///< Internal point data diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h index 8375c646bf4..49ae29b2640 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h @@ -30,7 +30,7 @@ #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -186,15 +186,15 @@ class HexahedralFEMForceField : virtual public BaseLinearElasticityFEMForceField int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DISABLED("", "v24.12", "Use d_youngModulus instead") DeprecatedAndRemoved f_youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > hexahedronInfo; + sofa::core::objectmodel::lifecycle::RenamedData > hexahedronInfo; Data d_method; ///< "large" or "polar" displacements diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.h index 012ce1f3433..f436dfd65c0 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceFieldAndMass.h @@ -28,7 +28,7 @@ #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -128,22 +128,22 @@ class HexahedralFEMForceFieldAndMass : virtual public sofa::core::behavior::Mass protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _density; + sofa::core::objectmodel::lifecycle::RenamedData _density; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _useLumpedMass; + sofa::core::objectmodel::lifecycle::RenamedData _useLumpedMass; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> _elementMasses; + sofa::core::objectmodel::lifecycle::RenamedData> _elementMasses; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > _elementTotalMass; + sofa::core::objectmodel::lifecycle::RenamedData > _elementTotalMass; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > _particleMasses; + sofa::core::objectmodel::lifecycle::RenamedData > _particleMasses; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > _lumpedMasses; + sofa::core::objectmodel::lifecycle::RenamedData > _lumpedMasses; Data d_density; ///< density == volumetric mass in english (kg.m-3) Data d_useLumpedMass; ///< Does it use lumped masses? diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h index 082f2ee9d76..92b4462cf3c 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -117,27 +117,27 @@ class HexahedronFEMForceField : virtual public BaseLinearElasticityFEMForceField int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DISABLED("", "v24.12", "Use d_youngModulus instead") DeprecatedAndRemoved f_youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_updateStiffnessMatrix; + sofa::core::objectmodel::lifecycle::RenamedData f_updateStiffnessMatrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData< sofa::helper::OptionsGroup > _gatherPt; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::helper::OptionsGroup > _gatherPt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData< sofa::helper::OptionsGroup > _gatherBsize; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::helper::OptionsGroup > _gatherBsize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_drawing; + sofa::core::objectmodel::lifecycle::RenamedData f_drawing; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_drawPercentageOffset; + sofa::core::objectmodel::lifecycle::RenamedData f_drawPercentageOffset; @@ -194,7 +194,7 @@ class HexahedronFEMForceField : virtual public BaseLinearElasticityFEMForceField typedef type::vector VecElementStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _elementStiffnesses; + sofa::core::objectmodel::lifecycle::RenamedData _elementStiffnesses; Data d_elementStiffnesses; ///< Stiffness matrices per element (K_i) @@ -207,7 +207,7 @@ class HexahedronFEMForceField : virtual public BaseLinearElasticityFEMForceField topology::container::grid::SparseGridTopology* _sparseGrid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _initialPoints; + sofa::core::objectmodel::lifecycle::RenamedData _initialPoints; Data< VecCoord > d_initialPoints; ///< Initial Position diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.h index 0c26029c00d..2e537911626 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/QuadBendingFEMForceField.h @@ -36,7 +36,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -170,13 +170,13 @@ class QuadBendingFEMForceField : public core::behavior::ForceField }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > quadInfo; + sofa::core::objectmodel::lifecycle::RenamedData > quadInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > vertexInfo; + sofa::core::objectmodel::lifecycle::RenamedData > vertexInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData > edgeInfo; /// Topology Data core::topology::QuadData > d_quadInfo; core::topology::PointData > d_vertexInfo; ///< Internal point data @@ -233,16 +233,16 @@ protected : int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> f_poisson; + sofa::core::objectmodel::lifecycle::RenamedData> f_poisson; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> f_young; + sofa::core::objectmodel::lifecycle::RenamedData> f_young; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_thickness; + sofa::core::objectmodel::lifecycle::RenamedData f_thickness; Data d_method; ///< large: large displacements, small: small displacements Data > d_poisson; ///< Poisson ratio in Hooke's law (vector) diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h index ff6292fed70..49bbc29ccf0 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h @@ -31,7 +31,7 @@ #include #include -#include +#include // corotational tetrahedron from // @InProceedings{NPF05, @@ -128,7 +128,7 @@ class TetrahedralCorotationalFEMForceField : public BaseLinearElasticityFEMForce }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > tetrahedronInfo; + sofa::core::objectmodel::lifecycle::RenamedData > tetrahedronInfo; /// container that stotes all requires information for each tetrahedron core::topology::TetrahedronData > d_tetrahedronInfo; @@ -151,37 +151,37 @@ class TetrahedralCorotationalFEMForceField : public BaseLinearElasticityFEMForce int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData _poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() SOFA_ATTRIBUTE_DISABLED("", "v24.12", "Use d_youngModulus instead") DeprecatedAndRemoved _youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _localStiffnessFactor; + sofa::core::objectmodel::lifecycle::RenamedData _localStiffnessFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _updateStiffnessMatrix; + sofa::core::objectmodel::lifecycle::RenamedData _updateStiffnessMatrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData _assembling; + sofa::core::objectmodel::lifecycle::RenamedData _assembling; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_drawing; + sofa::core::objectmodel::lifecycle::RenamedData f_drawing; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor1; + sofa::core::objectmodel::lifecycle::RenamedData drawColor1; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor2; + sofa::core::objectmodel::lifecycle::RenamedData drawColor2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor3; + sofa::core::objectmodel::lifecycle::RenamedData drawColor3; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData drawColor4; + sofa::core::objectmodel::lifecycle::RenamedData drawColor4; Data d_method; ///< "small", "large" (by QR) or "polar" displacements Data d_localStiffnessFactor; ///< Allow specification of different stiffness per element. If there are N element and M values are specified, the youngModulus factor for element i would be localStiffnessFactor[i*M/N] diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.h index 10652e50b37..f5e28dabc83 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedronFEMForceField.h @@ -33,7 +33,7 @@ #include #include -#include +#include // corotational tetrahedron from // @InProceedings{NPF05, @@ -189,28 +189,28 @@ class TetrahedronFEMForceField : public BaseLinearElasticityFEMForceField& getRotations() override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _initialPoints; + core::objectmodel::lifecycle::RenamedData _initialPoints; Data< VecCoord > d_initialPoints; ///< Initial Position int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData f_method; + core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() DeprecatedAndRemoved _poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _youngModulus; + core::objectmodel::lifecycle::RenamedData _youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _localStiffnessFactor; + core::objectmodel::lifecycle::RenamedData _localStiffnessFactor; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _updateStiffnessMatrix; + core::objectmodel::lifecycle::RenamedData _updateStiffnessMatrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _assembling; + core::objectmodel::lifecycle::RenamedData _assembling; Data d_method; ///< "small", "large" (by QR), "polar" or "svd" displacements @@ -219,13 +219,13 @@ class TetrahedronFEMForceField : public BaseLinearElasticityFEMForceField d_assembling; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _plasticMaxThreshold; + core::objectmodel::lifecycle::RenamedData _plasticMaxThreshold; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _plasticYieldThreshold; + core::objectmodel::lifecycle::RenamedData _plasticYieldThreshold; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _plasticCreep; + core::objectmodel::lifecycle::RenamedData _plasticCreep; /// @name Plasticity such as "Interactive Virtual Materials", Muller & Gross, GI 2004 /// @{ @@ -235,13 +235,13 @@ class TetrahedronFEMForceField : public BaseLinearElasticityFEMForceField _gatherPt; + core::objectmodel::lifecycle::RenamedData _gatherPt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _gatherBsize; + core::objectmodel::lifecycle::RenamedData _gatherBsize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData drawHeterogeneousTetra; + core::objectmodel::lifecycle::RenamedData drawHeterogeneousTetra; Data< sofa::helper::OptionsGroup > d_gatherPt; ///< number of dof accumulated per threads during the gather operation (Only use in GPU version) Data< sofa::helper::OptionsGroup > d_gatherBsize; ///< number of dof accumulated per threads during the gather operation (Only use in GPU version) @@ -259,16 +259,16 @@ class TetrahedronFEMForceField : public BaseLinearElasticityFEMForceField _computeVonMisesStress; + core::objectmodel::lifecycle::RenamedData _computeVonMisesStress; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData > _vonMisesPerElement; + core::objectmodel::lifecycle::RenamedData > _vonMisesPerElement; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData > _vonMisesPerNode; + core::objectmodel::lifecycle::RenamedData > _vonMisesPerNode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData > _vonMisesStressColors; + core::objectmodel::lifecycle::RenamedData > _vonMisesStressColors; Data d_computeVonMisesStress; ///< compute and display von Mises stress: 0: no computations, 1: using corotational strain, 2: using full Green strain. Set listening=1 Data > d_vonMisesPerElement; ///< von Mises Stress per element @@ -279,22 +279,22 @@ class TetrahedronFEMForceField : public BaseLinearElasticityFEMForceField _showStressColorMap; + core::objectmodel::lifecycle::RenamedData _showStressColorMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _showStressAlpha; + core::objectmodel::lifecycle::RenamedData _showStressAlpha; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _showVonMisesStressPerNode; + core::objectmodel::lifecycle::RenamedData _showVonMisesStressPerNode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _showVonMisesStressPerNodeColorMap; + core::objectmodel::lifecycle::RenamedData _showVonMisesStressPerNodeColorMap; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _showVonMisesStressPerElement; + core::objectmodel::lifecycle::RenamedData _showVonMisesStressPerElement; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - core::objectmodel::RenamedData _updateStiffness; + core::objectmodel::lifecycle::RenamedData _updateStiffness; Data d_showStressColorMap; ///< Color map used to show stress values Data d_showStressAlpha; ///< Alpha for vonMises visualisation diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h index 725c4158037..4815eec396f 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h @@ -28,7 +28,7 @@ #include #include -#include +#include // corotational triangle from // @InProceedings{NPF05, @@ -92,7 +92,7 @@ class TriangleFEMForceField : public BaseLinearElasticityFEMForceField _initialPoints; + sofa::core::objectmodel::lifecycle::RenamedData _initialPoints; Data< VecCoord > d_initialPoints; ///< Initial Position @@ -120,19 +120,19 @@ class TriangleFEMForceField : public BaseLinearElasticityFEMForceField f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_poisson; + sofa::core::objectmodel::lifecycle::RenamedData f_poisson; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_young; + sofa::core::objectmodel::lifecycle::RenamedData f_young; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_thickness; + sofa::core::objectmodel::lifecycle::RenamedData f_thickness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_planeStrain; + sofa::core::objectmodel::lifecycle::RenamedData f_planeStrain; Data d_method; ///< large: large displacements, small: small displacements Data d_thickness; ///< Thickness of the elements diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.h index 9c13be03ecb..27231b69eba 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularAnisotropicFEMForceField.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -77,19 +77,19 @@ class TriangularAnisotropicFEMForceField : public TriangularFEMForceField> f_young2; + sofa::core::objectmodel::lifecycle::RenamedData> f_young2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_theta; + sofa::core::objectmodel::lifecycle::RenamedData f_theta; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_fiberCenter; + sofa::core::objectmodel::lifecycle::RenamedData f_fiberCenter; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData showFiber; + sofa::core::objectmodel::lifecycle::RenamedData showFiber; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > localFiberDirection; + sofa::core::objectmodel::lifecycle::RenamedData > localFiberDirection; Data > f_poisson2; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.h index 4a178998e1f..67273d2f9e5 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangularFEMForceField.h @@ -33,7 +33,7 @@ #include #endif -#include +#include namespace sofa::helper { @@ -187,10 +187,10 @@ class TriangularFEMForceField : public BaseLinearElasticityFEMForceField> triangleInfo; + sofa::core::objectmodel::lifecycle::RenamedData> triangleInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > vertexInfo; + sofa::core::objectmodel::lifecycle::RenamedData > vertexInfo; /// Topology Data core::topology::TriangleData > d_triangleInfo; @@ -256,37 +256,37 @@ protected : int method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_method; + sofa::core::objectmodel::lifecycle::RenamedData f_method; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> f_poisson; + sofa::core::objectmodel::lifecycle::RenamedData> f_poisson; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData> f_young; + sofa::core::objectmodel::lifecycle::RenamedData> f_young; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > > m_rotatedInitialElements; + sofa::core::objectmodel::lifecycle::RenamedData > > m_rotatedInitialElements; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData > m_initialTransformation; + sofa::core::objectmodel::lifecycle::RenamedData > m_initialTransformation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData hosfordExponant; + sofa::core::objectmodel::lifecycle::RenamedData hosfordExponant; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData criteriaValue; + sofa::core::objectmodel::lifecycle::RenamedData criteriaValue; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData showStressValue; + sofa::core::objectmodel::lifecycle::RenamedData showStressValue; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData showStressVector; + sofa::core::objectmodel::lifecycle::RenamedData showStressVector; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData showFracturableTriangles; + sofa::core::objectmodel::lifecycle::RenamedData showFracturableTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_FEM_ELASTIC() - sofa::core::objectmodel::RenamedData f_computePrincipalStress; + sofa::core::objectmodel::lifecycle::RenamedData f_computePrincipalStress; Data d_method; ///< large: large displacements, small: small displacements diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BaseTetrahedronFEMForceField_test.h b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BaseTetrahedronFEMForceField_test.h index 7fbb0d13749..c5ed72d676e 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BaseTetrahedronFEMForceField_test.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BaseTetrahedronFEMForceField_test.h @@ -64,12 +64,12 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest public: - void SetUp() override + void doSetUp() override { m_simulation = sofa::simulation::getSimulation(); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr) sofa::simulation::node::unload(m_root); @@ -93,10 +93,10 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest simpleapi::createObject(m_root, "DefaultAnimationLoop"); simpleapi::createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); simpleapi::createObject(m_root, "MechanicalObject", { {"template", dataTypeName}, {"position", "0 0 0 1 0 0 0 1 0 0 0 1"} }); simpleapi::createObject(m_root, "TetrahedronSetTopologyContainer", { {"tetrahedra","2 3 1 0"} }); @@ -122,16 +122,16 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest simpleapi::createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Direct"); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Lagrangian"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Mapping"); - sofa::simpleapi::importPlugin("Sofa.Component.Engine.Select"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Projective"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Direct); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Lagrangian); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Mapping); + sofa::simpleapi::importPlugin(Sofa.Component.Engine.Select); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); simpleapi::createObject(m_root, "GenericConstraintSolver", { {"tolerance", "1e-3"}, {"maxIt", "1000"} }); @@ -195,7 +195,7 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest simpleapi::createObject(m_root, "DefaultAnimationLoop"); simpleapi::createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); simpleapi::createObject(m_root, "MechanicalObject", { {"template","Vec3"}, {"position", "0 0 0 1 0 0 0 1 0 0 0 1"} }); addTetraFEMForceField(m_root, 100, 0.3, "large"); @@ -214,8 +214,8 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest simpleapi::createObject(m_root, "DefaultAnimationLoop"); simpleapi::createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); simpleapi::createObject(m_root, "MechanicalObject", { {"template","Vec3"} }); simpleapi::createObject(m_root, "TetrahedronSetTopologyContainer"); @@ -234,9 +234,9 @@ class BaseTetrahedronFEMForceField_test : public sofa::testing::BaseTest simpleapi::createObject(m_root, "DefaultAnimationLoop"); simpleapi::createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); simpleapi::createObject(m_root, "MechanicalObject", { {"template", dataTypeName}, {"position", "0 0 0 1 0 0 0 1 0 0 0 1"} }); simpleapi::createObject(m_root, "TetrahedronSetTopologyContainer", { {"tetrahedra","2 3 1 0"} }); diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BeamFEMForceField_test.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BeamFEMForceField_test.cpp index 78292aa26f6..7edff8e465e 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BeamFEMForceField_test.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/BeamFEMForceField_test.cpp @@ -66,13 +66,13 @@ class BeamFEMForceField_test : public BaseTest public: - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component"); + sofa::simpleapi::importPlugin(Sofa.Component); m_simulation = sofa::simulation::getSimulation(); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr) sofa::simulation::node::unload(m_root); diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/TriangleFEMForceField_test.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/TriangleFEMForceField_test.cpp index 9ec55cb14cb..2440c772962 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/tests/TriangleFEMForceField_test.cpp +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/tests/TriangleFEMForceField_test.cpp @@ -79,12 +79,12 @@ class TriangleFEMForceField_test : public BaseTest public: - void SetUp() override + void doSetUp() override { m_simulation = sofa::simulation::getSimulation(); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr) sofa::simulation::node::unload(m_root); @@ -97,10 +97,10 @@ class TriangleFEMForceField_test : public BaseTest createObject(m_root, "DefaultAnimationLoop"); createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); createObject(m_root, "MechanicalObject", {{"template",dataTypeName}, {"position", "0 0 0 1 0 0 0 1 0 1 1 1"} }); createObject(m_root, "TriangleSetTopologyContainer", { {"triangles","0 1 2 1 3 2"} }); @@ -138,7 +138,7 @@ class TriangleFEMForceField_test : public BaseTest createObject(m_root, "DefaultAnimationLoop"); createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Grid"); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); createObject(m_root, "RegularGridTopology", { {"name", "grid"}, {"n", str(type::Vec3(nbrGrid, nbrGrid, 1))}, {"min", "0 0 0"}, {"max", "10 10 0"} }); @@ -175,12 +175,12 @@ class TriangleFEMForceField_test : public BaseTest { const Node::SPtr FEMNode = sofa::simpleapi::createChild(m_root, nodeName); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); - sofa::simpleapi::importPlugin("Sofa.Component.Constraint.Projective"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); createObject(FEMNode, "EulerImplicitSolver"); createObject(FEMNode, "CGLinearSolver", {{ "iterations", "20" }, { "tolerance", "1e-5" }, {"threshold", "1e-6"}}); @@ -259,8 +259,8 @@ class TriangleFEMForceField_test : public BaseTest createObject(m_root, "DefaultAnimationLoop"); createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); createObject(m_root, "MechanicalObject", { {"template",dataTypeName}, {"position", "0 0 0 1 0 0 0 1 0"} }); if (FEMType == 0) // TriangleModel @@ -291,9 +291,9 @@ class TriangleFEMForceField_test : public BaseTest createObject(m_root, "DefaultAnimationLoop"); createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); createObject(m_root, "MechanicalObject", { {"template",dataTypeName} }); createObject(m_root, "TriangleSetTopologyContainer"); @@ -326,9 +326,9 @@ class TriangleFEMForceField_test : public BaseTest createObject(m_root, "DefaultAnimationLoop"); createObject(m_root, "DefaultVisualManagerLoop"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); createObject(m_root, "MechanicalObject", { {"template",dataTypeName}, {"position", "0 0 0 1 0 0 0 1 0"} }); createObject(m_root, "TriangleSetTopologyContainer", { {"triangles","0 1 2"} }); diff --git a/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_params_test.cpp b/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_params_test.cpp index 7845bbe38e8..055fb1a9279 100644 --- a/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_params_test.cpp +++ b/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_params_test.cpp @@ -74,7 +74,7 @@ struct TetrahedronHyperelasticityFEMForceField_params_test : public BaseSimulati unsigned char flags; ///< testing options. (all by default). To be used with precaution. /// } - void SetUp() override + void doSetUp() override { } diff --git a/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_scene_test.cpp b/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_scene_test.cpp index f68e680790f..5fa2c6b37e2 100644 --- a/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_scene_test.cpp +++ b/Sofa/Component/SolidMechanics/FEM/HyperElastic/tests/TetrahedronHyperelasticityFEMForceField_scene_test.cpp @@ -74,7 +74,7 @@ struct TetrahedronHyperelasticityFEMForceField_scene_test : public BaseSimulatio unsigned char flags; ///< testing options. (all by default). To be used with precaution. /// } - void SetUp() override + void doSetUp() override { } diff --git a/Sofa/Component/SolidMechanics/FEM/src/sofa/component/solidmechanics/fem/init.cpp b/Sofa/Component/SolidMechanics/FEM/src/sofa/component/solidmechanics/fem/init.cpp index 06c8c86b4fd..9e60a6ad828 100644 --- a/Sofa/Component/SolidMechanics/FEM/src/sofa/component/solidmechanics/fem/init.cpp +++ b/Sofa/Component/SolidMechanics/FEM/src/sofa/component/solidmechanics/fem/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::solidmechanics::fem { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.FEM.HyperElastic"); - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.FEM.NonUniform"); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.FEM.HyperElastic); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.FEM.NonUniform); } void init() diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/AngularSpringForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/AngularSpringForceField.h index cd5e969b749..54c20464e36 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/AngularSpringForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/AngularSpringForceField.h @@ -28,7 +28,7 @@ #include #include -#include +#include namespace sofa::core::behavior @@ -67,19 +67,19 @@ class AngularSpringForceField : public core::behavior::ForceField typedef core::objectmodel::Data DataVecDeriv; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData< type::vector< sofa::Index > > indices; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector< sofa::Index > > indices; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData angularStiffness; + sofa::core::objectmodel::lifecycle::RenamedData angularStiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData angularLimit; + sofa::core::objectmodel::lifecycle::RenamedData angularLimit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData drawSpring; + sofa::core::objectmodel::lifecycle::RenamedData drawSpring; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData springColor; + sofa::core::objectmodel::lifecycle::RenamedData springColor; Data< type::vector< sofa::Index > > d_indices; ///< index of nodes controlled by the angular springs Data< VecReal > d_angularStiffness; ///< angular stiffness for the controlled nodes diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FrameSpringForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FrameSpringForceField.h index 3677cf59b68..2e29259fc59 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FrameSpringForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FrameSpringForceField.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -156,13 +156,13 @@ class FrameSpringForceField : public core::behavior::PairInteractionForceField > springs; + sofa::core::objectmodel::lifecycle::RenamedData > springs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData showLawfulTorsion; + sofa::core::objectmodel::lifecycle::RenamedData showLawfulTorsion; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData showExtraTorsion; + sofa::core::objectmodel::lifecycle::RenamedData showExtraTorsion; SReal m_potentialEnergy; /// the list of the springs diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/GearSpringForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/GearSpringForceField.h index de953fedabb..c555fc89d15 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/GearSpringForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/GearSpringForceField.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -289,19 +289,19 @@ class GearSpringForceField : public core::behavior::PairInteractionForceField > springs; + sofa::core::objectmodel::lifecycle::RenamedData > springs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() sofa::core::objectmodel::DataFileName f_filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_period; + sofa::core::objectmodel::lifecycle::RenamedData f_period; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_reinit; + sofa::core::objectmodel::lifecycle::RenamedData f_reinit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData showFactorSize; + sofa::core::objectmodel::lifecycle::RenamedData showFactorSize; /// the list of the springs Data > d_springs; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/JointSpringForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/JointSpringForceField.h index c45e5fb5106..535bc3df98d 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/JointSpringForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/JointSpringForceField.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -141,10 +141,10 @@ class JointSpringForceField : public core::behavior::PairInteractionForceField f_period; + sofa::core::objectmodel::lifecycle::RenamedData f_period; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_reinit; + sofa::core::objectmodel::lifecycle::RenamedData f_reinit; sofa::core::objectmodel::DataFileName d_outfilename; ///< output file name sofa::core::objectmodel::DataFileName d_infilename; ///< input file containing constant joint force diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/QuadBendingSprings.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/QuadBendingSprings.h index aa121a98879..21059847a7c 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/QuadBendingSprings.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/QuadBendingSprings.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -47,7 +47,7 @@ class QuadBendingSprings : public SpringForceField typedef core::behavior::MechanicalState MechanicalState; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData> localRange; + sofa::core::objectmodel::lifecycle::RenamedData> localRange; /// optional range of local DOF indices. Any computation involving only indices outside of this range are discarded (useful for parallelization using mesh partitioning) Data< type::Vec<2,int> > d_localRange; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl index c3fc5d30191..dd046de4d8c 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl @@ -159,6 +159,7 @@ const typename RestShapeSpringsForceField::VecIndex& RestShapeSprings else { return this->d_indices.getValue(); + } } diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBendingSprings.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBendingSprings.h index b57362f1233..9940fd7add4 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBendingSprings.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBendingSprings.h @@ -28,7 +28,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -98,7 +98,7 @@ class TriangularBendingSprings : public core::behavior::ForceField } }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData> edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData> edgeInfo; sofa::core::topology::EdgeData > d_edgeInfo; ///< Internal edge data diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBiquadraticSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBiquadraticSpringsForceField.h index b60ef5199cd..28fc16c2501 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBiquadraticSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularBiquadraticSpringsForceField.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -124,31 +124,31 @@ class TriangularBiquadraticSpringsForceField : public core::behavior::ForceField }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData > triangleInfo; + sofa::core::objectmodel::lifecycle::RenamedData > triangleInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData > edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData > edgeInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData _initialPoints; + sofa::core::objectmodel::lifecycle::RenamedData _initialPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_youngModulus; + sofa::core::objectmodel::lifecycle::RenamedData f_youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_dampingRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_dampingRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_useAngularSprings; + sofa::core::objectmodel::lifecycle::RenamedData f_useAngularSprings; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_compressible; + sofa::core::objectmodel::lifecycle::RenamedData f_compressible; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_stiffnessMatrixRegularizationWeight; + sofa::core::objectmodel::lifecycle::RenamedData f_stiffnessMatrixRegularizationWeight; diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularQuadraticSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularQuadraticSpringsForceField.h index 998784e9994..9697d00e39b 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularQuadraticSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/TriangularQuadraticSpringsForceField.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -116,19 +116,19 @@ class TriangularQuadraticSpringsForceField : public core::behavior::ForceField _initialPoints; + sofa::core::objectmodel::lifecycle::RenamedData _initialPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_youngModulus; + sofa::core::objectmodel::lifecycle::RenamedData f_youngModulus; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_dampingRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_dampingRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData f_useAngularSprings; + sofa::core::objectmodel::lifecycle::RenamedData f_useAngularSprings; Data< VecCoord > d_initialPoints; ///< Initial Position @@ -205,10 +205,10 @@ class TriangularQuadraticSpringsForceField : public core::behavior::ForceField> triangleInfo; + sofa::core::objectmodel::lifecycle::RenamedData> triangleInfo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData > edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData > edgeInfo; sofa::core::topology::TriangleData > d_triangleInfo; ///< Internal triangle data sofa::core::topology::EdgeData > d_edgeInfo; ///< Internal edge data diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/VectorSpringForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/VectorSpringForceField.h index c8f7660ca1e..03680f095eb 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/VectorSpringForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/VectorSpringForceField.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::spring { @@ -96,19 +96,19 @@ class VectorSpringForceField: public core::behavior::PairInteractionForceField > springArray; + sofa::core::objectmodel::lifecycle::RenamedData > springArray; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() sofa::core::objectmodel::DataFileName m_filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData m_stiffness; + sofa::core::objectmodel::lifecycle::RenamedData m_stiffness; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData m_viscosity; + sofa::core::objectmodel::lifecycle::RenamedData m_viscosity; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_SPRING() - sofa::core::objectmodel::RenamedData m_useTopology; + sofa::core::objectmodel::lifecycle::RenamedData m_useTopology; /// where the springs information are stored diff --git a/Sofa/Component/SolidMechanics/Spring/tests/PolynomialRestShapeSpringsForceField_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/PolynomialRestShapeSpringsForceField_test.cpp index 0af527cfba3..3d987884321 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/PolynomialRestShapeSpringsForceField_test.cpp +++ b/Sofa/Component/SolidMechanics/Spring/tests/PolynomialRestShapeSpringsForceField_test.cpp @@ -42,9 +42,9 @@ class PolynomialRestShapeSpringsForceField_test : public BaseSimulationTest root->setGravity(Vec3(0.0,0.0,0.0)); root->setDt(dt); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Forward"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Forward); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.Spring); const Node::SPtr childNode = sofa::simpleapi::createChild(root, "Particle"); sofa::simpleapi::createObject(childNode, "EulerExplicitSolver"); diff --git a/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp index 0a9c1f3bfe4..cc6d7bf5d39 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp +++ b/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp @@ -58,10 +58,10 @@ sofa::simulation::Node::SPtr RestSpringsForceField_test::createScene(const std:: { const auto theSimulation = createSimulation(); auto theRoot = createRootNode(theSimulation, "root"); - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Backward"); - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); createObject(theRoot, "DefaultAnimationLoop"); createObject(theRoot, "EulerImplicitSolver"); diff --git a/Sofa/Component/SolidMechanics/Spring/tests/TriangularBendingSprings_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/TriangularBendingSprings_test.cpp index 0149f6d8c1c..5288e64ee48 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/TriangularBendingSprings_test.cpp +++ b/Sofa/Component/SolidMechanics/Spring/tests/TriangularBendingSprings_test.cpp @@ -67,14 +67,14 @@ class TriangularBendingSprings_test : public BaseTest public: - void SetUp() override + void doSetUp() override { m_simulation = sofa::simulation::getSimulation(); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Grid"); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); } - void TearDown() override + void doTearDown() override { if (m_root != nullptr) sofa::simulation::node::unload(m_root); diff --git a/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TetrahedralTensorMassForceField.h b/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TetrahedralTensorMassForceField.h index 4734b3db415..32b23bff853 100644 --- a/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TetrahedralTensorMassForceField.h +++ b/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TetrahedralTensorMassForceField.h @@ -33,7 +33,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::tensormass { @@ -89,10 +89,10 @@ class TetrahedralTensorMassForceField : public core::behavior::ForceField f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_TENSORMASS() - sofa::core::objectmodel::RenamedData f_youngModulus; + sofa::core::objectmodel::lifecycle::RenamedData f_youngModulus; Data d_poissonRatio; ///< Poisson ratio in Hooke's law Data d_youngModulus; ///< Young's modulus in Hooke's law @@ -166,7 +166,7 @@ class TetrahedralTensorMassForceField : public core::behavior::ForceField edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData edgeInfo; core::topology::EdgeData < edgeRestInfoVector > d_edgeInfo; ///< Internal edge data diff --git a/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TriangularTensorMassForceField.h b/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TriangularTensorMassForceField.h index 8593d337670..7612409982e 100644 --- a/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TriangularTensorMassForceField.h +++ b/Sofa/Component/SolidMechanics/TensorMass/src/sofa/component/solidmechanics/tensormass/TriangularTensorMassForceField.h @@ -29,7 +29,7 @@ #include #include -#include +#include namespace sofa::component::solidmechanics::tensormass { @@ -91,7 +91,7 @@ class TriangularTensorMassForceField : public core::behavior::ForceField> edgeInfo; + sofa::core::objectmodel::lifecycle::RenamedData > edgeInfo; sofa::core::topology::EdgeData > d_edgeInfo; ///< Internal edge data @@ -124,10 +124,10 @@ class TriangularTensorMassForceField : public core::behavior::ForceField f_poissonRatio; + sofa::core::objectmodel::lifecycle::RenamedData f_poissonRatio; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_SOLIDMECHANICS_TENSORMASS() - sofa::core::objectmodel::RenamedData f_youngModulus; + sofa::core::objectmodel::lifecycle::RenamedData f_youngModulus; Data d_poissonRatio; ///< Poisson ratio in Hooke's law Data d_youngModulus; ///< Young's modulus in Hooke's law diff --git a/Sofa/Component/SolidMechanics/simutests/AffinePatch_test.cpp b/Sofa/Component/SolidMechanics/simutests/AffinePatch_test.cpp index 270088dbaca..baa7a16efde 100644 --- a/Sofa/Component/SolidMechanics/simutests/AffinePatch_test.cpp +++ b/Sofa/Component/SolidMechanics/simutests/AffinePatch_test.cpp @@ -80,7 +80,7 @@ struct AffinePatch_sofa_test : public sofa::testing::BaseSimulationTest, sofa::t Coord testedTranslation; /// Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); diff --git a/Sofa/Component/SolidMechanics/simutests/LinearElasticity_test.cpp b/Sofa/Component/SolidMechanics/simutests/LinearElasticity_test.cpp index 6202204e7e1..3db4e9cc08c 100644 --- a/Sofa/Component/SolidMechanics/simutests/LinearElasticity_test.cpp +++ b/Sofa/Component/SolidMechanics/simutests/LinearElasticity_test.cpp @@ -196,7 +196,7 @@ struct LinearElasticity_test : public sofa::testing::BaseSimulationTest, sofa::t // Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); @@ -281,7 +281,7 @@ struct LinearElasticity_test : public sofa::testing::BaseSimulationTest, sofa::t } return true; } - void TearDown() override + void doTearDown() override { if (tractionStruct.root!=nullptr) sofa::simulation::node::unload(tractionStruct.root); diff --git a/Sofa/Component/SolidMechanics/src/sofa/component/solidmechanics/init.cpp b/Sofa/Component/SolidMechanics/src/sofa/component/solidmechanics/init.cpp index a35ec25d9d9..8638bbdb020 100644 --- a/Sofa/Component/SolidMechanics/src/sofa/component/solidmechanics/init.cpp +++ b/Sofa/Component/SolidMechanics/src/sofa/component/solidmechanics/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::solidmechanics { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.FEM"); - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.Spring"); - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics.TensorMass"); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.FEM); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.Spring); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics.TensorMass); } void init() diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MappedObject.h b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MappedObject.h index 1d96f21d115..c9de6e7431e 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MappedObject.h +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MappedObject.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::statecontainer { @@ -65,10 +65,10 @@ class MappedObject : public core::State void init() override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_STATECONTAINER() - sofa::core::objectmodel::RenamedData f_X; + sofa::core::objectmodel::lifecycle::RenamedData f_X; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_STATECONTAINER() - sofa::core::objectmodel::RenamedData f_V; + sofa::core::objectmodel::lifecycle::RenamedData f_V; Data d_X; ///< position vector Data d_V; ///< velocity vector diff --git a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/CubeTopology.h b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/CubeTopology.h index ebfc4f3b25c..8a9d87bf9eb 100644 --- a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/CubeTopology.h +++ b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/CubeTopology.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::topology::container::constant { @@ -97,25 +97,25 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_CONSTANT_API CubeTopology : public MeshT protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData nx; + sofa::core::objectmodel::lifecycle::RenamedData nx; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData ny; + sofa::core::objectmodel::lifecycle::RenamedData ny; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData nz; + sofa::core::objectmodel::lifecycle::RenamedData nz; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData internalPoints; + sofa::core::objectmodel::lifecycle::RenamedData internalPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData splitNormals; + sofa::core::objectmodel::lifecycle::RenamedData splitNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData min; + sofa::core::objectmodel::lifecycle::RenamedData min; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData max; + sofa::core::objectmodel::lifecycle::RenamedData max; Data d_nx; ///< x grid resolution diff --git a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.cpp b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.cpp index 5ae461075e0..d41efbaed97 100644 --- a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.cpp +++ b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.cpp @@ -492,6 +492,7 @@ MeshTopology::MeshTopology() , d_seqTetrahedra(initData(&d_seqTetrahedra, "tetrahedra", "List of tetrahedron indices")) , d_seqHexahedra(initData(&d_seqHexahedra, "hexahedra", "List of hexahedron indices")) , d_seqUVs(initData(&d_seqUVs, "uv", "List of uv coordinates")) + , d_computeAllBuffers(initData(&d_computeAllBuffers, false, "computeAllBuffers", "Option to compute all crossed topology buffers at init. False by default")) , nbPoints(0) , validTetrahedra(false), validHexahedra(false) , revision(0) @@ -524,7 +525,6 @@ MeshTopology::MeshTopology() void MeshTopology::init() { - BaseMeshTopology::init(); const auto hexahedra = sofa::helper::getReadAccessor(d_seqHexahedra); @@ -533,7 +533,6 @@ void MeshTopology::init() const auto triangles = sofa::helper::getReadAccessor(d_seqTriangles); const auto edges = sofa::helper::getReadAccessor(d_seqEdges); - // looking for upper topology if (!hexahedra.empty()) m_upperElementType = geometry::ElementType::HEXAHEDRON; @@ -548,6 +547,11 @@ void MeshTopology::init() else m_upperElementType = sofa::geometry::ElementType::POINT; + // If true, will compute all crossed element buffers such as triangleAroundEdges, EdgesIntriangle, etc. + if (d_computeAllBuffers.getValue()) + { + computeCrossElementBuffers(); + } // compute the number of points, if the topology is charged from the scene or if it was loaded from a MeshLoader without any points data. if (nbPoints==0) @@ -576,6 +580,7 @@ void MeshTopology::init() nbPoints = n; } + if(edges.empty() ) { if(d_seqEdges.getParent() != nullptr ) @@ -608,6 +613,72 @@ void MeshTopology::init() } } +void MeshTopology::computeCrossElementBuffers() +{ + const auto hexahedra = sofa::helper::getReadAccessor(d_seqHexahedra); + const auto tetrahedra = sofa::helper::getReadAccessor(d_seqTetrahedra); + const auto quads = sofa::helper::getReadAccessor(d_seqQuads); + const auto triangles = sofa::helper::getReadAccessor(d_seqTriangles); + const auto edges = sofa::helper::getReadAccessor(d_seqEdges); + + if (!hexahedra.empty()) // Create hexahedron cross element buffers. + { + createHexahedraAroundVertexArray(); + + if (!quads.empty()) + { + createQuadsInHexahedronArray(); + createHexahedraAroundQuadArray(); + } + + if (!edges.empty()) + { + createEdgesInHexahedronArray(); + createHexahedraAroundEdgeArray(); + } + } + if (!tetrahedra.empty()) // Create tetrahedron cross element buffers. + { + createTetrahedraAroundVertexArray(); + + if (!triangles.empty()) + { + createTrianglesInTetrahedronArray(); + createTetrahedraAroundTriangleArray(); + } + + if (!edges.empty()) + { + createEdgesInTetrahedronArray(); + createTetrahedraAroundEdgeArray(); + } + } + if (!quads.empty()) // Create triangle cross element buffers. + { + createQuadsAroundVertexArray(); + + if (!edges.empty()) + { + createEdgesInQuadArray(); + createQuadsAroundEdgeArray(); + } + } + if (!triangles.empty()) // Create triangle cross element buffers. + { + createTrianglesAroundVertexArray(); + + if (!edges.empty()) + { + createEdgesInTriangleArray(); + createTrianglesAroundEdgeArray(); + } + } + if (!edges.empty()) + { + createEdgesAroundVertexArray(); + } +} + void MeshTopology::clear() { nbPoints = 0; diff --git a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.h b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.h index d4b0d37e717..ffab38c37f3 100644 --- a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.h +++ b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/MeshTopology.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::component::topology::container::constant { @@ -86,6 +86,9 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_CONSTANT_API MeshTopology : public core: public: void init() override; + /// Method called by component Init method. Will create all the topology buffers + void computeCrossElementBuffers() override; + Size getNbPoints() const override; void setNbPoints(Size n) override; @@ -306,40 +309,40 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_CONSTANT_API MeshTopology : public core: typedef type::vector SeqPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData< SeqPoints > seqPoints; + sofa::core::objectmodel::lifecycle::RenamedData< SeqPoints > seqPoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqEdges; + sofa::core::objectmodel::lifecycle::RenamedData seqEdges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqTriangles; + sofa::core::objectmodel::lifecycle::RenamedData seqTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqQuads; + sofa::core::objectmodel::lifecycle::RenamedData seqQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqTetrahedra; + sofa::core::objectmodel::lifecycle::RenamedData seqTetrahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqHexahedra; + sofa::core::objectmodel::lifecycle::RenamedData seqHexahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData seqUVs; + sofa::core::objectmodel::lifecycle::RenamedData seqUVs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData _drawEdges; + sofa::core::objectmodel::lifecycle::RenamedData _drawEdges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData _drawTriangles; + sofa::core::objectmodel::lifecycle::RenamedData _drawTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData _drawQuads; + sofa::core::objectmodel::lifecycle::RenamedData _drawQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData _drawTetra; + sofa::core::objectmodel::lifecycle::RenamedData _drawTetra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData _drawHexa; + sofa::core::objectmodel::lifecycle::RenamedData _drawHexa; Data< SeqPoints > d_seqPoints; ///< List of point positions Data d_seqEdges; ///< List of edge indices @@ -348,6 +351,7 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_CONSTANT_API MeshTopology : public core: Data d_seqTetrahedra; ///< List of tetrahedron indices Data d_seqHexahedra; ///< List of hexahedron indices Data d_seqUVs; ///< List of uv coordinates + Data d_computeAllBuffers; ///< Option to call method computeCrossElementBuffers. False by default protected: Size nbPoints; diff --git a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/SphereQuadTopology.h b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/SphereQuadTopology.h index d8521b50088..aef14d72cb9 100644 --- a/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/SphereQuadTopology.h +++ b/Sofa/Component/Topology/Container/Constant/src/sofa/component/topology/container/constant/SphereQuadTopology.h @@ -22,7 +22,7 @@ #pragma once #include -#include +#include namespace sofa::component::topology::container::constant { @@ -42,10 +42,10 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_CONSTANT_API SphereQuadTopology : public protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData< Vec3 > center; + sofa::core::objectmodel::lifecycle::RenamedData< Vec3 > center; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_CONSTANT() - sofa::core::objectmodel::RenamedData< SReal > radius; + sofa::core::objectmodel::lifecycle::RenamedData< SReal > radius; Data< Vec3 > d_center; ///< Center of the sphere diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/DynamicSparseGridTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/DynamicSparseGridTopologyContainer.h index 6c3fdd28a7f..2c8ad019160 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/DynamicSparseGridTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/DynamicSparseGridTopologyContainer.h @@ -28,7 +28,7 @@ #include #include -#include +#include namespace sofa::component::topology::container::dynamic { @@ -46,22 +46,22 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API DynamicSparseGridTopologyCon typedef QuadsInHexahedron QuadsInHexahedron; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData resolution; + sofa::core::objectmodel::lifecycle::RenamedData resolution; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData< sofa::type::vector > valuesIndexedInRegularGrid; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > valuesIndexedInRegularGrid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData< sofa::type::vector > valuesIndexedInTopology; ///< values indexed in the topology + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > valuesIndexedInTopology; ///< values indexed in the topology SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData< sofa::type::vector > idxInRegularGrid; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::vector > idxInRegularGrid; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData< std::map< unsigned int, BaseMeshTopology::HexaID> > idInRegularGrid2IndexInTopo; + sofa::core::objectmodel::lifecycle::RenamedData< std::map< unsigned int, BaseMeshTopology::HexaID> > idInRegularGrid2IndexInTopo; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData< type::Vec3 > voxelSize; + sofa::core::objectmodel::lifecycle::RenamedData< type::Vec3 > voxelSize; Data d_resolution; ///< voxel grid resolution diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.cpp b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.cpp index 15ddadbc529..4e212ff7696 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.cpp @@ -77,10 +77,10 @@ void EdgeSetTopologyContainer::init() // only init if edges are present at init. if (!m_edge.empty()) - initTopology(); + computeCrossElementBuffers(); } -void EdgeSetTopologyContainer::initTopology() +void EdgeSetTopologyContainer::computeCrossElementBuffers() { // force computation of neighborhood elements createEdgesAroundVertexArray(); diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.h index 2cf809bbe3a..7749c66f00d 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/EdgeSetTopologyContainer.h @@ -24,7 +24,7 @@ #include -#include +#include namespace sofa::component::topology::container::dynamic { @@ -100,7 +100,7 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API EdgeSetTopologyContainer : p /// Dynamic Topology API /// @{ /// Method called by component Init method. Will create all the topology neighborhood buffers. - void initTopology(); + void computeCrossElementBuffers() override; /** \brief Checks if the topology is coherent * @@ -228,7 +228,7 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API EdgeSetTopologyContainer : p public: /** The array that stores the set of edges in the edge set */ SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData m_checkConnexity; + sofa::core::objectmodel::lifecycle::RenamedData m_checkConnexity; Data< sofa::type::vector > d_edge; ///< List of edge indices diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.cpp b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.cpp index b8fb2b1c268..554a87f9352 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.cpp @@ -83,12 +83,12 @@ void HexahedronSetTopologyContainer::init() } if (!m_hexahedron.empty()) - initTopology(); + computeCrossElementBuffers(); } -void HexahedronSetTopologyContainer::initTopology() +void HexahedronSetTopologyContainer::computeCrossElementBuffers() { - QuadSetTopologyContainer::initTopology(); + QuadSetTopologyContainer::computeCrossElementBuffers(); // Create tetrahedron cross element buffers. createQuadsInHexahedronArray(); diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.h index 65238e957a2..9bb8f012910 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/HexahedronSetTopologyContainer.h @@ -222,8 +222,8 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API HexahedronSetTopologyContain /// Dynamic Topology API /// @{ - /// Method called by component Init method. Will create all the topology neighborhood buffers and call @see TriangleSetTopologyContainer::initTopology() - void initTopology(); + /// Method called by component Init method. Will create all the topology neighboorhood buffers and call @see QuadSetTopologyContainer::computeCrossElementBuffers() + void computeCrossElementBuffers() override; /** \brief Checks if the topology is coherent * diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetTopologyContainer.h index 6ffe3fa0952..f5c28d9b37c 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/PointSetTopologyContainer.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::topology::container::dynamic { @@ -160,7 +160,7 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API PointSetTopologyContainer : private: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_DYNAMIC() - sofa::core::objectmodel::RenamedData nbPoints; + sofa::core::objectmodel::lifecycle::RenamedData nbPoints; Data d_nbPoints; ///< Number of points }; diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.cpp b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.cpp index b9434772f7f..d861dfc5ea2 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.cpp @@ -72,13 +72,13 @@ void QuadSetTopologyContainer::init() // only init if triangles are present at init. if (!m_quads.empty()) - initTopology(); + computeCrossElementBuffers(); } -void QuadSetTopologyContainer::initTopology() +void QuadSetTopologyContainer::computeCrossElementBuffers() { // Force creation of Edge Neighborhood buffers. - EdgeSetTopologyContainer::initTopology(); + EdgeSetTopologyContainer::computeCrossElementBuffers(); // Create triangle cross element buffers. createEdgesInQuadArray(); diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.h index 54a78981e3a..58efedcc105 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/QuadSetTopologyContainer.h @@ -144,8 +144,8 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API QuadSetTopologyContainer : p /// Dynamic Topology API /// @{ - /// Method called by component Init method. Will create all the topology neighborhood buffers and call @see EdgeSetTopologyContainer::initTopology() - void initTopology(); + /// Method called by component Init method. Will create all the topology neighboorhood buffers and call @see EdgeSetTopologyContainer::computeCrossElementBuffers() + void computeCrossElementBuffers() override; /** \brief Checks if the topology is coherent * diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.cpp b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.cpp index d8fbe58adcd..5ad91e53519 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.cpp @@ -79,12 +79,12 @@ void TetrahedronSetTopologyContainer::init() } if (!m_tetrahedron.empty()) - initTopology(); + computeCrossElementBuffers(); } -void TetrahedronSetTopologyContainer::initTopology() +void TetrahedronSetTopologyContainer::computeCrossElementBuffers() { - TriangleSetTopologyContainer::initTopology(); + TriangleSetTopologyContainer::computeCrossElementBuffers(); // Create tetrahedron cross element buffers. createTrianglesInTetrahedronArray(); diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.h index 089d3e6f7f2..2376324fbb2 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TetrahedronSetTopologyContainer.h @@ -193,8 +193,8 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API TetrahedronSetTopologyContai /// Dynamic Topology API /// @{ - /// Method called by component Init method. Will create all the topology neighborhood buffers and call @see TriangleSetTopologyContainer::initTopology() - void initTopology(); + /// Method called by component Init method. Will create all the topology neighboorhood buffers and call @see TriangleSetTopologyContainer::computeCrossElementBuffers() + void computeCrossElementBuffers() override; /** \brief Checks if the topology is coherent * diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.cpp b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.cpp index cfc69119e8c..577727a1c01 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.cpp @@ -73,13 +73,13 @@ void TriangleSetTopologyContainer::init() // only init if triangles are present at init. if (!m_triangle.empty()) - initTopology(); + computeCrossElementBuffers(); } -void TriangleSetTopologyContainer::initTopology() +void TriangleSetTopologyContainer::computeCrossElementBuffers() { // Force creation of Edge Neighborhood buffers. - EdgeSetTopologyContainer::initTopology(); + EdgeSetTopologyContainer::computeCrossElementBuffers(); // Create triangle cross element buffers. createEdgesInTriangleArray(); diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.h index 8c41f4a5ecd..ba0bfa3c8f9 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetTopologyContainer.h @@ -151,8 +151,8 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_DYNAMIC_API TriangleSetTopologyContainer /// Dynamic Topology API /// @{ - /// Method called by component Init method. Will create all the topology neighborhood buffers and call @see EdgeSetTopologyContainer::initTopology() - void initTopology(); + /// Method called by component Init method. Will create all the topology neighboorhood buffers and call @see EdgeSetTopologyContainer::computeCrossElementBuffers() + void computeCrossElementBuffers() override; /** \brief Checks if the topology is coherent * diff --git a/Sofa/Component/Topology/Container/Dynamic/tests/TetrahedronNumericalIntegration_test.cpp b/Sofa/Component/Topology/Container/Dynamic/tests/TetrahedronNumericalIntegration_test.cpp index 19c4cde4a41..c172e8c740e 100644 --- a/Sofa/Component/Topology/Container/Dynamic/tests/TetrahedronNumericalIntegration_test.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/tests/TetrahedronNumericalIntegration_test.cpp @@ -63,7 +63,7 @@ struct TetrahedronNumericalIntegration_test : public NumericTest::SPtr geo; // Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); @@ -135,7 +135,7 @@ struct TetrahedronNumericalIntegration_test : public NumericTest::SPtr geo; // Create the context for the scene - void SetUp() override + void doSetUp() override { // Init simulation simulation = sofa::simulation::getSimulation(); @@ -135,7 +135,7 @@ struct TriangleNumericalIntegration_test : public NumericTest -#include +#include namespace sofa::component::topology::container::grid { @@ -82,19 +82,19 @@ public : protected : SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData> _fileTopologies; + sofa::core::objectmodel::lifecycle::RenamedData> _fileTopologies; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData> _dataStiffnessCoefs; + sofa::core::objectmodel::lifecycle::RenamedData> _dataStiffnessCoefs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData> _dataMassCoefs; + sofa::core::objectmodel::lifecycle::RenamedData> _dataMassCoefs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _computeRamifications; + sofa::core::objectmodel::lifecycle::RenamedData _computeRamifications; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _erasePreviousCoef; + sofa::core::objectmodel::lifecycle::RenamedData _erasePreviousCoef; Data< type::vector< std::string > > d_fileTopologies; ///< All topology filenames diff --git a/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridRamificationTopology.h b/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridRamificationTopology.h index 560cd3867f6..923960b7bca 100644 --- a/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridRamificationTopology.h +++ b/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridRamificationTopology.h @@ -25,7 +25,7 @@ #include -#include +#include namespace sofa::component::topology::container::grid { @@ -78,7 +78,7 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_GRID_API SparseGridRamificationTopology enum {UP,DOWN,RIGHT,LEFT,BEFORE,BEHIND,NUM_CONNECTED_NODES}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _finestConnectivity; + sofa::core::objectmodel::lifecycle::RenamedData _finestConnectivity; // Does the connectivity test have to be done at the finest level? (more precise but slow) diff --git a/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridTopology.h b/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridTopology.h index 52f204d08ad..7ec17f8c093 100644 --- a/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridTopology.h +++ b/Sofa/Component/Topology/Container/Grid/src/sofa/component/topology/container/grid/SparseGridTopology.h @@ -32,7 +32,7 @@ #include #include -#include +#include namespace sofa::core::loader { @@ -192,13 +192,13 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_GRID_API SparseGridTopology : public con return d_dataVoxels.getValue()[index] == 1; } SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _fillWeighted; + sofa::core::objectmodel::lifecycle::RenamedData _fillWeighted; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData bOnlyInsideCells; + sofa::core::objectmodel::lifecycle::RenamedData bOnlyInsideCells; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData< type::vector< unsigned char > > dataVoxels; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector< unsigned char > > dataVoxels; Data< type::vector< unsigned char > > d_dataVoxels; @@ -212,19 +212,19 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_GRID_API SparseGridTopology : public con SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData< sofa::type::Vec< 3, int > > n; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::Vec< 3, int > > n; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _min; + sofa::core::objectmodel::lifecycle::RenamedData _min; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _max; + sofa::core::objectmodel::lifecycle::RenamedData _max; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _cellWidth; + sofa::core::objectmodel::lifecycle::RenamedData _cellWidth; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData _nbVirtualFinerLevels; + sofa::core::objectmodel::lifecycle::RenamedData _nbVirtualFinerLevels; bool isVirtual; @@ -238,19 +238,19 @@ class SOFA_COMPONENT_TOPOLOGY_CONTAINER_GRID_API SparseGridTopology : public con public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData dataResolution; + sofa::core::objectmodel::lifecycle::RenamedData dataResolution; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData voxelSize; + sofa::core::objectmodel::lifecycle::RenamedData voxelSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData marchingCubeStep; + sofa::core::objectmodel::lifecycle::RenamedData marchingCubeStep; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData convolutionSize; + sofa::core::objectmodel::lifecycle::RenamedData convolutionSize; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID()SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_CONTAINER_GRID() - sofa::core::objectmodel::RenamedData< type::vector< type::vector > > facets; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector< type::vector > > facets; Data< type::Vec3i > d_dataResolution; ///< Dimension of the voxel File Data< type::Vec3 > d_voxelSize; ///< Dimension of one voxel diff --git a/Sofa/Component/Topology/Container/Grid/tests/SparseGridTopology_test.cpp b/Sofa/Component/Topology/Container/Grid/tests/SparseGridTopology_test.cpp index a10918d8f78..80ca289b559 100644 --- a/Sofa/Component/Topology/Container/Grid/tests/SparseGridTopology_test.cpp +++ b/Sofa/Component/Topology/Container/Grid/tests/SparseGridTopology_test.cpp @@ -40,7 +40,7 @@ using namespace sofa::testing; struct SparseGridTopology_test : public BaseTest { - void SetUp() override + void doSetUp() override { DataRepository.addFirstPath(SOFA_TESTING_RESOURCES_DIR); } diff --git a/Sofa/Component/Topology/Container/src/sofa/component/topology/container/init.cpp b/Sofa/Component/Topology/Container/src/sofa/component/topology/container/init.cpp index 99b3ffeac8d..bd43c782876 100644 --- a/Sofa/Component/Topology/Container/src/sofa/component/topology/container/init.cpp +++ b/Sofa/Component/Topology/Container/src/sofa/component/topology/container/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::topology::container { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Container.Constant"); - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Container.Dynamic"); - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Container.Grid"); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Container.Constant); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Container.Dynamic); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Container.Grid); } void init() diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2QuadTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2QuadTopologicalMapping.h index 5d2d6d70e5e..234ba72670a 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2QuadTopologicalMapping.h +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2QuadTopologicalMapping.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::topology::mapping { @@ -78,7 +78,7 @@ class SOFA_COMPONENT_TOPOLOGY_MAPPING_API Hexa2QuadTopologicalMapping : public s protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData flipNormals; + sofa::core::objectmodel::lifecycle::RenamedData flipNormals; Data d_flipNormals; ///< Flip Normal ? (Inverse point order when creating triangle) diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.h index f13d26e77ea..53e04c13fb8 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.h +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::topology::mapping @@ -77,7 +77,7 @@ class SOFA_COMPONENT_TOPOLOGY_MAPPING_API Hexa2TetraTopologicalMapping : public Index getFromIndex(Index ind) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData swapping; + sofa::core::objectmodel::lifecycle::RenamedData swapping; sofa::core::objectmodel::Data d_swapping; ///< Boolean enabling to swapp hexa-edges in order to avoid bias effect diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/SubsetTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/SubsetTopologicalMapping.h index 12c080e3d8e..b083a5442cd 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/SubsetTopologicalMapping.h +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/SubsetTopologicalMapping.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::topology::mapping { @@ -53,58 +53,58 @@ class SOFA_COMPONENT_TOPOLOGY_MAPPING_API SubsetTopologicalMapping : public sofa public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData samePoints; + sofa::core::objectmodel::lifecycle::RenamedData samePoints; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData handleEdges; + sofa::core::objectmodel::lifecycle::RenamedData handleEdges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData handleTriangles; + sofa::core::objectmodel::lifecycle::RenamedData handleTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData handleQuads; + sofa::core::objectmodel::lifecycle::RenamedData handleQuads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData handleTetrahedra; + sofa::core::objectmodel::lifecycle::RenamedData handleTetrahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData handleHexahedra; + sofa::core::objectmodel::lifecycle::RenamedData handleHexahedra; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData pointS2D; + sofa::core::objectmodel::lifecycle::RenamedData pointS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData pointD2S; + sofa::core::objectmodel::lifecycle::RenamedData pointD2S; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData edgeS2D; + sofa::core::objectmodel::lifecycle::RenamedData edgeS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData edgeD2S; + sofa::core::objectmodel::lifecycle::RenamedData edgeD2S; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData triangleS2D; + sofa::core::objectmodel::lifecycle::RenamedData triangleS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData triangleD2S; + sofa::core::objectmodel::lifecycle::RenamedData triangleD2S; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData quadS2D; + sofa::core::objectmodel::lifecycle::RenamedData quadS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData quadD2S; + sofa::core::objectmodel::lifecycle::RenamedData quadD2S; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData tetrahedronS2D; + sofa::core::objectmodel::lifecycle::RenamedData tetrahedronS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData tetrahedronD2S; + sofa::core::objectmodel::lifecycle::RenamedData tetrahedronD2S; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData hexahedronS2D; + sofa::core::objectmodel::lifecycle::RenamedData hexahedronS2D; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData hexahedronD2S; + sofa::core::objectmodel::lifecycle::RenamedData hexahedronD2S; Data d_samePoints; ///< True if the same set of points is used in both topologies Data d_handleEdges; ///< True if edges events and mapping should be handled diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h index d6c599932dd..c38d8c0858b 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h @@ -29,7 +29,7 @@ #include -#include +#include namespace sofa::component::topology::container::dynamic { @@ -84,13 +84,13 @@ class SOFA_COMPONENT_TOPOLOGY_MAPPING_API Tetra2TriangleTopologicalMapping : pub protected: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData flipNormals; + sofa::core::objectmodel::lifecycle::RenamedData flipNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData noNewTriangles; + sofa::core::objectmodel::lifecycle::RenamedData noNewTriangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA() - sofa::core::objectmodel::RenamedData noInitialTriangles; + sofa::core::objectmodel::lifecycle::RenamedData noInitialTriangles; Data d_flipNormals; ///< Flip Normal ? (Inverse point order when creating triangle) diff --git a/Sofa/Component/Topology/Testing/src/sofa/component/topology/testing/fake_TopologyScene.h b/Sofa/Component/Topology/Testing/src/sofa/component/topology/testing/fake_TopologyScene.h index bdd5bf4c915..fe2283294da 100644 --- a/Sofa/Component/Topology/Testing/src/sofa/component/topology/testing/fake_TopologyScene.h +++ b/Sofa/Component/Topology/Testing/src/sofa/component/topology/testing/fake_TopologyScene.h @@ -25,6 +25,7 @@ #include #include #include +#include class fake_TopologyScene { @@ -52,11 +53,11 @@ class fake_TopologyScene m_simu = createSimulation("DAG"); m_root = createRootNode(m_simu, "root"); - sofa::simpleapi::importPlugin("Sofa.Component.IO.Mesh"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Constant"); - sofa::simpleapi::importPlugin("Sofa.Component.Topology.Container.Dynamic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mass"); + sofa::simpleapi::importPlugin(Sofa.Component.IO.Mesh); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Constant); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); createObject(m_root, "DefaultAnimationLoop"); @@ -110,7 +111,7 @@ class fake_TopologyScene createObject(m_root, "MeshMatrixMass"); if (m_topoType == sofa::geometry::ElementType::EDGE) { - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.Spring); createObject(m_root, "VectorSpringForceField", { {"useTopology", "true"} }); } diff --git a/Sofa/Component/Topology/Utility/src/sofa/component/topology/utility/TopologicalChangeProcessor.h b/Sofa/Component/Topology/Utility/src/sofa/component/topology/utility/TopologicalChangeProcessor.h index 8b9d51ed1c5..9fa48c8277d 100644 --- a/Sofa/Component/Topology/Utility/src/sofa/component/topology/utility/TopologicalChangeProcessor.h +++ b/Sofa/Component/Topology/Utility/src/sofa/component/topology/utility/TopologicalChangeProcessor.h @@ -29,7 +29,7 @@ #include -#include +#include #if SOFAMISCTOPOLOGY_HAVE_ZLIB @@ -58,52 +58,52 @@ class SOFA_COMPONENT_TOPOLOGY_UTILITY_API TopologicalChangeProcessor: public cor sofa::core::objectmodel::DataFileName m_filename; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData < type::vector< type::vector > > m_listChanges; + sofa::core::objectmodel::lifecycle::RenamedData < type::vector< type::vector > > m_listChanges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_interval; + sofa::core::objectmodel::lifecycle::RenamedData m_interval; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_shift; + sofa::core::objectmodel::lifecycle::RenamedData m_shift; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_loop; + sofa::core::objectmodel::lifecycle::RenamedData m_loop; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_useDataInputs; + sofa::core::objectmodel::lifecycle::RenamedData m_useDataInputs; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_timeToRemove; + sofa::core::objectmodel::lifecycle::RenamedData m_timeToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData >m_pointsToRemove; + sofa::core::objectmodel::lifecycle::RenamedData >m_pointsToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData > m_edgesToRemove; + sofa::core::objectmodel::lifecycle::RenamedData > m_edgesToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData > m_trianglesToRemove; + sofa::core::objectmodel::lifecycle::RenamedData > m_trianglesToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData > m_quadsToRemove; + sofa::core::objectmodel::lifecycle::RenamedData > m_quadsToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData > m_tetrahedraToRemove; + sofa::core::objectmodel::lifecycle::RenamedData > m_tetrahedraToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData > m_hexahedraToRemove; + sofa::core::objectmodel::lifecycle::RenamedData > m_hexahedraToRemove; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_saveIndicesAtInit; + sofa::core::objectmodel::lifecycle::RenamedData m_saveIndicesAtInit; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_epsilonSnapPath; + sofa::core::objectmodel::lifecycle::RenamedData m_epsilonSnapPath; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_epsilonSnapBorder; + sofa::core::objectmodel::lifecycle::RenamedData m_epsilonSnapBorder; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_TOPOLOGY_UTILITY() - sofa::core::objectmodel::RenamedData m_draw; + sofa::core::objectmodel::lifecycle::RenamedData m_draw; sofa::core::objectmodel::DataFileName d_filename; Data < type::vector< type::vector > > d_listChanges; ///< 0 for adding, 1 for removing, 2 for cutting and associated indices. diff --git a/Sofa/Component/Topology/Utility/tests/TopologicalChangeProcessor_test.cpp b/Sofa/Component/Topology/Utility/tests/TopologicalChangeProcessor_test.cpp index 2114477f075..4bda2e56669 100644 --- a/Sofa/Component/Topology/Utility/tests/TopologicalChangeProcessor_test.cpp +++ b/Sofa/Component/Topology/Utility/tests/TopologicalChangeProcessor_test.cpp @@ -46,7 +46,7 @@ struct TopologicalChangeProcessor_test: public BaseSimulationTest std::string m_fileName = ""; /// Method use at start to load the scene file - void SetUp() override + void doSetUp() override { // Load the scene from the xml file const std::string filePath = std::string(SOFA_COMPONENT_TOPOLOGY_UTILITY_TEST_SCENES_DIR) + "/" + m_fileName; @@ -68,7 +68,7 @@ struct TopologicalChangeProcessor_test: public BaseSimulationTest virtual bool testTopologyChanges() = 0; /// Unload the scene - void TearDown() override + void doTearDown() override { if (m_instance.root !=nullptr) sofa::simulation::node::unload(m_instance.root); diff --git a/Sofa/Component/Topology/Utility/tests/TopologyChecker_test.cpp b/Sofa/Component/Topology/Utility/tests/TopologyChecker_test.cpp index 2bc9934cb6f..e35ebdb0332 100644 --- a/Sofa/Component/Topology/Utility/tests/TopologyChecker_test.cpp +++ b/Sofa/Component/Topology/Utility/tests/TopologyChecker_test.cpp @@ -56,7 +56,7 @@ struct TopologyChecker_test: public BaseSimulationTest Node::SPtr m_topoNode = nullptr; /// Method use at start to load the scene file - void SetUp() override + void doSetUp() override { // Load the scene from the xml file const std::string filePath = std::string(SOFA_COMPONENT_TOPOLOGY_UTILITY_TEST_SCENES_DIR) + "/" + m_fileName; @@ -81,7 +81,7 @@ struct TopologyChecker_test: public BaseSimulationTest virtual bool testInvalidContainer() = 0; /// Unload the scene - void TearDown() override + void doTearDown() override { if (m_instance.root !=nullptr) sofa::simulation::node::unload(m_instance.root); diff --git a/Sofa/Component/Topology/src/sofa/component/topology/init.cpp b/Sofa/Component/Topology/src/sofa/component/topology/init.cpp index 145ed36c9ec..550085ae7c1 100644 --- a/Sofa/Component/Topology/src/sofa/component/topology/init.cpp +++ b/Sofa/Component/Topology/src/sofa/component/topology/init.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace sofa::component::topology { @@ -55,9 +56,9 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Container"); - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Mapping"); - factory->registerObjectsFromPlugin("Sofa.Component.Topology.Utility"); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Container); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Mapping); + factory->registerObjectsFromPlugin(Sofa.Component.Topology.Utility); } void init() diff --git a/Sofa/Component/Visual/CMakeLists.txt b/Sofa/Component/Visual/CMakeLists.txt index 8dd7b074047..d1a525f0c29 100644 --- a/Sofa/Component/Visual/CMakeLists.txt +++ b/Sofa/Component/Visual/CMakeLists.txt @@ -8,6 +8,7 @@ set(HEADER_FILES ${SOFACOMPONENTVISUAL_SOURCE_DIR}/init.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/BaseCamera.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/Camera.h + ${SOFACOMPONENTVISUAL_SOURCE_DIR}/CylinderVisualModel.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/InteractiveCamera.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/LineAxis.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/RecordedCamera.h @@ -24,6 +25,7 @@ set(SOURCE_FILES ${SOFACOMPONENTVISUAL_SOURCE_DIR}/init.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/BaseCamera.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/Camera.cpp + ${SOFACOMPONENTVISUAL_SOURCE_DIR}/CylinderVisualModel.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/InteractiveCamera.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/LineAxis.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/RecordedCamera.cpp diff --git a/Sofa/Component/Visual/src/sofa/component/visual/BaseCamera.h b/Sofa/Component/Visual/src/sofa/component/visual/BaseCamera.h index 5512f37e7ed..0e9e82b9d99 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/BaseCamera.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/BaseCamera.h @@ -30,7 +30,7 @@ #include #include -#include +#include namespace sofa::component::visual { @@ -68,55 +68,55 @@ class SOFA_COMPONENT_VISUAL_API BaseCamera : public core::objectmodel::BaseObjec }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_position; + sofa::core::objectmodel::lifecycle::RenamedData p_position; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_orientation; + sofa::core::objectmodel::lifecycle::RenamedData p_orientation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_lookAt; + sofa::core::objectmodel::lifecycle::RenamedData p_lookAt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_distance; + sofa::core::objectmodel::lifecycle::RenamedData p_distance; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_fieldOfView; + sofa::core::objectmodel::lifecycle::RenamedData p_fieldOfView; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_zNear; + sofa::core::objectmodel::lifecycle::RenamedData p_zNear; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_zFar; + sofa::core::objectmodel::lifecycle::RenamedData p_zFar; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_computeZClip; + sofa::core::objectmodel::lifecycle::RenamedData p_computeZClip; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_minBBox; + sofa::core::objectmodel::lifecycle::RenamedData p_minBBox; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_maxBBox; + sofa::core::objectmodel::lifecycle::RenamedData p_maxBBox; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_widthViewport; + sofa::core::objectmodel::lifecycle::RenamedData p_widthViewport; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_heightViewport; + sofa::core::objectmodel::lifecycle::RenamedData p_heightViewport; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_type; + sofa::core::objectmodel::lifecycle::RenamedData p_type; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_activated; + sofa::core::objectmodel::lifecycle::RenamedData p_activated; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_fixedLookAtPoint; + sofa::core::objectmodel::lifecycle::RenamedData p_fixedLookAtPoint; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData > p_modelViewMatrix; + sofa::core::objectmodel::lifecycle::RenamedData > p_modelViewMatrix; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData > p_projectionMatrix; + sofa::core::objectmodel::lifecycle::RenamedData > p_projectionMatrix; Data d_position; ///< Camera's position diff --git a/Sofa/Component/Visual/src/sofa/component/visual/CylinderVisualModel.cpp b/Sofa/Component/Visual/src/sofa/component/visual/CylinderVisualModel.cpp new file mode 100644 index 00000000000..98d778731bd --- /dev/null +++ b/Sofa/Component/Visual/src/sofa/component/visual/CylinderVisualModel.cpp @@ -0,0 +1,94 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include +#include + +namespace sofa::component::visual +{ + +void registerCylinderVisualModel(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Visualize a set of cylinders.") + .add< CylinderVisualModel >()); +} + +CylinderVisualModel::CylinderVisualModel() + : radius(initData(&radius, 1.0f, "radius", "Radius of the cylinder.")), + color(initData(&color, sofa::type::RGBAColor::white(), "color", "Color of the cylinders.")) + , d_edges(initData(&d_edges,"edges","List of edge indices")) +{ +} + +CylinderVisualModel::~CylinderVisualModel() = default; + +void CylinderVisualModel::init() +{ + VisualModel::init(); + + reinit(); +} + +void CylinderVisualModel::doDrawVisual(const core::visual::VisualParams* vparams) +{ + const VecCoord& pos = this->read( core::vec_id::read_access::position )->getValue(); + + auto* drawTool = vparams->drawTool(); + + drawTool->setLightingEnabled(true); + + const float _radius = radius.getValue(); + const sofa::type::RGBAColor& col = color.getValue(); + + const SeqEdges& edges = d_edges.getValue(); + + for(const auto& edge : edges) + { + const Coord& p1 = pos[edge[0]]; + const Coord& p2 = pos[edge[1]]; + + drawTool->drawCylinder(p1, p2, _radius, col); + } +} + +void CylinderVisualModel::exportOBJ(std::string name, std::ostream* out, std::ostream* /*mtl*/, Index& vindex, Index& /*nindex*/, Index& /*tindex*/, int& /*count*/) +{ + const VecCoord& x = this->read( core::vec_id::read_access::position )->getValue(); + const SeqEdges& edges = d_edges.getValue(); + + const int nbv = int(x.size()); + + *out << "g "<. * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include + +namespace sofa::component::visual +{ + +class SOFA_COMPONENT_VISUAL_API CylinderVisualModel : + public core::visual::VisualModel, public sofa::core::visual::VisualState +{ +public: + using Vec3State = sofa::core::visual::VisualState; + SOFA_CLASS2(CylinderVisualModel,core::visual::VisualModel, Vec3State); + +protected: + CylinderVisualModel(); + ~CylinderVisualModel() override; +public: + void init() override; + + void doDrawVisual(const core::visual::VisualParams* vparams) override; + + void exportOBJ(std::string /*name*/, std::ostream* /*out*/, std::ostream* /*mtl*/, Index& /*vindex*/, Index& /*nindex*/, Index& /*tindex*/, int& /*count*/) override; + +private: + Data radius; ///< Radius of the cylinder. + Data color; ///< Color of the cylinders. + + typedef sofa::type::vector SeqEdges; + Data d_edges; ///< List of edge indices + +public: + bool insertInNode( core::objectmodel::BaseNode* node ) override { Inherit1::insertInNode(node); Inherit2::insertInNode(node); return true; } + bool removeInNode( core::objectmodel::BaseNode* node ) override { Inherit1::removeInNode(node); Inherit2::removeInNode(node); return true; } +}; + +} // namespace sofa::component::visual diff --git a/Sofa/Component/Visual/src/sofa/component/visual/InteractiveCamera.h b/Sofa/Component/Visual/src/sofa/component/visual/InteractiveCamera.h index b8fc38d4913..35cf08acd05 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/InteractiveCamera.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/InteractiveCamera.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::core::objectmodel { @@ -46,13 +46,13 @@ class SOFA_COMPONENT_VISUAL_API InteractiveCamera : public BaseCamera enum { CAMERA_LOOKAT_PIVOT = 0, CAMERA_POSITION_PIVOT = 1, SCENE_CENTER_PIVOT = 2, WORLD_CENTER_PIVOT = 3}; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_zoomSpeed; + sofa::core::objectmodel::lifecycle::RenamedData p_zoomSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_panSpeed; + sofa::core::objectmodel::lifecycle::RenamedData p_panSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_pivot; + sofa::core::objectmodel::lifecycle::RenamedData p_pivot; Data d_zoomSpeed; ///< Zoom Speed Data d_panSpeed; ///< Pan Speed diff --git a/Sofa/Component/Visual/src/sofa/component/visual/RecordedCamera.h b/Sofa/Component/Visual/src/sofa/component/visual/RecordedCamera.h index 6c1f6f9591f..4675f3a40f0 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/RecordedCamera.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/RecordedCamera.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace sofa::component::visual { @@ -81,58 +81,58 @@ class SOFA_COMPONENT_VISUAL_API RecordedCamera : public BaseCamera public: SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_zoomSpeed; + sofa::core::objectmodel::lifecycle::RenamedData p_zoomSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_panSpeed; + sofa::core::objectmodel::lifecycle::RenamedData p_panSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_pivot; + sofa::core::objectmodel::lifecycle::RenamedData p_pivot; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_startTime; + sofa::core::objectmodel::lifecycle::RenamedData m_startTime; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_endTime; + sofa::core::objectmodel::lifecycle::RenamedData m_endTime; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationMode; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_translationMode; + sofa::core::objectmodel::lifecycle::RenamedData m_translationMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_navigationMode; + sofa::core::objectmodel::lifecycle::RenamedData m_navigationMode; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationSpeed; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationSpeed; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationCenter; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationCenter; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationStartPoint; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationStartPoint; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationLookAt; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationLookAt; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_rotationAxis; + sofa::core::objectmodel::lifecycle::RenamedData m_rotationAxis; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_cameraUp; + sofa::core::objectmodel::lifecycle::RenamedData m_cameraUp; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_drawRotation; + sofa::core::objectmodel::lifecycle::RenamedData p_drawRotation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData p_drawTranslation; + sofa::core::objectmodel::lifecycle::RenamedData p_drawTranslation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData> m_translationPositions; + sofa::core::objectmodel::lifecycle::RenamedData> m_translationPositions; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData > m_translationOrientations; + sofa::core::objectmodel::lifecycle::RenamedData > m_translationOrientations; Data d_startTime; ///< Time when the camera moves will start Data d_endTime; ///< Time when the camera moves will end (or loop) diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualModelImpl.h b/Sofa/Component/Visual/src/sofa/component/visual/VisualModelImpl.h index a225821b27d..2760ecc16ef 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualModelImpl.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualModelImpl.h @@ -32,7 +32,7 @@ #include -#include +#include namespace sofa::component::visual { @@ -85,55 +85,55 @@ class SOFA_COMPONENT_VISUAL_API VisualModelImpl : public core::visual::VisualMod sofa::core::topology::BaseMeshTopology* m_topology; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_initRestPositions; + sofa::core::objectmodel::lifecycle::RenamedData m_initRestPositions; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_useNormals; + sofa::core::objectmodel::lifecycle::RenamedData m_useNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_updateNormals; + sofa::core::objectmodel::lifecycle::RenamedData m_updateNormals; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_computeTangents; + sofa::core::objectmodel::lifecycle::RenamedData m_computeTangents; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_updateTangents; + sofa::core::objectmodel::lifecycle::RenamedData m_updateTangents; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_handleDynamicTopology; + sofa::core::objectmodel::lifecycle::RenamedData m_handleDynamicTopology; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_fixMergedUVSeams; + sofa::core::objectmodel::lifecycle::RenamedData m_fixMergedUVSeams; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_keepLines; + sofa::core::objectmodel::lifecycle::RenamedData m_keepLines; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData m_vertices2; + sofa::core::objectmodel::lifecycle::RenamedData m_vertices2; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecTexCoord > m_vtexcoords; + sofa::core::objectmodel::lifecycle::RenamedData< VecTexCoord > m_vtexcoords; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecCoord > m_vtangents; + sofa::core::objectmodel::lifecycle::RenamedData< VecCoord > m_vtangents; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecCoord > m_vbitangents; + sofa::core::objectmodel::lifecycle::RenamedData< VecCoord > m_vbitangents; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecVisualEdge > m_edges; + sofa::core::objectmodel::lifecycle::RenamedData< VecVisualEdge > m_edges; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecVisualTriangle > m_triangles; + sofa::core::objectmodel::lifecycle::RenamedData< VecVisualTriangle > m_triangles; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< VecVisualQuad > m_quads; + sofa::core::objectmodel::lifecycle::RenamedData< VecVisualQuad > m_quads; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< type::vector > m_vertPosIdx; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > m_vertPosIdx; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< type::vector > m_vertNormIdx; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > m_vertNormIdx; Data d_initRestPositions; ///< True if rest positions must be initialized with initial positions @@ -182,19 +182,19 @@ class SOFA_COMPONENT_VISUAL_API VisualModelImpl : public core::visual::VisualMod typedef sofa::type::Vec<3,Real> Vec3Real; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< Vec3Real >m_translation; + sofa::core::objectmodel::lifecycle::RenamedData< Vec3Real >m_translation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< Vec3Real > m_rotation; + sofa::core::objectmodel::lifecycle::RenamedData< Vec3Real > m_rotation; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< Vec3Real >m_scale; + sofa::core::objectmodel::lifecycle::RenamedData< Vec3Real >m_scale; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< TexCoord > m_scaleTex; + sofa::core::objectmodel::lifecycle::RenamedData< TexCoord > m_scaleTex; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< TexCoord > m_translationTex; + sofa::core::objectmodel::lifecycle::RenamedData< TexCoord > m_translationTex; Data< Vec3Real > d_translation; ///< Initial Translation of the object Data< Vec3Real > d_rotation; ///< Initial Rotation of the object @@ -237,13 +237,13 @@ class SOFA_COMPONENT_VISUAL_API VisualModelImpl : public core::visual::VisualMod sofa::type::Vec3f bbox[2]; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< sofa::type::Material >material; + sofa::core::objectmodel::lifecycle::RenamedData< sofa::type::Material >material; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData putOnlyTexCoords; + sofa::core::objectmodel::lifecycle::RenamedData putOnlyTexCoords; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData srgbTexturing; + sofa::core::objectmodel::lifecycle::RenamedData srgbTexturing; Data< sofa::type::Material > d_material; Data< bool > d_putOnlyTexCoords; @@ -283,10 +283,10 @@ class SOFA_COMPONENT_VISUAL_API VisualModelImpl : public core::visual::VisualMod } }; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< type::vector > materials; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > materials; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData< type::vector > groups; + sofa::core::objectmodel::lifecycle::RenamedData< type::vector > groups; Data< type::vector > d_materials; Data< type::vector > d_groups; diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.cpp b/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.cpp index 54931804369..0e50ca0d8f2 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.cpp +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.cpp @@ -62,17 +62,30 @@ VisualStyle::VisualStyle() displayFlags.setOriginalData(&d_displayFlags); } -void VisualStyle::fwdDraw(VisualParams* vparams) +void VisualStyle::updateVisualFlags(VisualParams* vparams) { backupFlags = vparams->displayFlags(); vparams->displayFlags() = sofa::core::visual::merge_displayFlags(backupFlags, d_displayFlags.getValue()); } -void VisualStyle::bwdDraw(VisualParams* vparams) +void VisualStyle::applyBackupFlags(VisualParams* vparams) { vparams->displayFlags() = backupFlags; } + +bool VisualStyle::insertInNode( sofa::core::objectmodel::BaseNode* node ) +{ + node->addVisualStyle(this); + return true; +} + +bool VisualStyle::removeInNode( sofa::core::objectmodel::BaseNode* node ) +{ + node->removeVisualStyle(this); + return true; +} + helper::WriteAccessor addVisualStyle( simulation::Node::SPtr node ) { const VisualStyle::SPtr visualStyle = New(); diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.h b/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.h index eb43f2f5ebf..7d647960592 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualStyle.h @@ -21,12 +21,14 @@ ******************************************************************************/ #pragma once #include +#include #include +#include #include #include -#include +#include namespace sofa::component::visual { @@ -56,21 +58,24 @@ namespace sofa::component::visual * showNormals hideNormals * showWireframe hideWireframe */ -class SOFA_COMPONENT_VISUAL_API VisualStyle : public sofa::core::visual::VisualModel +class SOFA_COMPONENT_VISUAL_API VisualStyle : public sofa::core::visual::BaseVisualStyle { public: - SOFA_CLASS(VisualStyle,sofa::core::visual::VisualModel); + SOFA_CLASS(VisualStyle,sofa::core::visual::BaseVisualStyle); typedef sofa::core::visual::VisualParams VisualParams; typedef sofa::core::visual::DisplayFlags DisplayFlags; protected: VisualStyle(); public: - void fwdDraw(VisualParams* ) override; - void bwdDraw(VisualParams* ) override; + void updateVisualFlags(VisualParams* ) override; + void applyBackupFlags(VisualParams* ) override; + + bool insertInNode(sofa::core::objectmodel::BaseNode* node) override; + bool removeInNode(sofa::core::objectmodel::BaseNode* node) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData displayFlags; + sofa::core::objectmodel::lifecycle::RenamedData displayFlags; Data d_displayFlags; ///< Display Flags diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualTransform.h b/Sofa/Component/Visual/src/sofa/component/visual/VisualTransform.h index 9fe684a9f5a..ae9d6842d1f 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualTransform.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualTransform.h @@ -25,7 +25,7 @@ #include #include -#include +#include namespace sofa::component::visual { @@ -53,10 +53,10 @@ class SOFA_COMPONENT_VISUAL_API VisualTransform : public sofa::core::visual::Vis void drawTransparent(const sofa::core::visual::VisualParams* vparams) override; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData transform; + sofa::core::objectmodel::lifecycle::RenamedData transform; SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_VISUAL() - sofa::core::objectmodel::RenamedData recursive; + sofa::core::objectmodel::lifecycle::RenamedData recursive; Data d_transform; ///< Transformation to apply Data d_recursive; ///< True to apply transform to all nodes below diff --git a/Sofa/Component/Visual/src/sofa/component/visual/init.cpp b/Sofa/Component/Visual/src/sofa/component/visual/init.cpp index b2f8a2c08eb..c4060d561ac 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/init.cpp +++ b/Sofa/Component/Visual/src/sofa/component/visual/init.cpp @@ -27,6 +27,7 @@ namespace sofa::component::visual { extern void registerCamera(sofa::core::ObjectFactory* factory); +extern void registerCylinderVisualModel(sofa::core::ObjectFactory* factory); extern void registerInteractiveCamera(sofa::core::ObjectFactory* factory); extern void registerLineAxis(sofa::core::ObjectFactory* factory); extern void registerRecordedCamera(sofa::core::ObjectFactory* factory); @@ -63,6 +64,7 @@ void registerObjects(sofa::core::ObjectFactory* factory) { registerCamera(factory); registerInteractiveCamera(factory); + registerCylinderVisualModel(factory); registerLineAxis(factory); registerRecordedCamera(factory); registerTrailRenderer(factory); diff --git a/Sofa/Component/src/sofa/component/init.cpp b/Sofa/Component/src/sofa/component/init.cpp index 00f7034fde6..6e1494deb84 100644 --- a/Sofa/Component/src/sofa/component/init.cpp +++ b/Sofa/Component/src/sofa/component/init.cpp @@ -45,6 +45,7 @@ #include #include +#include namespace sofa::component { @@ -73,27 +74,27 @@ const char* getModuleVersion() void registerObjects(sofa::core::ObjectFactory* factory) { - factory->registerObjectsFromPlugin("Sofa.Component.AnimationLoop"); - factory->registerObjectsFromPlugin("Sofa.Component.Collision"); - factory->registerObjectsFromPlugin("Sofa.Component.Constraint"); - factory->registerObjectsFromPlugin("Sofa.Component.Controller"); - factory->registerObjectsFromPlugin("Sofa.Component.Diffusion"); - factory->registerObjectsFromPlugin("Sofa.Component.Engine"); - factory->registerObjectsFromPlugin("Sofa.Component.Haptics"); - factory->registerObjectsFromPlugin("Sofa.Component.IO"); - factory->registerObjectsFromPlugin("Sofa.Component.LinearSolver"); - factory->registerObjectsFromPlugin("Sofa.Component.LinearSystem"); - factory->registerObjectsFromPlugin("Sofa.Component.Mapping"); - factory->registerObjectsFromPlugin("Sofa.Component.Mass"); - factory->registerObjectsFromPlugin("Sofa.Component.MechanicalLoad"); - factory->registerObjectsFromPlugin("Sofa.Component.ODESolver"); - factory->registerObjectsFromPlugin("Sofa.Component.Playback"); - factory->registerObjectsFromPlugin("Sofa.Component.SceneUtility"); - factory->registerObjectsFromPlugin("Sofa.Component.Setting"); - factory->registerObjectsFromPlugin("Sofa.Component.SolidMechanics"); - factory->registerObjectsFromPlugin("Sofa.Component.StateContainer"); - factory->registerObjectsFromPlugin("Sofa.Component.Topology"); - factory->registerObjectsFromPlugin("Sofa.Component.Visual"); + factory->registerObjectsFromPlugin(Sofa.Component.AnimationLoop); + factory->registerObjectsFromPlugin(Sofa.Component.Collision); + factory->registerObjectsFromPlugin(Sofa.Component.Constraint); + factory->registerObjectsFromPlugin(Sofa.Component.Controller); + factory->registerObjectsFromPlugin(Sofa.Component.Diffusion); + factory->registerObjectsFromPlugin(Sofa.Component.Engine); + factory->registerObjectsFromPlugin(Sofa.Component.Haptics); + factory->registerObjectsFromPlugin(Sofa.Component.IO); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSolver); + factory->registerObjectsFromPlugin(Sofa.Component.LinearSystem); + factory->registerObjectsFromPlugin(Sofa.Component.Mapping); + factory->registerObjectsFromPlugin(Sofa.Component.Mass); + factory->registerObjectsFromPlugin(Sofa.Component.MechanicalLoad); + factory->registerObjectsFromPlugin(Sofa.Component.ODESolver); + factory->registerObjectsFromPlugin(Sofa.Component.Playback); + factory->registerObjectsFromPlugin(Sofa.Component.SceneUtility); + factory->registerObjectsFromPlugin(Sofa.Component.Setting); + factory->registerObjectsFromPlugin(Sofa.Component.SolidMechanics); + factory->registerObjectsFromPlugin(Sofa.Component.StateContainer); + factory->registerObjectsFromPlugin(Sofa.Component.Topology); + factory->registerObjectsFromPlugin(Sofa.Component.Visual); } void init() diff --git a/Sofa/Component/test/CMakeLists.txt b/Sofa/Component/test/CMakeLists.txt new file mode 100644 index 00000000000..ae42441ddc2 --- /dev/null +++ b/Sofa/Component/test/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.22) + +project(Sofa.Component_test) + +set(SOURCE_FILES + Modules_test.cpp +) + +set(HEADER_FILES + Modules_test.h.in +) + +# The following block of code will generate a unit test for each of the target starting with Sofa.Component.* +# It checks that there is a corresponding data structure in Sofa.Config (otherwise it does not compile), and that the +# data structure converts to a string matching the target name. +set(ALL_SOFA_MODULES) +sofa_get_all_targets(all_targets "${CMAKE_SOURCE_DIR}") +foreach(target ${all_targets}) + if(target MATCHES "Sofa.Component.*" + AND NOT target MATCHES ".*_relocatable_install" + AND NOT target MATCHES ".*_test" + AND NOT target MATCHES ".*_simutest" + AND NOT target MATCHES ".*Testing") + string(REPLACE "." "" noDotTarget ${target}) #gtest does not like dots in test names + set(ALL_SOFA_MODULES "${ALL_SOFA_MODULES}\\\nTEST(SofaComponent, ${noDotTarget}){EXPECT_EQ(static_cast(${target}), \"${target}\");}") + endif() +endforeach() + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/Modules_test.h.in + ${CMAKE_CURRENT_BINARY_DIR}/Modules_test.h) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES}) +target_link_libraries(${PROJECT_NAME} Sofa.Testing) +target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) diff --git a/Sofa/Component/test/Modules_test.cpp b/Sofa/Component/test/Modules_test.cpp new file mode 100644 index 00000000000..389379fef85 --- /dev/null +++ b/Sofa/Component/test/Modules_test.cpp @@ -0,0 +1,25 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +ALL_SOFA_MODULES diff --git a/applications/plugins/SofaSimpleGUI/config.h.in b/Sofa/Component/test/Modules_test.h.in similarity index 86% rename from applications/plugins/SofaSimpleGUI/config.h.in rename to Sofa/Component/test/Modules_test.h.in index 5b9af608bb5..85dd4b6b3bf 100644 --- a/applications/plugins/SofaSimpleGUI/config.h.in +++ b/Sofa/Component/test/Modules_test.h.in @@ -19,16 +19,7 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#ifndef SOFASIMPLEGUI_CONFIG_H -#define SOFASIMPLEGUI_CONFIG_H - #include +#include -#ifdef SOFA_BUILD_SOFASIMPLEGUI -# define SOFA_TARGET SofaSimpleGUI -# define SOFA_SOFASIMPLEGUI_API SOFA_EXPORT_DYNAMIC_LIBRARY -#else -# define SOFA_SOFASIMPLEGUI_API SOFA_IMPORT_DYNAMIC_LIBRARY -#endif - -#endif +#cmakedefine ALL_SOFA_MODULES @ALL_SOFA_MODULES@ diff --git a/Sofa/GL/Component/Rendering2D/tests/OglLabel_test.cpp b/Sofa/GL/Component/Rendering2D/tests/OglLabel_test.cpp index 384a424251b..72092164165 100644 --- a/Sofa/GL/Component/Rendering2D/tests/OglLabel_test.cpp +++ b/Sofa/GL/Component/Rendering2D/tests/OglLabel_test.cpp @@ -53,9 +53,9 @@ using sofa::type::RGBAColor ; class OglLabelTest : public BaseTest { public: - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.GL.Component.Rendering2D"); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Rendering2D); } void checkExcludingAttributes() diff --git a/Sofa/GL/Component/Rendering3D/CMakeLists.txt b/Sofa/GL/Component/Rendering3D/CMakeLists.txt index 112674f2623..948bc3ac2b8 100644 --- a/Sofa/GL/Component/Rendering3D/CMakeLists.txt +++ b/Sofa/GL/Component/Rendering3D/CMakeLists.txt @@ -21,7 +21,6 @@ set(SOURCE_FILES ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/ClipPlane.cpp ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/DataDisplay.cpp ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/MergeVisualModels.cpp - ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/OglCylinderModel.cpp ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/OglModel.cpp ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/OglSceneFrame.cpp ${SOFAGLCOMPONENTRENDERING3D_SOURCE_DIR}/PointSplatModel.cpp diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglCylinderModel.cpp b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglCylinderModel.cpp deleted file mode 100644 index 9067ba2522b..00000000000 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglCylinderModel.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::gl::component::rendering3d -{ - -void registerOglCylinderModel(sofa::core::ObjectFactory* factory) -{ - factory->registerObjects(core::ObjectRegistrationData("OpenGL-based visualization for a cylinders over edges.") - .add< OglCylinderModel >()); -} - -using namespace sofa::defaulttype; -using namespace sofa::core::topology; - -OglCylinderModel::OglCylinderModel() - : radius(initData(&radius, 1.0f, "radius", "Radius of the cylinder.")), - color(initData(&color, sofa::type::RGBAColor(1.0,1.0,1.0,1.0), "color", "Color of the cylinders.")) - , d_edges(initData(&d_edges,"edges","List of edge indices")) - // , pointData(initData(&pointData, "pointData", "scalar field modulating point colors")) -{ -} - -OglCylinderModel::~OglCylinderModel() -{ -} - -void OglCylinderModel::init() -{ - VisualModel::init(); - - reinit(); -} - -void OglCylinderModel::doDrawVisual(const core::visual::VisualParams* vparams) -{ - const VecCoord& pos = this->read( core::vec_id::read_access::position )->getValue(); - - vparams->drawTool()->setLightingEnabled(true); - const float _radius = radius.getValue(); - - const sofa::type::RGBAColor col( r, g, b, a ); - - const SeqEdges& edges = d_edges.getValue(); - - for(auto edge : edges) - { - const Coord& p1 = pos[edge[0]]; - const Coord& p2 = pos[edge[1]]; - - vparams->drawTool()->drawCylinder(p1,p2,_radius,col); - } -} - - -void OglCylinderModel::setColor(float r, float g, float b, float a) -{ - this->r = r; - this->g = g; - this->b = b; - this->a = a; -} - -static int hexval(char c) -{ - if (c>='0' && c<='9') return c-'0'; - else if (c>='a' && c<='f') return (c-'a')+10; - else if (c>='A' && c<='F') return (c-'A')+10; - else return 0; -} - -void OglCylinderModel::setColor(std::string color) -{ - if (color.empty()) return; - float r = 1.0f; - float g = 1.0f; - float b = 1.0f; - float a = 1.0f; - if (color[0]>='0' && color[0]<='9') - { - sscanf(color.c_str(),"%f %f %f %f", &r, &g, &b, &a); - } - else if (color[0]=='#' && color.length()>=7) - { - r = (hexval(color[1])*16+hexval(color[2]))/255.0f; - g = (hexval(color[3])*16+hexval(color[4]))/255.0f; - b = (hexval(color[5])*16+hexval(color[6]))/255.0f; - if (color.length()>=9) - a = (hexval(color[7])*16+hexval(color[8]))/255.0f; - } - else if (color[0]=='#' && color.length()>=4) - { - r = (hexval(color[1])*17)/255.0f; - g = (hexval(color[2])*17)/255.0f; - b = (hexval(color[3])*17)/255.0f; - if (color.length()>=5) - a = (hexval(color[4])*17)/255.0f; - } - else if (color == "white") { r = 1.0f; g = 1.0f; b = 1.0f; } - else if (color == "black") { r = 0.0f; g = 0.0f; b = 0.0f; } - else if (color == "red") { r = 1.0f; g = 0.0f; b = 0.0f; } - else if (color == "green") { r = 0.0f; g = 1.0f; b = 0.0f; } - else if (color == "blue") { r = 0.0f; g = 0.0f; b = 1.0f; } - else if (color == "cyan") { r = 0.0f; g = 1.0f; b = 1.0f; } - else if (color == "magenta") { r = 1.0f; g = 0.0f; b = 1.0f; } - else if (color == "yellow") { r = 1.0f; g = 1.0f; b = 0.0f; } - else if (color == "gray") { r = 0.5f; g = 0.5f; b = 0.5f; } - else - { - msg_error() << "Unknown color " << color; - return; - } - setColor(r,g,b,a); -} - -void OglCylinderModel::exportOBJ(std::string name, std::ostream* out, std::ostream* /*mtl*/, Index& vindex, Index& /*nindex*/, Index& /*tindex*/, int& /*count*/) -{ - const VecCoord& x = this->read( core::vec_id::read_access::position )->getValue(); - const SeqEdges& edges = d_edges.getValue(); - - const int nbv = int(x.size()); - - *out << "g "< +#include -#include -#include -#include -#include -#include -#include +SOFA_HEADER_DEPRECATED("v24.12", "v25.06", "sofa/component/visual/CylinderVisualModel.h") -namespace sofa::core::topology -{ - class BaseMeshTopology; -} // namespace sofa::core::topology - -namespace sofa::core::behavior -{ - class BaseMechanicalState; -} // namespace sofa::core::behavior +#include namespace sofa::gl::component::rendering3d { - -// I have no idea what is Ogl in this component ?... -class SOFA_GL_COMPONENT_RENDERING3D_API OglCylinderModel : public core::visual::VisualModel, public sofa::core::visual::VisualState -{ -public: - using Vec3State = sofa::core::visual::VisualState; - SOFA_CLASS2(OglCylinderModel,core::visual::VisualModel, Vec3State); - - using Index = sofa::Index; -protected: - OglCylinderModel(); - ~OglCylinderModel() override; -public: - void init() override; - - void doDrawVisual(const core::visual::VisualParams* vparams) override; - - void exportOBJ(std::string /*name*/, std::ostream* /*out*/, std::ostream* /*mtl*/, Index& /*vindex*/, Index& /*nindex*/, Index& /*tindex*/, int& /*count*/) override; - -private: - void setColor(float r, float g, float b, float a); - void setColor(std::string color); - -private: - Data radius; ///< Radius of the cylinder. - // Data alpha; - Data color; ///< Color of the cylinders. - - typedef sofa::type::vector SeqEdges; - Data d_edges; ///< List of edge indices - - - float r,g,b,a; - // sofa::core::topology::PointData > pointData; - - typedef Vec3State::Coord Coord; - typedef Vec3State::VecCoord VecCoord; - typedef Vec3State::Real Real; - -public: - bool insertInNode( core::objectmodel::BaseNode* node ) override { Inherit1::insertInNode(node); Inherit2::insertInNode(node); return true; } - bool removeInNode( core::objectmodel::BaseNode* node ) override { Inherit1::removeInNode(node); Inherit2::removeInNode(node); return true; } -}; - -} // namespace sofa::gl::component::rendering3d +using OglCylinderModel = sofa::component::visual::CylinderVisualModel; +} diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.cpp b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.cpp index 1f88ebc2905..1e6341d4f12 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.cpp +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.cpp @@ -59,7 +59,7 @@ OglModel::OglModel() , blendEquation( initData(&blendEquation, "blendEquation", "if alpha blending is enabled this specifies how source and destination colors are combined") ) , sourceFactor( initData(&sourceFactor, "sfactor", "if alpha blending is enabled this specifies how the red, green, blue, and alpha source blending factors are computed") ) , destFactor( initData(&destFactor, "dfactor", "if alpha blending is enabled this specifies how the red, green, blue, and alpha destination blending factors are computed") ) - , tex(nullptr) + , m_tex(nullptr) , vbo(0), iboEdges(0), iboTriangles(0), iboQuads(0) , VBOGenDone(false), initDone(false), useEdges(false), useTriangles(false), useQuads(false), canUsePatches(false) , oldVerticesSize(0), oldNormalsSize(0), oldTexCoordsSize(0), oldTangentsSize(0), oldBitangentsSize(0), oldEdgesSize(0), oldTrianglesSize(0), oldQuadsSize(0) @@ -88,11 +88,16 @@ void OglModel::parse(core::objectmodel::BaseObjectDescription* arg) void OglModel::deleteTextures() { - if (tex!=nullptr) delete tex; + if (m_tex != nullptr) + { + delete m_tex; + m_tex = nullptr; + } for (unsigned int i = 0 ; i < textures.size() ; i++) { delete textures[i]; + textures[i] = nullptr; } } @@ -162,7 +167,7 @@ void OglModel::drawGroup(int ig, bool transparent) if (transparent ^ isTransparent) return; - if (!tex && m.useTexture && m.activated) + if (!m_tex && m.useTexture && m.activated) { //get the texture id corresponding to the current material size_t indexInTextureArray = size_t(materialTextureIdMap[g.materialId]); @@ -288,7 +293,7 @@ void OglModel::drawGroup(int ig, bool transparent) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - if (!tex && m.useTexture && m.activated) + if (!m_tex && m.useTexture && m.activated) { int indexInTextureArray = materialTextureIdMap[g.materialId]; if (indexInTextureArray < int(textures.size()) && textures[size_t(indexInTextureArray)]) @@ -379,12 +384,12 @@ void OglModel::internalDraw(const core::visual::VisualParams* vparams, bool tran glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); - if ((tex || d_putOnlyTexCoords.getValue()) ) + if ((m_tex || d_putOnlyTexCoords.getValue()) ) { - if(tex) + if(m_tex) { glEnable(GL_TEXTURE_2D); - tex->bind(); + m_tex->bind(); } const size_t textureArrayByteSize = vtexcoords.size()*sizeof(vtexcoords[0]); @@ -522,11 +527,11 @@ void OglModel::internalDraw(const core::visual::VisualParams* vparams, bool tran glDepthMask(GL_TRUE); } - if ( (tex || d_putOnlyTexCoords.getValue()) ) + if ( (m_tex || d_putOnlyTexCoords.getValue()) ) { - if (tex) + if (m_tex) { - tex->unbind(); + m_tex->unbind(); glDisable(GL_TEXTURE_2D); } glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -582,7 +587,7 @@ bool OglModel::hasTransparent() bool OglModel::hasTexture() { - return !textures.empty() || tex; + return !textures.empty() || m_tex; } bool OglModel::loadTexture(const std::string& filename) @@ -590,7 +595,7 @@ bool OglModel::loadTexture(const std::string& filename) helper::io::Image *img = helper::io::Image::Create(filename); if (!img) return false; - tex = new sofa::gl::Texture(img, true, true, false, d_srgbTexturing.getValue()); + m_tex = new sofa::gl::Texture(img, true, true, false, d_srgbTexturing.getValue()); return true; } @@ -696,9 +701,9 @@ void OglModel::doInitVisual(const core::visual::VisualParams*) void OglModel::initTextures() { - if (tex) + if (m_tex) { - tex->init(); + m_tex->init(); } else { @@ -755,7 +760,7 @@ void OglModel::initVertexBuffer() positionsBufferSize = (vertices.size()*sizeof(Vec3f)); normalsBufferSize = (vnormals.size()*sizeof(Vec3f)); - if (tex || d_putOnlyTexCoords.getValue() || !textures.empty()) + if (m_tex || d_putOnlyTexCoords.getValue() || !textures.empty()) { textureCoordsBufferSize = vtexcoords.size() * sizeof(vtexcoords[0]); @@ -847,7 +852,7 @@ void OglModel::updateVertexBuffer() positionsBufferSize = (vertices.size()*sizeof(Vec3f)); normalsBufferSize = (vnormals.size()*sizeof(Vec3f)); - if (tex || d_putOnlyTexCoords.getValue() || !textures.empty()) + if (m_tex || d_putOnlyTexCoords.getValue() || !textures.empty()) { textureCoordsBufferSize = (vtexcoords.size() * sizeof(vtexcoords[0])); @@ -873,7 +878,7 @@ void OglModel::updateVertexBuffer() normalBuffer); ////Texture coords - if (tex || d_putOnlyTexCoords.getValue() || !textures.empty()) + if (m_tex || d_putOnlyTexCoords.getValue() || !textures.empty()) { glBufferSubData(GL_ARRAY_BUFFER, positionsBufferSize + normalsBufferSize, diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.h b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.h index d5ff3338b15..672710715ec 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.h +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglModel.h @@ -74,7 +74,7 @@ class SOFA_GL_COMPONENT_RENDERING3D_API OglModel : public sofa::component::visua Data destFactor; ///< if alpha blending is enabled this specifies how the red, green, blue, and alpha destination blending factors are computed GLenum blendEq, sfactor, dfactor; - sofa::gl::Texture *tex; //this texture is used only if a texture name is specified in the scn + sofa::gl::Texture *m_tex; //this texture is used only if a texture name is specified in the scn GLuint vbo, iboEdges, iboTriangles, iboQuads; bool VBOGenDone, initDone, useEdges, useTriangles, useQuads, canUsePatches; size_t oldVerticesSize, oldNormalsSize, oldTexCoordsSize, oldTangentsSize, oldBitangentsSize, oldEdgesSize, oldTrianglesSize, oldQuadsSize; @@ -126,7 +126,7 @@ class SOFA_GL_COMPONENT_RENDERING3D_API OglModel : public sofa::component::visua bool isUseTriangles() { return useTriangles; } bool isUseQuads() { return useQuads; } - sofa::gl::Texture* getTex() const { return tex; } + sofa::gl::Texture* getTex() const { return m_tex; } GLuint getVbo() { return vbo; } GLuint getIboEdges() { return iboEdges; } GLuint getIboTriangles() { return iboTriangles; } diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/init.cpp b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/init.cpp index a4096afa836..61a827c7dea 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/init.cpp +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/init.cpp @@ -29,7 +29,6 @@ namespace sofa::gl::component::rendering3d extern void registerClipPlane(sofa::core::ObjectFactory* factory); extern void registerDataDisplay(sofa::core::ObjectFactory* factory); extern void registerMergeVisualModels(sofa::core::ObjectFactory* factory); -extern void registerOglCylinderModel(sofa::core::ObjectFactory* factory); extern void registerOglModel(sofa::core::ObjectFactory* factory); extern void registerOglSceneFrame(sofa::core::ObjectFactory* factory); extern void registerPointSplatModel(sofa::core::ObjectFactory* factory); @@ -62,7 +61,6 @@ void registerObjects(sofa::core::ObjectFactory* factory) registerClipPlane(factory); registerDataDisplay(factory); registerMergeVisualModels(factory); - registerOglCylinderModel(factory); registerOglModel(factory); registerOglSceneFrame(factory); registerPointSplatModel(factory); diff --git a/Sofa/GL/Component/Rendering3D/tests/ClipPlane_test.cpp b/Sofa/GL/Component/Rendering3D/tests/ClipPlane_test.cpp index f596ef6ebe9..ea821661307 100644 --- a/Sofa/GL/Component/Rendering3D/tests/ClipPlane_test.cpp +++ b/Sofa/GL/Component/Rendering3D/tests/ClipPlane_test.cpp @@ -60,10 +60,10 @@ int messageInited = initMessage(); class TestClipPlane : public BaseTest { public: - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.GL.Component.Rendering3D"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Rendering3D); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); } void checkClipPlaneValidAttributes(); diff --git a/Sofa/GL/Component/Shader/tests/LightManager_test.cpp b/Sofa/GL/Component/Shader/tests/LightManager_test.cpp index cde4ddc5a17..21da2ac3c47 100644 --- a/Sofa/GL/Component/Shader/tests/LightManager_test.cpp +++ b/Sofa/GL/Component/Shader/tests/LightManager_test.cpp @@ -53,10 +53,10 @@ namespace sofa { struct TestLightManager : public BaseTest { - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.GL.Component.Shader"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Shader); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); } }; @@ -94,7 +94,7 @@ void checkAttributes() TEST_F(TestLightManager, checkAttributes) { - sofa::simpleapi::importPlugin("Sofa.GL.Component.Shader"); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Shader); checkAttributes(); } diff --git a/Sofa/GL/Component/Shader/tests/Light_test.cpp b/Sofa/GL/Component/Shader/tests/Light_test.cpp index 29fbf100cf3..2a83d5535a5 100644 --- a/Sofa/GL/Component/Shader/tests/Light_test.cpp +++ b/Sofa/GL/Component/Shader/tests/Light_test.cpp @@ -48,10 +48,10 @@ int messageInited = initMessage(); class TestLight : public BaseTest { public: - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.GL.Component.Shader"); - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Shader); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); } void checkSpotLightValidAttributes(); diff --git a/Sofa/GUI/Component/src/sofa/gui/component/performer/ConstraintAttachBodyPerformer.inl b/Sofa/GUI/Component/src/sofa/gui/component/performer/ConstraintAttachBodyPerformer.inl index a64f733f7d2..fad3af6dc4b 100644 --- a/Sofa/GUI/Component/src/sofa/gui/component/performer/ConstraintAttachBodyPerformer.inl +++ b/Sofa/GUI/Component/src/sofa/gui/component/performer/ConstraintAttachBodyPerformer.inl @@ -97,7 +97,7 @@ bool ConstraintAttachBodyPerformer::startPartial(const BodyPicked& pi this->m_interactionObject = sofa::core::objectmodel::New >(m_mstate1, m_mstate2); auto* bconstraint = dynamic_cast< BilateralLagrangianConstraint< DataTypes >* >(this->m_interactionObject.get()); - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { // BilateralLagrangianConstraint::d_keepOrientDiff is protected auto* keepOrientDiffBaseData = bconstraint->findData("keepOrientationDifference"); diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp index 2b529ba25fa..0a57b822880 100644 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp +++ b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp @@ -154,7 +154,6 @@ QPixmap* getPixmap(core::objectmodel::Base* obj, bool haveInfo, bool haveWarning if(haveErrors) flags |= 1 << (4) ; - static std::map pixmaps; if (!pixmaps.count(flags)) { @@ -236,10 +235,10 @@ QPixmap* getPixmap(core::objectmodel::Base* obj, bool haveInfo, bool haveWarning flags |= 1 << (ALLCOLORS+1) ; if(haveWarning) - flags |= 1 << (ALLCOLORS+1) ; + flags |= 1 << (ALLCOLORS+2) ; if(haveErrors) - flags |= 1 << (ALLCOLORS+1) ; + flags |= 1 << (ALLCOLORS+3) ; static std::map pixmaps; if (!pixmaps.count(flags)) @@ -249,10 +248,8 @@ QPixmap* getPixmap(core::objectmodel::Base* obj, bool haveInfo, bool haveWarning if (flags & (1<setAlphaBuffer(true); img->fill(qRgba(0,0,0,0)); // Workaround for qt 3.x where fill() does not set the alpha channel for (int y=0 ; y < iconHeight ; y++) diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp index 7942456a333..0cca21cc8c3 100644 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp +++ b/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp @@ -241,8 +241,8 @@ SelectableItemWidget::SelectableItemWidget(QWidget* parent, const char* name, bool SelectableItemWidget::createWidgets() { - if (Tdata && Tdata->getValueTypeString() != "SelectableItem" || - baseData && baseData->getValueTypeString() != "SelectableItem") + if ((Tdata && Tdata->getValueTypeString() != "SelectableItem") || + (baseData && baseData->getValueTypeString() != "SelectableItem")) { return false; } diff --git a/Sofa/framework/Config/CMakeLists.txt b/Sofa/framework/Config/CMakeLists.txt index 4683959c252..e1374daf83c 100644 --- a/Sofa/framework/Config/CMakeLists.txt +++ b/Sofa/framework/Config/CMakeLists.txt @@ -85,6 +85,7 @@ set(HEADER_FILES ${SOFACONFIGSRC_ROOT}/config.h.in ${SOFACONFIGSRC_ROOT}/version.h.in ${SOFACONFIGSRC_ROOT}/url.h.in + ${SOFACONFIGSRC_ROOT}/Modules.h ) set(SOURCE_FILES ${SOFACONFIGSRC_ROOT}/initSofaConfig.cpp # necessary to build a library @@ -105,8 +106,8 @@ if((CMAKE_SYSTEM_NAME STREQUAL Windows) AND SOFA_USE_DEPENDENCY_PACK) endif() # Compile options -# Set C++17 -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) +# Set C++20 +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) set(SOFACONFIG_COMPILE_OPTIONS_DEBUG "") set(SOFACONFIG_COMPILE_OPTIONS_RELEASE "") diff --git a/Sofa/framework/Config/cmake/SofaMacrosUtils.cmake b/Sofa/framework/Config/cmake/SofaMacrosUtils.cmake index bff05bcce1f..bb4aa5490cc 100644 --- a/Sofa/framework/Config/cmake/SofaMacrosUtils.cmake +++ b/Sofa/framework/Config/cmake/SofaMacrosUtils.cmake @@ -42,6 +42,12 @@ endmacro() function(sofa_get_all_targets var) set(targets) - __get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR}) + + set(source_dir ${ARGV1}) #optional argument to define the source directory + if(NOT DEFINED source_dir) + set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}") # Set a default value + endif() + + __get_all_targets_recursive(targets ${source_dir}) set(${var} ${targets} PARENT_SCOPE) endfunction() diff --git a/Sofa/framework/Config/src/sofa/Modules.h b/Sofa/framework/Config/src/sofa/Modules.h new file mode 100644 index 00000000000..a02c7962c1e --- /dev/null +++ b/Sofa/framework/Config/src/sofa/Modules.h @@ -0,0 +1,179 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +/** + * The macro allows a simpler definition and maintenance of the module data + * structure + * @param name Module name + */ +#define START_MODULE(name, fullModuleName)\ + private:\ + struct Module ## name\ + {\ + private:\ + static constexpr const char* moduleName = fullModuleName;\ + public:\ + Module ## name() = default;\ + Module ## name(const Module ## name&) = delete;\ + Module ## name& operator=(const Module ## name&) = delete;\ + operator std::string() const { return moduleName; } + +#define END_MODULE(name)\ + };\ + public:\ + Module ## name name; + +#define MODULE(name, fullModuleName) \ + START_MODULE(name, fullModuleName) END_MODULE(name) + +inline struct ModuleSofa +{ +private: + static constexpr const char* moduleName = "Sofa"; +public: + ModuleSofa() = default; + ModuleSofa(const ModuleSofa&) = delete; + ModuleSofa& operator=(const ModuleSofa&) = delete; + operator std::string() const { return moduleName; } + + START_MODULE(Component, "Sofa.Component") + MODULE(AnimationLoop, "Sofa.Component.AnimationLoop") + START_MODULE(Collision, "Sofa.Component.Collision") + START_MODULE(Detection, "Sofa.Component.Collision.Detection") + MODULE(Algorithm, "Sofa.Component.Collision.Detection.Algorithm") + MODULE(Intersection, "Sofa.Component.Collision.Detection.Intersection") + END_MODULE(Detection) + MODULE(Geometry, "Sofa.Component.Collision.Geometry") + START_MODULE(Response, "Sofa.Component.Collision.Response") + MODULE(Contact, "Sofa.Component.Collision.Response.Contact") + MODULE(Mapper, "Sofa.Component.Collision.Response.Mapper") + END_MODULE(Response) + END_MODULE(Collision) + + START_MODULE(Constraint, "Sofa.Component.Constraint") + START_MODULE(Lagrangian, "Sofa.Component.Constraint.Lagrangian") + MODULE(Correction, "Sofa.Component.Constraint.Lagrangian.Correction") + MODULE(Model, "Sofa.Component.Constraint.Lagrangian.Model") + MODULE(Solver, "Sofa.Component.Constraint.Lagrangian.Solver") + END_MODULE(Lagrangian) + + MODULE(Projective, "Sofa.Component.Constraint.Projective") + END_MODULE(Constraint) + + MODULE(Controller, "Sofa.Component.Controller") + MODULE(Diffusion, "Sofa.Component.Diffusion") + + START_MODULE(Engine, "Sofa.Component.Engine") + MODULE(Analyze, "Sofa.Component.Engine.Analyze") + MODULE(Generate, "Sofa.Component.Engine.Generate") + MODULE(Select, "Sofa.Component.Engine.Select") + MODULE(Transform, "Sofa.Component.Engine.Transform") + END_MODULE(Engine) + + MODULE(Haptics, "Sofa.Component.Haptics") + + START_MODULE(IO, "Sofa.Component.IO") + MODULE(Mesh, "Sofa.Component.IO.Mesh") + END_MODULE(IO) + + START_MODULE(LinearSolver, "Sofa.Component.LinearSolver") + MODULE(Direct, "Sofa.Component.LinearSolver.Direct") + MODULE(Iterative, "Sofa.Component.LinearSolver.Iterative") + MODULE(Ordering, "Sofa.Component.LinearSolver.Ordering") + MODULE(Preconditioner, "Sofa.Component.LinearSolver.Preconditioner") + END_MODULE(LinearSolver) + + MODULE(LinearSystem, "Sofa.Component.LinearSystem") + + START_MODULE(Mapping, "Sofa.Component.Mapping") + MODULE(Linear, "Sofa.Component.Mapping.Linear") + MODULE(MappedMatrix, "Sofa.Component.Mapping.MappedMatrix") + MODULE(NonLinear, "Sofa.Component.Mapping.NonLinear") + END_MODULE(Mapping) + + MODULE(Mass, "Sofa.Component.Mass") + MODULE(MechanicalLoad, "Sofa.Component.MechanicalLoad") + + START_MODULE(ODESolver, "Sofa.Component.ODESolver") + MODULE(Backward, "Sofa.Component.ODESolver.Backward") + MODULE(Forward, "Sofa.Component.ODESolver.Forward") + END_MODULE(ODESolver) + + MODULE(Playback, "Sofa.Component.Playback") + MODULE(SceneUtility, "Sofa.Component.SceneUtility") + MODULE(Setting, "Sofa.Component.Setting") + + START_MODULE(SolidMechanics, "Sofa.Component.SolidMechanics") + START_MODULE(FEM, "Sofa.Component.SolidMechanics.FEM") + MODULE(Elastic, "Sofa.Component.SolidMechanics.FEM.Elastic") + MODULE(HyperElastic, "Sofa.Component.SolidMechanics.FEM.HyperElastic") + MODULE(NonUniform, "Sofa.Component.SolidMechanics.FEM.NonUniform") + END_MODULE(FEM) + + MODULE(Spring, "Sofa.Component.SolidMechanics.Spring") + MODULE(TensorMass, "Sofa.Component.SolidMechanics.TensorMass") + END_MODULE(SolidMechanics) + + MODULE(StateContainer, "Sofa.Component.StateContainer") + + START_MODULE(Topology, "Sofa.Component.Topology") + START_MODULE(Container, "Sofa.Component.Topology.Container") + MODULE(Constant, "Sofa.Component.Topology.Container.Constant") + MODULE(Dynamic, "Sofa.Component.Topology.Container.Dynamic") + MODULE(Grid, "Sofa.Component.Topology.Container.Grid") + END_MODULE(Container) + MODULE(Mapping, "Sofa.Component.Topology.Mapping") + MODULE(Utility, "Sofa.Component.Topology.Utility") + END_MODULE(Topology) + + MODULE(Visual, "Sofa.Component.Visual") + END_MODULE(Component) + + START_MODULE(GL, "Sofa.GL") + START_MODULE(Component, "Sofa.GL.Component") + MODULE(Engine, "Sofa.GL.Component.Engine") + MODULE(Rendering2D, "Sofa.GL.Component.Rendering2D") + MODULE(Rendering3D, "Sofa.GL.Component.Rendering3D") + MODULE(Shader, "Sofa.GL.Component.Shader") + END_MODULE(Component) + END_MODULE(GL) + + START_MODULE(GUI, "Sofa.GUI") + MODULE(Component, "Sofa.GUI.Component") + END_MODULE(GUI) + +} +/** + * Nested data structure reproducing the architecture of SOFA modules (tree-like + * structure). All modules and submodules can convert implicitly to std::string. + * This allows to use this structure as a string in functions accepting a module + * name as a string. From the developer point of view, the use of this data + * structure is less error-prone compared to any string and the auto-completion + * allows faster developments. + */ +Sofa; + +#undef START_MODULE +#undef END_MODULE +#undef MODULE diff --git a/Sofa/framework/Core/CMakeLists.txt b/Sofa/framework/Core/CMakeLists.txt index 4910d364c28..35669bcbb87 100644 --- a/Sofa/framework/Core/CMakeLists.txt +++ b/Sofa/framework/Core/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES ${SRC_ROOT}/ExecParams.h ${SRC_ROOT}/fwd.h ${SRC_ROOT}/init.h + ${SRC_ROOT}/IntrusiveObject.h ${SRC_ROOT}/Mapping.h ${SRC_ROOT}/Mapping.inl ${SRC_ROOT}/MappingHelper.h @@ -150,8 +151,6 @@ set(HEADER_FILES ${SRC_ROOT}/objectmodel/DataFileName.h ${SRC_ROOT}/objectmodel/DataFileNameVector.h ${SRC_ROOT}/objectmodel/DataLink.h - ${SRC_ROOT}/objectmodel/DeprecatedData.h - ${SRC_ROOT}/objectmodel/RemovedData.h ${SRC_ROOT}/objectmodel/DetachNodeEvent.h ${SRC_ROOT}/objectmodel/Event.h ${SRC_ROOT}/objectmodel/GUIEvent.h @@ -160,9 +159,11 @@ set(HEADER_FILES ${SRC_ROOT}/objectmodel/JoystickEvent.h ${SRC_ROOT}/objectmodel/KeypressedEvent.h ${SRC_ROOT}/objectmodel/KeyreleasedEvent.h + ${SRC_ROOT}/objectmodel/lifecycle/DeprecatedData.h + ${SRC_ROOT}/objectmodel/lifecycle/RemovedData.h + ${SRC_ROOT}/objectmodel/lifecycle/RenamedData.h ${SRC_ROOT}/objectmodel/Link.h ${SRC_ROOT}/objectmodel/MouseEvent.h - ${SRC_ROOT}/objectmodel/RenamedData.h ${SRC_ROOT}/objectmodel/SPtr.h ${SRC_ROOT}/objectmodel/ScriptEvent.h ${SRC_ROOT}/objectmodel/TypeOfInsertion.h @@ -187,6 +188,7 @@ set(HEADER_FILES ${SRC_ROOT}/topology/TopologySubsetData.cpp ${SRC_ROOT}/topology/TopologySubsetIndices.h ${SRC_ROOT}/trait/DataTypes.h + ${SRC_ROOT}/visual/BaseVisualStyle.h ${SRC_ROOT}/visual/Data[DisplayFlags].h ${SRC_ROOT}/visual/DisplayFlags.h ${SRC_ROOT}/visual/FlagTreeItem.h @@ -216,6 +218,7 @@ set(SOURCE_FILES ${SRC_ROOT}/DataTrackerCallback.cpp ${SRC_ROOT}/DataTrackerFunctor.cpp ${SRC_ROOT}/ExecParams.cpp + ${SRC_ROOT}/IntrusiveObject.cpp ${SRC_ROOT}/fwd.cpp ${SRC_ROOT}/init.cpp ${SRC_ROOT}/Mapping.cpp @@ -296,7 +299,6 @@ set(SOURCE_FILES ${SRC_ROOT}/objectmodel/DataFileNameVector.cpp ${SRC_ROOT}/objectmodel/DataLink.cpp ${SRC_ROOT}/objectmodel/DetachNodeEvent.cpp - ${SRC_ROOT}/objectmodel/DeprecatedData.cpp ${SRC_ROOT}/objectmodel/Event.cpp ${SRC_ROOT}/objectmodel/GUIEvent.cpp ${SRC_ROOT}/objectmodel/HapticDeviceEvent.cpp @@ -304,6 +306,7 @@ set(SOURCE_FILES ${SRC_ROOT}/objectmodel/JoystickEvent.cpp ${SRC_ROOT}/objectmodel/KeypressedEvent.cpp ${SRC_ROOT}/objectmodel/KeyreleasedEvent.cpp + ${SRC_ROOT}/objectmodel/lifecycle/DeprecatedData.cpp ${SRC_ROOT}/objectmodel/MouseEvent.cpp ${SRC_ROOT}/objectmodel/ScriptEvent.cpp ${SRC_ROOT}/objectmodel/Tag.cpp diff --git a/applications/plugins/SensableEmulation/config.h b/Sofa/framework/Core/src/sofa/core/IntrusiveObject.cpp similarity index 83% rename from applications/plugins/SensableEmulation/config.h rename to Sofa/framework/Core/src/sofa/core/IntrusiveObject.cpp index fbe888819f0..9b4325340f4 100644 --- a/applications/plugins/SensableEmulation/config.h +++ b/Sofa/framework/Core/src/sofa/core/IntrusiveObject.cpp @@ -19,16 +19,20 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#ifndef SENSABLEEMULATION_CONFIG_H -#define SENSABLEEMULATION_CONFIG_H +#include -#include +namespace sofa::core +{ +void IntrusiveObject::addRef() +{ + ++ref_counter; +} -#ifdef SOFA_BUILD_SENSABLEEMULATIONPLUGIN -# define SOFA_TARGET SensableEmulation -# define SOFA_SENSABLEEMUPLUGIN_API SOFA_EXPORT_DYNAMIC_LIBRARY -#else -# define SOFA_SENSABLEEMUPLUGIN_API SOFA_IMPORT_DYNAMIC_LIBRARY -#endif - -#endif +void IntrusiveObject::release() +{ + if (ref_counter.fetch_sub(1) == 1) + { + delete this; + } +} +} diff --git a/applications/plugins/SensableEmulation/initSensableEmulation.cpp b/Sofa/framework/Core/src/sofa/core/IntrusiveObject.h similarity index 61% rename from applications/plugins/SensableEmulation/initSensableEmulation.cpp rename to Sofa/framework/Core/src/sofa/core/IntrusiveObject.h index 1c218b3ab77..0b6ed680520 100644 --- a/applications/plugins/SensableEmulation/initSensableEmulation.cpp +++ b/Sofa/framework/Core/src/sofa/core/IntrusiveObject.h @@ -19,61 +19,37 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include +#pragma once +#include +#include -namespace sofa +namespace sofa::core { -namespace component +/** + * The `IntrusiveObject` class implements an internal reference counting mechanism + * to manage its lifetime. It is intended to work with intrusive smart pointers like + * `boost::intrusive_ptr`. + */ +class SOFA_CORE_API IntrusiveObject { + std::atomic ref_counter { 0 }; -//Here are just several convenient functions to help user to know what contains the plugin + void addRef(); + void release(); -extern "C" { - SOFA_SENSABLEEMUPLUGIN_API void initExternalModule(); - SOFA_SENSABLEEMUPLUGIN_API const char* getModuleName(); - SOFA_SENSABLEEMUPLUGIN_API const char* getModuleVersion(); - SOFA_SENSABLEEMUPLUGIN_API const char* getModuleLicense(); - SOFA_SENSABLEEMUPLUGIN_API const char* getModuleDescription(); - SOFA_SENSABLEEMUPLUGIN_API const char* getModuleComponentList(); -} - -void initExternalModule() -{ - static bool first = true; - if (first) + friend inline void intrusive_ptr_add_ref(IntrusiveObject* p) { - first = false; + p->addRef(); } -} -const char* getModuleName() -{ - return "SensableEmulation"; -} - -const char* getModuleVersion() -{ - return "beta 1.0"; -} - -const char* getModuleLicense() -{ - return "LGPL"; -} + friend inline void intrusive_ptr_release(IntrusiveObject* p) + { + p->release(); + } -const char* getModuleDescription() -{ - return "Force feedback with sensable devices into SOFA Framework"; -} +protected: + virtual ~IntrusiveObject() = default; +}; -const char* getModuleComponentList() -{ - return "OmniDriverEmu"; } - -} // namespace component - -} // namespace sofa - - diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp b/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp index 6f9d02cf2c8..20402e7c25f 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactory.cpp @@ -775,7 +775,8 @@ bool ObjectFactory::registerObjectsFromPlugin(const std::string& pluginName) // do not register if it was already done before if(m_registeredPluginSet.count(pluginName) > 0) { - // msg_warning("ObjectFactory") << pluginName << " has already registered its components."; + // This warning should be generalized (i.e not only in dev mode) when runSofa will not auto-load modules/plugins by default anymore + dmsg_warning("ObjectFactory") << pluginName << " has already registered its components."; return false; } @@ -837,8 +838,8 @@ RegisterObject& RegisterObject::addCreator(std::string classname, std::string te RegisterObject::operator int() const { - //std::cout << "Implicit object registration is deprecrated since v24.06. Check #4429 for more information." << std::endl; - // msg_warning("RegisterObject") << "Implicit object registration is deprecrated since v24.06. Check #4429 for more information."; + dmsg_warning("RegisterObject") << m_objectRegistrationdata.entry.className + << ": Implicit object registration is deprecated since v24.12. Check #4429 for more information."; return commitTo(ObjectFactory::getInstance()); } diff --git a/Sofa/framework/Core/src/sofa/core/ObjectFactory.h b/Sofa/framework/Core/src/sofa/core/ObjectFactory.h index 302c70f3590..2126496ac8e 100644 --- a/Sofa/framework/Core/src/sofa/core/ObjectFactory.h +++ b/Sofa/framework/Core/src/sofa/core/ObjectFactory.h @@ -377,12 +377,14 @@ class SOFA_CORE_API ObjectRegistrationData /// This is the final operation that will actually commit the additions to the ObjectFactory. bool commitTo(sofa::core::ObjectFactory* objectFactory) const; + + friend class RegisterObject; }; // Legacy structure, to keep compatibility with olden code // using the singleton to get the instance of ObjectFactory -class /* SOFA_ATTRIBUTE_DEPRECATED__REGISTEROBJECT() */ SOFA_CORE_API RegisterObject +class SOFA_ATTRIBUTE_DEPRECATED__REGISTEROBJECT() SOFA_CORE_API RegisterObject { private: ObjectRegistrationData m_objectRegistrationdata; diff --git a/Sofa/framework/Core/src/sofa/core/behavior/BaseConstraintSet.h b/Sofa/framework/Core/src/sofa/core/behavior/BaseConstraintSet.h index 8e0d839fcba..896e7641675 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/BaseConstraintSet.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/BaseConstraintSet.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace sofa::core::behavior { @@ -94,7 +94,7 @@ class SOFA_CORE_API BaseConstraintSet : public virtual objectmodel::BaseObject Data< sofa::Index > d_constraintIndex; ///< Constraint index (first index in the right hand term resolution vector) SOFA_ATTRIBUTE_DEPRECATED__CORE_RENAME_DATA_IN_CORE() - sofa::core::objectmodel::RenamedData< unsigned int > m_constraintIndex; + sofa::core::objectmodel::lifecycle::RenamedData< unsigned int > m_constraintIndex; bool insertInNode( objectmodel::BaseNode* node ) override; bool removeInNode( objectmodel::BaseNode* node ) override; diff --git a/Sofa/framework/Core/src/sofa/core/behavior/BaseMechanicalState.h b/Sofa/framework/Core/src/sofa/core/behavior/BaseMechanicalState.h index d761f405d40..9344498e63f 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/BaseMechanicalState.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/BaseMechanicalState.h @@ -188,7 +188,7 @@ class SOFA_CORE_API BaseMechanicalState : public virtual BaseState /// Called at the end of each integration step. virtual void endIntegration(const ExecParams* params, SReal /*dt*/) { - vOp(params, VecId::externalForce(), ConstVecId::null(), ConstVecId::null(), 1.0); // externalForce = 0 + vOp(params, sofa::core::vec_id::write_access::externalForce, ConstVecId::null(), ConstVecId::null(), 1.0); // externalForce = 0 } /// Set F = 0 @@ -202,7 +202,7 @@ class SOFA_CORE_API BaseMechanicalState : public virtual BaseState /// Add stored external forces to F virtual void accumulateForce( const ExecParams* params, VecDerivId f = vec_id::write_access::force ) { - vOp( params, f, f, ConstVecId::externalForce(), 1.0 ); // f += externalForce + vOp( params, f, f, sofa::core::vec_id::read_access::externalForce, 1.0 ); // f += externalForce } /// @} diff --git a/Sofa/framework/Core/src/sofa/core/config.h.in b/Sofa/framework/Core/src/sofa/core/config.h.in index 3742a00dc3f..a30bd9f6493 100644 --- a/Sofa/framework/Core/src/sofa/core/config.h.in +++ b/Sofa/framework/Core/src/sofa/core/config.h.in @@ -143,7 +143,7 @@ #define SOFA_ATTRIBUTE_DEPRECATED__FREE_POSITION() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::freePosition or sofa::core::vec_id::write_access::freePosition instead") #define SOFA_ATTRIBUTE_DEPRECATED__RESET_POSITION() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::resetPosition or sofa::core::vec_id::write_access::resetPosition instead") - #define SOFA_ATTRIBUTE_DEPRECATED__VELOCITY() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::velocity or sofa::core::vec_id::write_access::position velocity") + #define SOFA_ATTRIBUTE_DEPRECATED__VELOCITY() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::velocity or sofa::core::vec_id::write_access::velocity instead") #define SOFA_ATTRIBUTE_DEPRECATED__RESET_VELOCITY() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::resetVelocity or sofa::core::vec_id::write_access::resetVelocity instead") #define SOFA_ATTRIBUTE_DEPRECATED__FREE_VELOCITY() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::freeVelocity or sofa::core::vec_id::write_access::freeVelocity instead") #define SOFA_ATTRIBUTE_DEPRECATED__NORMAL() SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.06", "Use the variable sofa::core::vec_id::read_access::normal or sofa::core::vec_id::write_access::normal instead") diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/Base.cpp b/Sofa/framework/Core/src/sofa/core/objectmodel/Base.cpp index 1888327ab0d..6234a73b390 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/Base.cpp +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/Base.cpp @@ -51,8 +51,7 @@ using std::string; static const std::string unnamed_label=std::string("unnamed"); Base::Base() - : ref_counter(0) - , name(initData(&name,unnamed_label,"name","object name")) + : name(initData(&name,unnamed_label,"name","object name")) , f_printLog(initData(&f_printLog, false, "printLog", "if true, emits extra messages at runtime.")) , f_tags(initData( &f_tags, "tags", "list of the subsets the object belongs to")) , f_bbox(initData( &f_bbox, "bbox", "this object bounding box")) @@ -78,18 +77,6 @@ Base::~Base() { } -void Base::addRef() -{ - ++ref_counter; -} - -void Base::release() -{ - if (ref_counter.fetch_sub(1) == 1) - { - delete this; - } -} void Base::addUpdateCallback(const std::string& name, diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/Base.h b/Sofa/framework/Core/src/sofa/core/objectmodel/Base.h index 74948aa9674..81202a77fc3 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/Base.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/Base.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -33,11 +33,11 @@ #include #include -#include #include #include #include +#include #include #define SOFA_BASE_CAST_IMPLEMENTATION(CLASSNAME) \ @@ -55,7 +55,7 @@ namespace sofa::core::objectmodel * All classes deriving from Base should use the SOFA_CLASS macro within their declaration (see BaseClass.h). * */ -class SOFA_CORE_API Base +class SOFA_CORE_API Base : public IntrusiveObject { public: typedef Base* Ptr; @@ -86,20 +86,6 @@ class SOFA_CORE_API Base Base(const Base& b); Base& operator=(const Base& b); - std::atomic ref_counter; - void addRef(); - void release(); - - friend inline void intrusive_ptr_add_ref(Base* p) - { - p->addRef(); - } - - friend inline void intrusive_ptr_release(Base* p) - { - p->release(); - } - protected: std::map m_internalEngine; diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseContext.h b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseContext.h index 6163cb1a95e..e0ae2ddc670 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseContext.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseContext.h @@ -413,7 +413,7 @@ class BaseContext::GetObjectsCallBackT : public BaseContext::GetObjectsCallBack GetObjectsCallBackT(Container* d) : dest(d) {} void operator()(void* ptr) override { - if constexpr (sofa::type::trait::is_vector::value) + if constexpr (sofa::type::trait::is_vector) { dest->push_back(reinterpret_cast(ptr)); } diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseNode.h b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseNode.h index 79cbe8e255b..16d8e21ee3f 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseNode.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseNode.h @@ -23,6 +23,7 @@ #include #include +#include namespace sofa::core::objectmodel { @@ -172,6 +173,7 @@ class SOFA_CORE_API BaseNode : public virtual Base BASENODE_ADD_SPECIAL_COMPONENT( core::objectmodel::ConfigurationSetting, ConfigurationSetting, configurationSetting ) BASENODE_ADD_SPECIAL_COMPONENT( core::visual::Shader, Shader, shaders ) BASENODE_ADD_SPECIAL_COMPONENT( core::visual::VisualModel, VisualModel, visualModel ) + BASENODE_ADD_SPECIAL_COMPONENT( core::visual::BaseVisualStyle, VisualStyle, visualStyle ) BASENODE_ADD_SPECIAL_COMPONENT( core::visual::VisualManager, VisualManager, visualManager ) BASENODE_ADD_SPECIAL_COMPONENT( core::CollisionModel, CollisionModel, collisionModel ) BASENODE_ADD_SPECIAL_COMPONENT( core::collision::Pipeline, CollisionPipeline, collisionPipeline ) diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/DeprecatedData.cpp b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/DeprecatedData.cpp similarity index 97% rename from Sofa/framework/Core/src/sofa/core/objectmodel/DeprecatedData.cpp rename to Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/DeprecatedData.cpp index 5b1f42517be..b31e699fa5a 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/DeprecatedData.cpp +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/DeprecatedData.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace sofa::core::objectmodel::lifecycle { diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/DeprecatedData.h b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/DeprecatedData.h similarity index 100% rename from Sofa/framework/Core/src/sofa/core/objectmodel/DeprecatedData.h rename to Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/DeprecatedData.h diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/RemovedData.h b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RemovedData.h similarity index 97% rename from Sofa/framework/Core/src/sofa/core/objectmodel/RemovedData.h rename to Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RemovedData.h index 43e501af011..78c6fffcf1e 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/RemovedData.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RemovedData.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace sofa::core::objectmodel::lifecycle { diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/RenamedData.h b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RenamedData.h similarity index 99% rename from Sofa/framework/Core/src/sofa/core/objectmodel/RenamedData.h rename to Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RenamedData.h index 47b4933a87c..f22e7149b7e 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/RenamedData.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/lifecycle/RenamedData.h @@ -6,7 +6,7 @@ namespace sofa { -namespace core::objectmodel +namespace core::objectmodel::lifecycle { diff --git a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp index f1fbc45235f..7eb1494c17d 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp +++ b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp @@ -23,7 +23,6 @@ #include #include #include - namespace sofa::core::topology { diff --git a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h index 2a5348f3eb3..b8b36581ab4 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h +++ b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h @@ -85,6 +85,9 @@ class SOFA_CORE_API BaseMeshTopology : public core::topology::Topology public: void init() override; + /// Method to be overriden by child class to create all the topology buffers + virtual void computeCrossElementBuffers() {} + /// Load the topology from a file. /// /// The default implementation supports the following formats: obj, gmsh, mesh (custom simple text file), xs3 (deprecated description of mass-springs networks). diff --git a/applications/plugins/SofaSimpleGUI/initSimpleGUI.cpp b/Sofa/framework/Core/src/sofa/core/visual/BaseVisualStyle.h similarity index 58% rename from applications/plugins/SofaSimpleGUI/initSimpleGUI.cpp rename to Sofa/framework/Core/src/sofa/core/visual/BaseVisualStyle.h index 7cdc42b84c1..bfeb50bdd67 100644 --- a/applications/plugins/SofaSimpleGUI/initSimpleGUI.cpp +++ b/Sofa/framework/Core/src/sofa/core/visual/BaseVisualStyle.h @@ -19,62 +19,33 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include +#pragma once +#include +#include +#include +#include -namespace sofa::component +namespace sofa::core::visual { - //Here are just several convenient functions to help user to know what contains the plugin - - extern "C" { - SOFA_SOFASIMPLEGUI_API void initExternalModule(); - SOFA_SOFASIMPLEGUI_API const char* getModuleName(); - SOFA_SOFASIMPLEGUI_API const char* getModuleVersion(); - SOFA_SOFASIMPLEGUI_API const char* getModuleLicense(); - SOFA_SOFASIMPLEGUI_API const char* getModuleDescription(); - SOFA_SOFASIMPLEGUI_API const char* getModuleComponentList(); - } - - void initExternalModule() - { - static bool first = true; - if (first) - { - first = false; - } - } - - const char* getModuleName() - { - return "SimpleGUI"; - } - - const char* getModuleVersion() - { - return "0.2"; - } - - const char* getModuleLicense() - { - return "LGPL"; - } - - - const char* getModuleDescription() - { - return "TODO: replace this with the description of your plugin"; - } +class SOFA_CORE_API BaseVisualStyle : public sofa::core::objectmodel::BaseObject +{ +public: + SOFA_CLASS(BaseVisualStyle,sofa::core::objectmodel::BaseObject); - const char* getModuleComponentList() - { - /// string containing the names of the classes provided by the plugin - return ""; - //return "MyMappingPendulumInPlane, MyBehaviorModel, MyProjectiveConstraintSet"; - } + typedef sofa::core::visual::VisualParams VisualParams; + typedef sofa::core::visual::DisplayFlags DisplayFlags; +protected: + BaseVisualStyle() { } + ~BaseVisualStyle() override { } +public: + virtual void updateVisualFlags(VisualParams* ) { }; + virtual void applyBackupFlags(VisualParams* ) { }; -} +}; +} // namespace sofa::simulation::graph diff --git a/Sofa/framework/Core/src/sofa/core/visual/VisualState.h b/Sofa/framework/Core/src/sofa/core/visual/VisualState.h index c1a4cd4c231..4790d948149 100644 --- a/Sofa/framework/Core/src/sofa/core/visual/VisualState.h +++ b/Sofa/framework/Core/src/sofa/core/visual/VisualState.h @@ -33,7 +33,7 @@ template< typename DataTypes > class VisualState : public core::State< DataTypes > { public: - SOFA_CLASS(VisualState, SOFA_TEMPLATE(core::State, defaulttype::Vec3Types)); + SOFA_CLASS(SOFA_TEMPLATE(VisualState, DataTypes), SOFA_TEMPLATE(core::State, DataTypes)); using VecCoord = typename DataTypes::VecCoord; using VecDeriv = typename DataTypes::VecCoord; diff --git a/Sofa/framework/Core/test/DataEngine_test.cpp b/Sofa/framework/Core/test/DataEngine_test.cpp index 55f80bad61d..47b68aa5378 100644 --- a/Sofa/framework/Core/test/DataEngine_test.cpp +++ b/Sofa/framework/Core/test/DataEngine_test.cpp @@ -81,7 +81,7 @@ struct DataEngine_test: public BaseTest { TestEngine engine; - void SetUp() override + void doSetUp() override { engine.init(); } diff --git a/Sofa/framework/Core/test/Engine_test.cpp b/Sofa/framework/Core/test/Engine_test.cpp index 938a70aa950..0f872d3e7f1 100644 --- a/Sofa/framework/Core/test/Engine_test.cpp +++ b/Sofa/framework/Core/test/Engine_test.cpp @@ -47,7 +47,7 @@ struct Engine_test : public BaseTest TestEngine::SPtr engine3; /// Create the engines - void SetUp() override + void doSetUp() override { // Engine 1 engine1 = sofa::core::objectmodel::New(); diff --git a/Sofa/framework/Core/test/IntrusiveObject_test.cpp b/Sofa/framework/Core/test/IntrusiveObject_test.cpp new file mode 100644 index 00000000000..e1b38345c39 --- /dev/null +++ b/Sofa/framework/Core/test/IntrusiveObject_test.cpp @@ -0,0 +1,73 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include + + +class DummyIntrusiveObject : public sofa::core::IntrusiveObject +{ +public: + DummyIntrusiveObject() = default; + explicit DummyIntrusiveObject(const std::function& _destructorCallback) + : destructorCallback(_destructorCallback) {} + + ~DummyIntrusiveObject() override + { + destructorCallback(); + } + +private: + std::function destructorCallback; +}; + + + +TEST(IntrusiveObject, IsDestructorCalled) +{ + std::size_t nbTimesDestructorCalled = 0; + { + sofa::core::sptr dummy(new DummyIntrusiveObject([&nbTimesDestructorCalled]() + { + nbTimesDestructorCalled++; + })); + } + EXPECT_EQ(1, nbTimesDestructorCalled); +} + + +TEST(IntrusiveObject, Copy) +{ + std::size_t nbTimesDestructorCalled = 0; + { + sofa::core::sptr dummy0; + { + sofa::core::sptr dummy(new DummyIntrusiveObject([&nbTimesDestructorCalled]() + { + nbTimesDestructorCalled++; + })); + + dummy0 = dummy; + } + } + EXPECT_EQ(1, nbTimesDestructorCalled); +} diff --git a/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp b/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp index 1306c64b794..ce051811eb5 100644 --- a/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp +++ b/Sofa/framework/Core/test/ObjectFactoryJson_test.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace sofa @@ -70,7 +71,7 @@ TEST(ObjectFactoryJson, oneTemplatedObject) TEST(ObjectFactoryJson, mainInstance) { - EXPECT_TRUE(sofa::simpleapi::importPlugin("Sofa.Component")); + EXPECT_TRUE(sofa::simpleapi::importPlugin(Sofa.Component)); const auto dump = core::ObjectFactoryJson::dump(core::ObjectFactory::getInstance()); EXPECT_NE(dump.find("MechanicalObject"), std::string::npos); } diff --git a/Sofa/framework/Core/test/TrackedData_test.cpp b/Sofa/framework/Core/test/TrackedData_test.cpp index 39780a56921..91ecdca13e8 100644 --- a/Sofa/framework/Core/test/TrackedData_test.cpp +++ b/Sofa/framework/Core/test/TrackedData_test.cpp @@ -215,7 +215,7 @@ struct DataTrackerEngine_test: public BaseTest static unsigned updateCounter; core::DataTrackerCallback dataTracker; - void SetUp() override + void doSetUp() override { updateCounter = 0; } diff --git a/Sofa/framework/Core/test/VecId_test.cpp b/Sofa/framework/Core/test/VecId_test.cpp index 00833a8a72f..ed15bbb961f 100644 --- a/Sofa/framework/Core/test/VecId_test.cpp +++ b/Sofa/framework/Core/test/VecId_test.cpp @@ -21,6 +21,7 @@ ******************************************************************************/ #include #include +#include class DerivedBaseVecId : public sofa::core::BaseVecId { @@ -98,4 +99,7 @@ TEST(VecId, name) EXPECT_EQ(sofa::core::vec_id::read_access::dforce.getName(), "dforce(V_DERIV)"); EXPECT_EQ(sofa::core::vec_id::write_access::dforce.getName(), "dforce(V_DERIV)"); + const std::string s = Sofa.Component.Collision; + EXPECT_EQ(s, std::string("Sofa.Component.Collision")); + } diff --git a/Sofa/framework/Core/test/objectmodel/BaseObjectDescription_test.cpp b/Sofa/framework/Core/test/objectmodel/BaseObjectDescription_test.cpp index 702eb1f077a..ba7c858d238 100644 --- a/Sofa/framework/Core/test/objectmodel/BaseObjectDescription_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/BaseObjectDescription_test.cpp @@ -29,11 +29,11 @@ using sofa::testing::BaseTest ; struct BaseObjectDescription_test: public BaseTest { - void SetUp() override + void doSetUp() override { } - void TearDown() override + void doTearDown() override { } diff --git a/Sofa/framework/Core/test/objectmodel/DataFileName_test.cpp b/Sofa/framework/Core/test/objectmodel/DataFileName_test.cpp index 29d14e833c3..f37aa678b24 100644 --- a/Sofa/framework/Core/test/objectmodel/DataFileName_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/DataFileName_test.cpp @@ -43,7 +43,7 @@ class DataFileName_test: public BaseTest { DataFileName d_filename; public: - void SetUp() override + void doSetUp() override { DataRepository.addFirstPath( SOFA_TESTING_RESOURCES_DIR ); } diff --git a/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp b/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp index 34cd074c650..f6b020030bf 100644 --- a/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp @@ -40,7 +40,7 @@ struct DataLink_test: public BaseTest Data dataVec3f; Data dataVec3d; - void SetUp() override + void doSetUp() override { /// Setup the data and create a link between the two data data1.setName("data1"); @@ -50,7 +50,7 @@ struct DataLink_test: public BaseTest data2.setName("dataVec3d"); } - void TearDown() override + void doTearDown() override { data1.unset(); data2.unset(); diff --git a/Sofa/framework/Core/test/objectmodel/RemovedData_test.cpp b/Sofa/framework/Core/test/objectmodel/RemovedData_test.cpp index e06de833344..9ee53e0530b 100644 --- a/Sofa/framework/Core/test/objectmodel/RemovedData_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/RemovedData_test.cpp @@ -25,7 +25,7 @@ using sofa::core::objectmodel::BaseObject ; #include using sofa::testing::BaseTest; -#include +#include using sofa::core::objectmodel::lifecycle::DeprecatedData; using sofa::core::objectmodel::lifecycle::RemovedData; diff --git a/Sofa/framework/Core/test/objectmodel/SingleLink_test.cpp b/Sofa/framework/Core/test/objectmodel/SingleLink_test.cpp index 1e741f7b646..7ad36dabcd0 100644 --- a/Sofa/framework/Core/test/objectmodel/SingleLink_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/SingleLink_test.cpp @@ -47,7 +47,7 @@ class SingleLink_test: public BaseTest BaseObject::SPtr m_src ; /// Create a link to an object. - void SetUp() override + void doSetUp() override { m_dst = sofa::core::objectmodel::New() ; m_src = sofa::core::objectmodel::New() ; diff --git a/Sofa/framework/DefaultType/src/sofa/defaulttype/RigidTypes.h b/Sofa/framework/DefaultType/src/sofa/defaulttype/RigidTypes.h index e14165269ef..164249bab08 100644 --- a/Sofa/framework/DefaultType/src/sofa/defaulttype/RigidTypes.h +++ b/Sofa/framework/DefaultType/src/sofa/defaulttype/RigidTypes.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace sofa::defaulttype @@ -251,6 +252,9 @@ template<> constexpr const char* Rigid3fTypes::Name() { return "Rigid3f"; } typedef StdRigidTypes<3,SReal> Rigid3Types; ///< un-defined precision type typedef StdRigidTypes<3,SReal> RigidTypes; ///< alias (beurk) +static_assert(type::isRigidType); +static_assert(type::isRigidType); + //============================================================================= // 2D Rigids //============================================================================= @@ -413,6 +417,9 @@ class StdRigidTypes<2, real> template<> constexpr const char* Rigid2dTypes::Name() { return "Rigid2d"; } template<> constexpr const char* Rigid2fTypes::Name() { return "Rigid2f"; } +static_assert(type::isRigidType); +static_assert(type::isRigidType); + /// \endcond diff --git a/Sofa/framework/DefaultType/src/sofa/defaulttype/VecTypes.h b/Sofa/framework/DefaultType/src/sofa/defaulttype/VecTypes.h index 7fbb70e7c44..789ab1ca252 100644 --- a/Sofa/framework/DefaultType/src/sofa/defaulttype/VecTypes.h +++ b/Sofa/framework/DefaultType/src/sofa/defaulttype/VecTypes.h @@ -30,6 +30,8 @@ #include #include #include +#include + namespace sofa:: defaulttype { @@ -236,4 +238,15 @@ typedef StdVectorTypes Vec2Types typedef StdVectorTypes Vec1Types; +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); + +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); +static_assert(!type::isRigidType); + + } // namespace sofa:: defaulttype diff --git a/Sofa/framework/DefaultType/src/sofa/defaulttype/fwd.h b/Sofa/framework/DefaultType/src/sofa/defaulttype/fwd.h index 715d3c4a01f..fa22f6cc457 100644 --- a/Sofa/framework/DefaultType/src/sofa/defaulttype/fwd.h +++ b/Sofa/framework/DefaultType/src/sofa/defaulttype/fwd.h @@ -57,15 +57,6 @@ typedef RigidMass<3,float> Rigid3fMass; typedef StdRigidTypes<3,SReal> Rigid3Types; ///< un-defined precision type typedef RigidMass<3,SReal> Rigid3Mass; ///< un-defined precision type -typedef StdRigidTypes<2,double> Rigid2dTypes; -typedef RigidMass<2,double> Rigid2dMass; - -typedef StdRigidTypes<2,float> Rigid2fTypes; -typedef RigidMass<2,float> Rigid2fMass; - -typedef StdRigidTypes<2,SReal> Rigid2Types; -typedef RigidMass<2,SReal> Rigid2Mass; - template class StdVectorTypes; diff --git a/Sofa/framework/Helper/CMakeLists.txt b/Sofa/framework/Helper/CMakeLists.txt index 0fc3c9d2650..b1e84de9954 100644 --- a/Sofa/framework/Helper/CMakeLists.txt +++ b/Sofa/framework/Helper/CMakeLists.txt @@ -216,11 +216,6 @@ add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) if((CMAKE_SYSTEM_NAME STREQUAL Windows) AND SOFA_USE_DEPENDENCY_PACK) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC "$") endif() -# The default binary suffix for libraries/plugins is "_d" when using a debug build. -# since this is configuration specific it is a bit more convenient to put it as a debug compile definition for -# PluginManager.cpp, at the expense of being much less visible compare to having it in the generated -# SofaFramework/config.h -set_property(SOURCE ${SRC_ROOT}/system/PluginManager.cpp APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG "SOFA_LIBSUFFIX=_d" ) # DEPENDENCY LINKS AND INCLUDE DIRS target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Config ) @@ -263,6 +258,23 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC "$") +set(is_release "$") +set(is_debug "$") +set(is_relwithdebinfo "$") +set(is_minsizerel "$") +# set the type of build as preprocessor value +target_compile_definitions(${PROJECT_NAME} PRIVATE "$<${is_release}:SOFA_BUILD_CONFIGURATION=Release>") +target_compile_definitions(${PROJECT_NAME} PRIVATE "$<${is_debug}:SOFA_BUILD_CONFIGURATION=Debug>") +target_compile_definitions(${PROJECT_NAME} PRIVATE "$<${is_relwithdebinfo}:SOFA_BUILD_CONFIGURATION=RelWithDebInfo>") +target_compile_definitions(${PROJECT_NAME} PRIVATE "$<${is_minsizerel}:SOFA_BUILD_CONFIGURATION=MinSizeRel>") +## if the type of build is something else (not supported), then SOFA_BUILD_CONFIGURATION wont be defined +# it could be also useful to know if we are using a multi-config generator +if(CMAKE_CONFIGURATION_TYPES) + target_compile_definitions(${PROJECT_NAME} PRIVATE "SOFA_BUILD_MULTI_CONFIGURATION=1") +else() + target_compile_definitions(${PROJECT_NAME} PRIVATE "SOFA_BUILD_MULTI_CONFIGURATION=0") +endif() + set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Sofa.Framework) # IDE folder sofa_create_package_with_targets( diff --git a/Sofa/framework/Helper/simutest/AdvancedTimer_test.cpp b/Sofa/framework/Helper/simutest/AdvancedTimer_test.cpp index a92b7440451..a7dc021fb53 100644 --- a/Sofa/framework/Helper/simutest/AdvancedTimer_test.cpp +++ b/Sofa/framework/Helper/simutest/AdvancedTimer_test.cpp @@ -40,7 +40,7 @@ namespace sofa { struct AdvancedTimerTest: public BaseSimulationTest { protected: - void onSetUp() override + void doSetUp() override { using namespace sofa::helper; diff --git a/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp b/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp index fa6c8375885..29d9abf57d8 100644 --- a/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp @@ -20,7 +20,7 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #include - +#include namespace sofa::helper::lifecycle { @@ -78,551 +78,553 @@ const std::map > movedComponents = { { "GlobalSystemMatrixExporter", Moved("v22.06", "SofaBaseLinearSolver", "SofaMatrix") }, // SofaMiscSolver was deprecated in #2571 - { "DampVelocitySolver", Moved("v22.06", "SofaMiscSolver", "Sofa.Component.ODESolver.Forward") }, - { "NewmarkImplicitSolver", Moved("v22.06", "SofaMiscSolver", "Sofa.Component.ODESolver.Backward") }, + { "DampVelocitySolver", Moved("v22.06", "SofaMiscSolver", Sofa.Component.ODESolver.Forward) }, + { "NewmarkImplicitSolver", Moved("v22.06", "SofaMiscSolver", Sofa.Component.ODESolver.Backward) }, // SofaExplicitOdeSolver was deprecated in #2571 - { "EulerExplicitSolver", Moved("v22.06", "SofaExplicitOdeSolver", "Sofa.Component.ODESolver.Forward") }, + { "EulerExplicitSolver", Moved("v22.06", "SofaExplicitOdeSolver", Sofa.Component.ODESolver.Forward) }, // SofaImplicitOdeSolver was deprecated in #2571 - { "EulerImplicitSolver", Moved("v22.06", "SofaImplicitOdeSolver", "Sofa.Component.ODESolver.Backward") }, - { "StaticSolver", Moved("v22.06", "SofaImplicitOdeSolver", "Sofa.Component.ODESolver.Backward") }, + { "EulerImplicitSolver", Moved("v22.06", "SofaImplicitOdeSolver", Sofa.Component.ODESolver.Backward) }, + { "StaticSolver", Moved("v22.06", "SofaImplicitOdeSolver", Sofa.Component.ODESolver.Backward) }, // SofaGeneralExplicitOdeSolver was deprecated in #2571 - { "CentralDifferenceSolver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", "Sofa.Component.ODESolver.Forward") }, - { "RungeKutta2Solver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", "Sofa.Component.ODESolver.Forward") }, - { "RungeKutta4Solver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", "Sofa.Component.ODESolver.Forward") }, + { "CentralDifferenceSolver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", Sofa.Component.ODESolver.Forward) }, + { "RungeKutta2Solver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", Sofa.Component.ODESolver.Forward) }, + { "RungeKutta4Solver", Moved("v22.06", "SofaGeneralExplicitOdeSolver", Sofa.Component.ODESolver.Forward) }, // SofaGeneralImplicitOdeSolver was deprecated in #2571 - { "VariationalSymplecticSolver", Moved("v22.06", "SofaGeneralImplicitOdeSolver", "Sofa.Component.ODESolver.Backward") }, + { "VariationalSymplecticSolver", Moved("v22.06", "SofaGeneralImplicitOdeSolver", Sofa.Component.ODESolver.Backward) }, // SofaLoader was deprecated in #2582 - { "MeshOBJLoader", Moved("v22.06", "SofaLoader", "Sofa.Component.IO.Mesh") }, - { "MeshVTKLoader", Moved("v22.06", "SofaLoader", "Sofa.Component.IO.Mesh") }, + { "MeshOBJLoader", Moved("v22.06", "SofaLoader", Sofa.Component.IO.Mesh) }, + { "MeshVTKLoader", Moved("v22.06", "SofaLoader", Sofa.Component.IO.Mesh) }, // SofaGeneralLoader was deprecated in #2582 - { "MeshGmshLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "GIDMeshLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "GridMeshCreator", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "MeshOffLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "MeshSTLLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "MeshTrianLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "MeshXspLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "OffSequenceLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "SphereLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "StringMeshCreator", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "VoxelGridLoader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.IO.Mesh") }, - { "ReadState", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.Playback") }, - { "ReadTopology", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.Playback") }, - { "InputEventReader", Moved("v22.06", "SofaGeneralLoader", "Sofa.Component.Playback") }, + { "MeshGmshLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "GIDMeshLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "GridMeshCreator", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "MeshOffLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "MeshSTLLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "MeshTrianLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "MeshXspLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "OffSequenceLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "SphereLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "StringMeshCreator", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "VoxelGridLoader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.IO.Mesh) }, + { "ReadState", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.Playback) }, + { "ReadTopology", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.Playback) }, + { "InputEventReader", Moved("v22.06", "SofaGeneralLoader", Sofa.Component.Playback) }, // SofaExporter was deprecated in #2582 - { "BlenderExporter", Moved("v22.06", "SofaExporter", "Sofa.Component.IO.Mesh") }, - { "MeshExporter", Moved("v22.06", "SofaExporter", "Sofa.Component.IO.Mesh") }, - { "STLExporter", Moved("v22.06", "SofaExporter", "Sofa.Component.IO.Mesh") }, - { "VisualModelOBJExporter", Moved("v22.06", "SofaExporter", "Sofa.Component.IO.Mesh") }, - { "VTKExporter", Moved("v22.06", "SofaExporter", "Sofa.Component.IO.Mesh") }, - { "WriteState", Moved("v22.06", "SofaExporter", "Sofa.Component.Playback") }, - { "WriteTopology", Moved("v22.06", "SofaExporter", "Sofa.Component.Playback") }, + { "BlenderExporter", Moved("v22.06", "SofaExporter", Sofa.Component.IO.Mesh) }, + { "MeshExporter", Moved("v22.06", "SofaExporter", Sofa.Component.IO.Mesh) }, + { "STLExporter", Moved("v22.06", "SofaExporter", Sofa.Component.IO.Mesh) }, + { "VisualModelOBJExporter", Moved("v22.06", "SofaExporter", Sofa.Component.IO.Mesh) }, + { "VTKExporter", Moved("v22.06", "SofaExporter", Sofa.Component.IO.Mesh) }, + { "WriteState", Moved("v22.06", "SofaExporter", Sofa.Component.Playback) }, + { "WriteTopology", Moved("v22.06", "SofaExporter", Sofa.Component.Playback) }, // SofaBaseUtils was deprecated in #2605 - { "AddResourceRepository", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, - { "MakeAliasComponent", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, - { "MakeDataAliasComponent", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, - { "MessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, - { "FileMessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, - { "InfoComponent", Moved("v22.06", "SofaBaseUtils", "Sofa.Component.SceneUtility") }, + { "AddResourceRepository", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, + { "MakeAliasComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, + { "MakeDataAliasComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, + { "MessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, + { "FileMessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, + { "InfoComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, { "RequiredPlugin", Moved("v22.06", "SofaBaseUtils", "Sofa.Core") }, // SofaGraphComponent was deprecated in #2605, #2843 and #2895 - { "AddFrameButtonSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.GUI.Component") }, - { "AddRecordedCameraButtonSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.GUI.Component") }, - { "StartNavigationButtonSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.Component.Setting") }, - { "AttachBodyButtonSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.GUI.Component") }, - { "FixPickedParticleButtonSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.GUI.Component") }, - { "SofaDefaultPathSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.Component.Setting") }, - { "StatsSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.Component.Setting") }, - { "ViewerSetting", Moved("v22.06", "SofaGraphComponent", "Sofa.Component.Setting") }, - { "APIVersion", Moved("v22.06", "SofaGraphComponent", "Sofa.Component.Setting") }, + { "AddFrameButtonSetting", Moved("v22.06", "SofaGraphComponent", Sofa.GUI.Component) }, + { "AddRecordedCameraButtonSetting", Moved("v22.06", "SofaGraphComponent", Sofa.GUI.Component) }, + { "StartNavigationButtonSetting", Moved("v22.06", "SofaGraphComponent", Sofa.Component.Setting) }, + { "AttachBodyButtonSetting", Moved("v22.06", "SofaGraphComponent", Sofa.GUI.Component) }, + { "FixPickedParticleButtonSetting", Moved("v22.06", "SofaGraphComponent", Sofa.GUI.Component) }, + { "SofaDefaultPathSetting", Moved("v22.06", "SofaGraphComponent", Sofa.Component.Setting) }, + { "StatsSetting", Moved("v22.06", "SofaGraphComponent", Sofa.Component.Setting) }, + { "ViewerSetting", Moved("v22.06", "SofaGraphComponent", Sofa.Component.Setting) }, + { "APIVersion", Moved("v22.06", "SofaGraphComponent", Sofa.Component.Setting) }, // SofaBaseTopology was deprecated in #2612 - { "EdgeSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "EdgeSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "EdgeSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "EdgeSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "HexahedronSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "HexahedronSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "HexahedronSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "HexahedronSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "PointSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "PointSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "PointSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "PointSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "QuadSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "QuadSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "QuadSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "QuadSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TetrahedronSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TetrahedronSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TetrahedronSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TetrahedronSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TriangleSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TriangleSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TriangleSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "TriangleSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Dynamic") }, - { "MeshTopology", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Constant") }, - { "GridTopology", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Grid") }, - { "RegularGridTopology", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Grid") }, - { "SparseGridTopology", Moved("v22.06", "SofaBaseTopology", "Sofa.Component.Topology.Container.Grid") }, + { "EdgeSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "EdgeSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "EdgeSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "EdgeSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "HexahedronSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "HexahedronSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "HexahedronSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "HexahedronSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "PointSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "PointSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "PointSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "PointSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "QuadSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "QuadSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "QuadSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "QuadSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TetrahedronSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TetrahedronSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TetrahedronSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TetrahedronSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TriangleSetGeometryAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TriangleSetTopologyAlgorithms", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TriangleSetTopologyContainer", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "TriangleSetTopologyModifier", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Dynamic) }, + { "MeshTopology", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Constant) }, + { "GridTopology", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Grid) }, + { "RegularGridTopology", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Grid) }, + { "SparseGridTopology", Moved("v22.06", "SofaBaseTopology", Sofa.Component.Topology.Container.Grid) }, // SofaGeneralTopology was deprecated in #2612 - { "CubeTopology", Moved("v22.06", "SofaGeneralTopology", "Sofa.Component.Topology.Container.Constant") }, - { "SphereQuadTopology", Moved("v22.06", "SofaGeneralTopology", "Sofa.Component.Topology.Container.Constant") }, - { "CylinderGridTopology", Moved("v22.06", "SofaGeneralTopology", "Sofa.Component.Topology.Container.Grid") }, - { "SphereGridTopology", Moved("v22.06", "SofaGeneralTopology", "Sofa.Component.Topology.Container.Grid") }, + { "CubeTopology", Moved("v22.06", "SofaGeneralTopology", Sofa.Component.Topology.Container.Constant) }, + { "SphereQuadTopology", Moved("v22.06", "SofaGeneralTopology", Sofa.Component.Topology.Container.Constant) }, + { "CylinderGridTopology", Moved("v22.06", "SofaGeneralTopology", Sofa.Component.Topology.Container.Grid) }, + { "SphereGridTopology", Moved("v22.06", "SofaGeneralTopology", Sofa.Component.Topology.Container.Grid) }, // SofaNonUniformFem was deprecated in #2612 and #2759 - { "DynamicSparseGridGeometryAlgorithms", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Dynamic") }, - { "DynamicSparseGridTopologyAlgorithms", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Dynamic") }, - { "DynamicSparseGridTopologyContainer", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Dynamic") }, - { "DynamicSparseGridTopologyModifier", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Dynamic") }, - { "MultilevelHexahedronSetTopologyContainer", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Dynamic") }, - { "SparseGridMultipleTopology", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Grid") }, - { "SparseGridRamificationTopology", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.Topology.Container.Grid") }, - { "NonUniformHexahedralFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.SolidMechanics.FEM.NonUniform") }, - { "NonUniformHexahedronFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.SolidMechanics.FEM.NonUniform") }, - { "HexahedronCompositeFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.SolidMechanics.FEM.NonUniform") }, - { "HexahedronCompositeFEMMapping", Moved("v22.06", "SofaNonUniformFem", "Sofa.Component.SolidMechanics.FEM.NonUniform") }, + { "DynamicSparseGridGeometryAlgorithms", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Dynamic) }, + { "DynamicSparseGridTopologyAlgorithms", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Dynamic) }, + { "DynamicSparseGridTopologyContainer", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Dynamic) }, + { "DynamicSparseGridTopologyModifier", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Dynamic) }, + { "MultilevelHexahedronSetTopologyContainer", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Dynamic) }, + { "SparseGridMultipleTopology", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Grid) }, + { "SparseGridRamificationTopology", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.Topology.Container.Grid) }, + { "NonUniformHexahedralFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.SolidMechanics.FEM.NonUniform) }, + { "NonUniformHexahedronFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.SolidMechanics.FEM.NonUniform) }, + { "HexahedronCompositeFEMForceFieldAndMass", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.SolidMechanics.FEM.NonUniform) }, + { "HexahedronCompositeFEMMapping", Moved("v22.06", "SofaNonUniformFem", Sofa.Component.SolidMechanics.FEM.NonUniform) }, // SofaTopologicalMapping was deprecated in #2612 and #XXXX - { "CenterPointTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Edge2QuadTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Hexa2QuadTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Hexa2TetraTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "IdentityTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Mesh2PointTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Quad2TriangleTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "SimpleTesselatedHexaTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "SimpleTesselatedTetraTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "SubsetTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Tetra2TriangleTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Triangle2EdgeTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Topology.Mapping") }, - { "Mesh2PointMechanicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Mapping.Linear") }, - { "SimpleTesselatedTetraMechanicalMapping", Moved("v22.06", "SofaTopologicalMapping", "Sofa.Component.Mapping.Linear") }, + { "CenterPointTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Edge2QuadTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Hexa2QuadTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Hexa2TetraTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "IdentityTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Mesh2PointTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Quad2TriangleTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "SimpleTesselatedHexaTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "SimpleTesselatedTetraTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "SubsetTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Tetra2TriangleTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Triangle2EdgeTopologicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Topology.Mapping) }, + { "Mesh2PointMechanicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Mapping.Linear) }, + { "SimpleTesselatedTetraMechanicalMapping", Moved("v22.06", "SofaTopologicalMapping", Sofa.Component.Mapping.Linear) }, // SofaMiscTopology was deprecated in #2612 - { "TopologicalChangeProcessor", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Topology.Utility") }, - { "TopologyBoundingTrasher", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Topology.Utility") }, - { "TopologyChecker", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Topology.Utility") }, + { "TopologicalChangeProcessor", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Topology.Utility) }, + { "TopologyBoundingTrasher", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Topology.Utility) }, + { "TopologyChecker", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Topology.Utility) }, // SofaBaseVisual was deprecated in #2679 and #XXXX - { "Camera", Moved("v22.06", "SofaBaseVisual", "Sofa.Component.Visual") }, - { "InteractiveCamera", Moved("v22.06", "SofaBaseVisual", "Sofa.Component.Visual") }, - { "VisualModelImpl", Moved("v22.06", "SofaBaseVisual", "Sofa.Component.Visual") }, - { "VisualStyle", Moved("v22.06", "SofaBaseVisual", "Sofa.Component.Visual") }, - { "BackgroundSetting", Moved("v22.06", "SofaBaseVisual", "Sofa.Component.Setting") }, + { "Camera", Moved("v22.06", "SofaBaseVisual", Sofa.Component.Visual) }, + { "InteractiveCamera", Moved("v22.06", "SofaBaseVisual", Sofa.Component.Visual) }, + { "VisualModelImpl", Moved("v22.06", "SofaBaseVisual", Sofa.Component.Visual) }, + { "VisualStyle", Moved("v22.06", "SofaBaseVisual", Sofa.Component.Visual) }, + { "BackgroundSetting", Moved("v22.06", "SofaBaseVisual", Sofa.Component.Setting) }, // SofaGeneralVisual was deprecated in #2679 - { "RecordedCamera", Moved("v22.06", "SofaGeneralVisual", "Sofa.Component.Visual") }, - { "Visual3DText", Moved("v22.06", "SofaGeneralVisual", "Sofa.Component.Visual") }, - { "VisualTransform", Moved("v22.06", "SofaGeneralVisual", "Sofa.Component.Visual") }, + { "RecordedCamera", Moved("v22.06", "SofaGeneralVisual", Sofa.Component.Visual) }, + { "Visual3DText", Moved("v22.06", "SofaGeneralVisual", Sofa.Component.Visual) }, + { "VisualTransform", Moved("v22.06", "SofaGeneralVisual", Sofa.Component.Visual) }, // SofaSimpleFem was deprecated in #2753 and .... - { "TetrahedronDiffusionFEMForceField", Moved("v22.06", "SofaSimpleFem", "Sofa.Component.Diffusion") }, + { "TetrahedronDiffusionFEMForceField", Moved("v22.06", "SofaSimpleFem", Sofa.Component.Diffusion) }, // SofaOpenglVisual was deprecated in #2709 - { "OglSceneFrame", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "DataDisplay", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "MergeVisualModels", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "OglCylinderModel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "OglModel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "PointSplatModel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "SlicedVolumetricModel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering3D") }, - { "OglColorMap", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering2D") }, - { "OglLabel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering2D") }, - { "OglViewport", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Rendering2D") }, - { "ClipPlane", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "CompositingVisualLoop", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "DirectionalLight", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "PositionalLight", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "SpotLight", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "LightManager", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloatAttribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat2Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat3Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat4Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglIntAttribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt2Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt3Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt4Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglUIntAttribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglUInt2Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglUInt3Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglUInt4Attribute", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglOITShader", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglRenderingSRGB", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglShader", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglShaderMacro", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglShaderVisualModel", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglShadowShader", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglTexture", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglTexture2D", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglIntVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt2Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt3Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt4Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloatVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat2Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat3Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat4Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglIntVectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt2VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt3VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglInt4VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloatVectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat2VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat3VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglFloat4VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix2Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix3Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix4Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix2x3Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix3x2Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix2x4Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix4x2Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix3x4Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix4x3Variable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OglMatrix4VectorVariable", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "OrderIndependentTransparencyManager", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "PostProcessManager", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "VisualManagerPass", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "VisualManagerSecondaryPass", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Shader") }, - { "TextureInterpolation", Moved("v22.06", "SofaOpenglVisual", "Sofa.GL.Component.Engine") }, + { "OglSceneFrame", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "DataDisplay", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "MergeVisualModels", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "OglCylinderModel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "OglModel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "PointSplatModel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "SlicedVolumetricModel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering3D) }, + { "OglColorMap", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering2D) }, + { "OglLabel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering2D) }, + { "OglViewport", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Rendering2D) }, + { "ClipPlane", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "CompositingVisualLoop", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "DirectionalLight", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "PositionalLight", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "SpotLight", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "LightManager", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloatAttribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat2Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat3Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat4Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglIntAttribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt2Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt3Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt4Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglUIntAttribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglUInt2Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglUInt3Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglUInt4Attribute", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglOITShader", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglRenderingSRGB", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglShader", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglShaderMacro", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglShaderVisualModel", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglShadowShader", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglTexture", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglTexture2D", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglIntVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt2Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt3Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt4Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloatVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat2Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat3Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat4Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglIntVectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt2VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt3VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglInt4VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloatVectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat2VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat3VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglFloat4VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix2Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix3Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix4Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix2x3Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix3x2Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix2x4Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix4x2Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix3x4Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix4x3Variable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OglMatrix4VectorVariable", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "OrderIndependentTransparencyManager", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "PostProcessManager", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "VisualManagerPass", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "VisualManagerSecondaryPass", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Shader) }, + { "TextureInterpolation", Moved("v22.06", "SofaOpenglVisual", Sofa.GL.Component.Engine) }, // SofaBaseLinearSolver was deprecated in #2717 - { "CGLinearSolver", Moved("v22.06", "SofaBaseLinearSolver", "Sofa.Component.LinearSolver.Iterative") }, + { "CGLinearSolver", Moved("v22.06", "SofaBaseLinearSolver", Sofa.Component.LinearSolver.Iterative) }, // SofaGeneralLinearSolver was deprecated in #2717 - { "MinResLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", "Sofa.Component.LinearSolver.Iterative") }, - { "BTDLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", "Sofa.Component.LinearSolver.Direct") }, - { "CholeskySolver", Moved("v22.06", "SofaGeneralLinearSolver", "Sofa.Component.LinearSolver.Direct") }, + { "MinResLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", Sofa.Component.LinearSolver.Iterative) }, + { "BTDLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", Sofa.Component.LinearSolver.Direct) }, + { "CholeskySolver", Moved("v22.06", "SofaGeneralLinearSolver", Sofa.Component.LinearSolver.Direct) }, // SofaSparseSolver was deprecated in #2717 - { "FillReducingOrdering", Moved("v22.06", "SofaGeneralLinearSolver", "Sofa.Component.LinearSolver.Direct") }, - { "PrecomputedLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", "Sofa.Component.LinearSolver.Direct") }, - { "SparseLDLSolver", Moved("v22.06", "SofaSparseSolver", "Sofa.Component.LinearSolver.Direct") }, + { "FillReducingOrdering", Moved("v22.06", "SofaGeneralLinearSolver", Sofa.Component.LinearSolver.Direct) }, + { "PrecomputedLinearSolver", Moved("v22.06", "SofaGeneralLinearSolver", Sofa.Component.LinearSolver.Direct) }, + { "SparseLDLSolver", Moved("v22.06", "SofaSparseSolver", Sofa.Component.LinearSolver.Direct) }, // SofaDenseSolver was deprecated in #2717 - { "SVDLinearSolver", Moved("v22.06", "SofaDenseSolver", "Sofa.Component.LinearSolver.Direct") }, + { "SVDLinearSolver", Moved("v22.06", "SofaDenseSolver", Sofa.Component.LinearSolver.Direct) }, // SofaPreconditioner was deprecated in #2717 - { "ShewchukPCGLinearSolver", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Iterative") }, - { "JacobiPreconditioner", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Preconditioner") }, - { "BlockJacobiPreconditioner", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Preconditioner") }, - { "PrecomputedWarpPreconditioner", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Preconditioner") }, - { "SSORPreconditioner", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Preconditioner") }, - { "WarpPreconditioner", Moved("v22.06", "SofaPreconditioner", "Sofa.Component.LinearSolver.Preconditioner") }, + { "ShewchukPCGLinearSolver", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Iterative) }, + { "JacobiPreconditioner", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Preconditioner) }, + { "BlockJacobiPreconditioner", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Preconditioner) }, + { "PrecomputedWarpPreconditioner", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Preconditioner) }, + { "SSORPreconditioner", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Preconditioner) }, + { "WarpPreconditioner", Moved("v22.06", "SofaPreconditioner", Sofa.Component.LinearSolver.Preconditioner) }, // SofaBaseMechanics was deprecated in #2752, #2635 and #2766 - { "DiagonalMass", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.Mass") }, - { "UniformMass", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.Mass") }, - { "BarycentricMapping", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.Mapping.Linear") }, - { "IdentityMapping", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.Mapping.Linear") }, - { "SubsetMapping", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.Mapping.Linear") }, - { "MechanicalObject", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.StateContainer") }, - { "MappedObject", Moved("v22.06", "SofaBaseMechanics", "Sofa.Component.StateContainer") }, + { "DiagonalMass", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.Mass) }, + { "UniformMass", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.Mass) }, + { "BarycentricMapping", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.Mapping.Linear) }, + { "IdentityMapping", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.Mapping.Linear) }, + { "SubsetMapping", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.Mapping.Linear) }, + { "MechanicalObject", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.StateContainer) }, + { "MappedObject", Moved("v22.06", "SofaBaseMechanics", Sofa.Component.StateContainer) }, // SofaMiscForceField was deprecated in #2752 and ... - { "MeshMatrixMass", Moved("v22.06", "SofaMiscForceField", "Sofa.Component.Mass") }, - { "GearSpringForceField", Moved("v22.06", "SofaMiscForceField", "Sofa.Component.SolidMechanics.Spring") }, + { "MeshMatrixMass", Moved("v22.06", "SofaMiscForceField", Sofa.Component.Mass) }, + { "GearSpringForceField", Moved("v22.06", "SofaMiscForceField", Sofa.Component.SolidMechanics.Spring) }, // SofaRigid was deprecated in #2635 and #2759 - { "RigidMapping", Moved("v22.06", "SofaRigid", "Sofa.Component.Mapping.NonLinear") }, - { "RigidRigidMapping", Moved("v22.06", "SofaRigid", "Sofa.Component.Mapping.NonLinear") }, - { "JointSpringForceField", Moved("v22.06", "SofaRigid", "Sofa.Component.SolidMechanics.Spring") }, + { "RigidMapping", Moved("v22.06", "SofaRigid", Sofa.Component.Mapping.NonLinear) }, + { "RigidRigidMapping", Moved("v22.06", "SofaRigid", Sofa.Component.Mapping.NonLinear) }, + { "JointSpringForceField", Moved("v22.06", "SofaRigid", Sofa.Component.SolidMechanics.Spring) }, // Movedgid was deprecated in #2635 and ... - { "LineSetSkinningMapping", Moved("v22.06", "Movedgid", "Sofa.Component.Mapping.Linear") }, - { "SkinningMapping", Moved("v22.06", "Movedgid", "Sofa.Component.Mapping.Linear") }, + { "LineSetSkinningMapping", Moved("v22.06", "Movedgid", Sofa.Component.Mapping.Linear) }, + { "SkinningMapping", Moved("v22.06", "Movedgid", Sofa.Component.Mapping.Linear) }, { "ArticulatedHierarchyContainer", Moved("v22.06", "Movedgid", "ArticulatedSystemPlugin") }, { "ArticulationCenter", Moved("v22.06", "Movedgid", "ArticulatedSystemPlugin") }, { "Articulation", Moved("v22.06", "Movedgid", "ArticulatedSystemPlugin") }, { "ArticulatedSystemMapping", Moved("v22.06", "Movedgid", "ArticulatedSystemPlugin") }, // SofaMiscMapping was deprecated in #2635 - { "BeamLinearMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "CenterOfMassMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "CenterOfMassMulti2Mapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "CenterOfMassMultiMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "DeformableOnRigidFrameMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "DistanceFromTargetMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.NonLinear") }, - { "DistanceMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.NonLinear") }, - { "IdentityMultiMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "SquareMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.NonLinear") }, - { "SquareDistanceMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.NonLinear") }, - { "SubsetMultiMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "TubularMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, - { "VoidMapping", Moved("v22.06", "SofaMiscMapping", "Sofa.Component.Mapping.Linear") }, + { "BeamLinearMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "CenterOfMassMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "CenterOfMassMulti2Mapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "CenterOfMassMultiMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "DeformableOnRigidFrameMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "DistanceFromTargetMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.NonLinear) }, + { "DistanceMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.NonLinear) }, + { "IdentityMultiMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "SquareMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.NonLinear) }, + { "SquareDistanceMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.NonLinear) }, + { "SubsetMultiMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "TubularMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, + { "VoidMapping", Moved("v22.06", "SofaMiscMapping", Sofa.Component.Mapping.Linear) }, // SofaConstraint was deprecated in #2635, #2790, #2796, #2813 and ... - { "BilateralInteractionConstraint", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Model") }, - { "GenericConstraintCorrection", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Correction") }, - { "GenericConstraintSolver", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Solver") }, - { "LCPConstraintSolver", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Solver") }, - { "LinearSolverConstraintCorrection", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Correction") }, - { "PrecomputedConstraintCorrection", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Correction") }, - { "SlidingConstraint", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Model") }, - { "StopperConstraint", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Model") }, - { "UncoupledConstraintCorrection", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Correction") }, - { "UniformConstraint", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Model") }, - { "UnilateralInteractionConstraint", Moved("v22.06", "SofaConstraint", "Sofa.Component.Constraint.Lagrangian.Model") }, - { "ConstraintAnimationLoop", Moved("v22.06", "SofaConstraint", "Sofa.Component.AnimationLoop") }, - { "FreeMotionAnimationLoop", Moved("v22.06", "SofaConstraint", "Sofa.Component.AnimationLoop") }, - { "LocalMinDistance", Moved("v22.06", "SofaConstraint", "Sofa.Component.Collision.Detection.Intersection") }, + { "BilateralInteractionConstraint", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Model) }, + { "GenericConstraintCorrection", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Correction) }, + { "GenericConstraintSolver", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Solver) }, + { "LCPConstraintSolver", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Solver) }, + { "LinearSolverConstraintCorrection", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Correction) }, + { "PrecomputedConstraintCorrection", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Correction) }, + { "SlidingConstraint", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Model) }, + { "StopperConstraint", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Model) }, + { "UncoupledConstraintCorrection", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Correction) }, + { "UniformConstraint", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Model) }, + { "UnilateralInteractionConstraint", Moved("v22.06", "SofaConstraint", Sofa.Component.Constraint.Lagrangian.Model) }, + { "ConstraintAnimationLoop", Moved("v22.06", "SofaConstraint", Sofa.Component.AnimationLoop) }, + { "FreeMotionAnimationLoop", Moved("v22.06", "SofaConstraint", Sofa.Component.AnimationLoop) }, + { "LocalMinDistance", Moved("v22.06", "SofaConstraint", Sofa.Component.Collision.Detection.Intersection) }, // SofaGeneralAnimationLoop was deprecated in #2635 and #2796 - { "MultiStepAnimationLoop", Moved("v22.06", "SofaGeneralAnimationLoop", "Sofa.Component.AnimationLoop") }, - { "MultiTagAnimationLoop", Moved("v22.06", "SofaGeneralAnimationLoop", "Sofa.Component.AnimationLoop") }, + { "MultiStepAnimationLoop", Moved("v22.06", "SofaGeneralAnimationLoop", Sofa.Component.AnimationLoop) }, + { "MultiTagAnimationLoop", Moved("v22.06", "SofaGeneralAnimationLoop", Sofa.Component.AnimationLoop) }, // SofaSimpleFem was deprecated in #2759 - { "HexahedronFEMForceField", Moved("v22.06", "SofaSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TetrahedronFEMForceField", Moved("v22.06", "SofaSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, + { "HexahedronFEMForceField", Moved("v22.06", "SofaSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TetrahedronFEMForceField", Moved("v22.06", "SofaSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, // SofaGeneralSimpleFem was deprecated in #2759 - { "BeamFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "HexahedralFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "HexahedralFEMForceFieldAndMass", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "HexahedronFEMForceFieldAndMass", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TetrahedralCorotationalFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TriangularFEMForceFieldOptim", Moved("v22.06", "SofaGeneralSimpleFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, + { "BeamFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "HexahedralFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "HexahedralFEMForceFieldAndMass", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "HexahedronFEMForceFieldAndMass", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TetrahedralCorotationalFEMForceField", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TriangularFEMForceFieldOptim", Moved("v22.06", "SofaGeneralSimpleFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, // SofaMiscFem was deprecated in #2759 - { "FastTetrahedralCorotationalForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "StandardTetrahedralFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TriangleFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TriangularAnisotropicFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "TriangularFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "QuadBendingFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.Elastic") }, - { "BoyceAndArruda", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "Costa", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "HyperelasticMaterial", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "MooneyRivlin", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "NeoHookean", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "Ogden", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "PlasticMaterial", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "StandardTetrahedralFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "STVenantKirchhoff", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "TetrahedronHyperelasticityFEMForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "VerondaWestman", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.HyperElastic") }, - { "TetrahedralTensorMassForceField", Moved("v22.06", "SofaMiscFem", "Sofa.Component.SolidMechanics.FEM.TensorMass") }, + { "FastTetrahedralCorotationalForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "StandardTetrahedralFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TriangleFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TriangularAnisotropicFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "TriangularFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "QuadBendingFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.Elastic) }, + { "BoyceAndArruda", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "Costa", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "HyperelasticMaterial", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "MooneyRivlin", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "NeoHookean", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "Ogden", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "PlasticMaterial", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "StandardTetrahedralFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "STVenantKirchhoff", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "TetrahedronHyperelasticityFEMForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "VerondaWestman", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.FEM.HyperElastic) }, + { "TetrahedralTensorMassForceField", Moved("v22.06", "SofaMiscFem", Sofa.Component.SolidMechanics.TensorMass) }, // SofaDeformable was deprecated in #2759 - { "AngularSpringForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "MeshSpringForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "RestShapeSpringsForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "PolynomialRestShapeSpringsForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "SpringForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "StiffSpringForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "PolynomialSpringsForceField", Moved("v22.06", "SofaDeformable", "Sofa.Component.SolidMechanics.Spring") }, + { "AngularSpringForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "MeshSpringForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "RestShapeSpringsForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "PolynomialRestShapeSpringsForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "SpringForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "StiffSpringForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "PolynomialSpringsForceField", Moved("v22.06", "SofaDeformable", Sofa.Component.SolidMechanics.Spring) }, // SofaGeneralDeformable was deprecated in #2759 - { "FastTriangularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "FrameSpringForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "QuadBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "QuadularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "RegularGridSpringForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangleBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangleBendingSprings", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangularBiquadraticSpringsForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangularQuadraticSpringsForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "VectorSpringForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.Spring") }, - { "TriangularTensorMassForceField", Moved("v22.06", "SofaGeneralDeformable", "Sofa.Component.SolidMechanics.TensorMass") }, + { "FastTriangularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "FrameSpringForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "QuadBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "QuadularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "RegularGridSpringForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangleBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangularBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangleBendingSprings", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangularBiquadraticSpringsForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangularQuadraticSpringsForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "VectorSpringForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.Spring) }, + { "TriangularTensorMassForceField", Moved("v22.06", "SofaGeneralDeformable", Sofa.Component.SolidMechanics.TensorMass) }, // SofaGeneralObjectInteraction was deprecated in #2759 and #3039 - { "RepulsiveSpringForceField", Moved("v22.06", "SofaGeneralObjectInteraction", "Sofa.Component.SolidMechanics.Spring") }, - { "InteractionEllipsoidForceField", Moved("v22.06", "SofaGeneralObjectInteraction", "Sofa.Component.MechanicalLoad") }, + { "RepulsiveSpringForceField", Moved("v22.06", "SofaGeneralObjectInteraction", Sofa.Component.SolidMechanics.Spring) }, + { "InteractionEllipsoidForceField", Moved("v22.06", "SofaGeneralObjectInteraction", Sofa.Component.MechanicalLoad) }, // SofaGeneralObjectInteraction was deprecated in #2790 and ... - { "AttachConstraint", Moved("v22.06", "SofaGeneralObjectInteraction", "Sofa.Component.Constraint.Projective") }, + { "AttachConstraint", Moved("v22.06", "SofaGeneralObjectInteraction", Sofa.Component.Constraint.Projective) }, // SofaBoundaryCondition was deprecated in #2790 and #2759 - { "AffineMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "FixedConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "FixedPlaneConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "FixedRotationConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "FixedTranslationConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "HermiteSplineConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "LinearMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "LinearVelocityConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "OscillatorConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ParabolicConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "PartialFixedConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "PartialLinearMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "PatchTestMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "PointConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "PositionBasedDynamicsConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ProjectDirectionConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ProjectToLineConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ProjectToPlaneConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ProjectToPointConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "AttachConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "SkeletalMotionConstraint", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.Constraint.Projective") }, - { "ConicalForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "ConstantForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "DiagonalVelocityDampingForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "EdgePressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "EllipsoidForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "LinearForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "OscillatingTorsionPressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "PlaneForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "QuadPressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "SphereForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "SurfacePressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "TaitSurfacePressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "TorsionForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "TrianglePressureForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, - { "UniformVelocityDampingForceField", Moved("v22.06", "SofaBoundaryCondition", "Sofa.Component.MechanicalLoad") }, + { "AffineMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "FixedConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "FixedPlaneConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "FixedRotationConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "FixedTranslationConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "HermiteSplineConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "LinearMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "LinearVelocityConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "OscillatorConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ParabolicConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "PartialFixedConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "PartialLinearMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "PatchTestMovementConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "PointConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "PositionBasedDynamicsConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ProjectDirectionConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ProjectToLineConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ProjectToPlaneConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ProjectToPointConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "AttachConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "SkeletalMotionConstraint", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.Constraint.Projective) }, + { "ConicalForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "ConstantForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "DiagonalVelocityDampingForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "EdgePressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "EllipsoidForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "LinearForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "OscillatingTorsionPressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "PlaneForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "QuadPressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "SphereForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "SurfacePressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "TaitSurfacePressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "TorsionForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "TrianglePressureForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, + { "UniformVelocityDampingForceField", Moved("v22.06", "SofaBoundaryCondition", Sofa.Component.MechanicalLoad) }, // SofaBaseCollision was deprecated in #2813 - { "BruteForceBroadPhase", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "BruteForceDetection", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "BVHNarrowPhase", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "DefaultPipeline", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "DiscreteIntersection", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Intersection") }, - { "MinProximityIntersection", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Intersection") }, - { "NewProximityIntersection", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Detection.Intersection") }, - { "CubeCollisionModel", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Geometry") }, - { "SphereCollisionModel", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Geometry") }, - { "CylinderCollisionModel", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Geometry") }, - { "DefaultContactManager", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Response.Contact") }, - { "ContactListener", Moved("v22.06", "SofaBaseCollision", "Sofa.Component.Collision.Response.Contact") }, + { "BruteForceBroadPhase", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "BruteForceDetection", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "BVHNarrowPhase", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "DefaultPipeline", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "DiscreteIntersection", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Intersection) }, + { "MinProximityIntersection", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Intersection) }, + { "NewProximityIntersection", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Detection.Intersection) }, + { "CubeCollisionModel", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Geometry) }, + { "SphereCollisionModel", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Geometry) }, + { "CylinderCollisionModel", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Geometry) }, + { "DefaultContactManager", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Response.Contact) }, + { "ContactListener", Moved("v22.06", "SofaBaseCollision", Sofa.Component.Collision.Response.Contact) }, // SofaMeshCollision was deprecated in #2813 - { "PointCollisionModel", Moved("v22.06", "SofaMeshCollision", "Sofa.Component.Collision.Geometry") }, - { "LineCollisionModel", Moved("v22.06", "SofaMeshCollision", "Sofa.Component.Collision.Geometry") }, - { "TriangleCollisionModel", Moved("v22.06", "SofaMeshCollision", "Sofa.Component.Collision.Geometry") }, + { "PointCollisionModel", Moved("v22.06", "SofaMeshCollision", Sofa.Component.Collision.Geometry) }, + { "LineCollisionModel", Moved("v22.06", "SofaMeshCollision", Sofa.Component.Collision.Geometry) }, + { "TriangleCollisionModel", Moved("v22.06", "SofaMeshCollision", Sofa.Component.Collision.Geometry) }, // SofaGeneralMeshCollision was deprecated in #2813 - { "DirectSAP", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "DirectSAPNarrowPhase", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "IncrSAPClassSofaVector", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "RayTraceNarrowPhase", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "RayTraceDetection", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Detection.Algorithm") }, - { "TriangleOctreeModel", Moved("v22.06", "SofaGeneralMeshCollision", "Sofa.Component.Collision.Geometry") }, + { "DirectSAP", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "DirectSAPNarrowPhase", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "IncrSAPClassSofaVector", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "RayTraceNarrowPhase", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "RayTraceDetection", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Detection.Algorithm) }, + { "TriangleOctreeModel", Moved("v22.06", "SofaGeneralMeshCollision", Sofa.Component.Collision.Geometry) }, // SofaUserInteraction was deprecated in #2813 - { "RayCollisionModel", Moved("v22.06", "SofaUserInteraction", "Sofa.Component.Collision.Geometry") }, - { "Controller", Moved("v22.06", "SofaUserInteraction", "Sofa.Component.Controller") }, - { "MechanicalStateController", Moved("v22.06", "SofaUserInteraction", "Sofa.Component.Controller") }, + { "RayCollisionModel", Moved("v22.06", "SofaUserInteraction", Sofa.Component.Collision.Geometry) }, + { "Controller", Moved("v22.06", "SofaUserInteraction", Sofa.Component.Controller) }, + { "MechanicalStateController", Moved("v22.06", "SofaUserInteraction", Sofa.Component.Controller) }, // SofaObjectInteraction was deprecated in #2813 - { "PenalityContactForceField", Moved("v22.06", "SofaObjectInteraction", "Sofa.Component.Collision.Response.Contact") }, + { "PenalityContactForceField", Moved("v22.06", "SofaObjectInteraction", Sofa.Component.Collision.Response.Contact) }, // SofaEngine was deprecated in #2812 - { "BoxROI", Moved("v22.06", "SofaEngine", "Sofa.Component.Engine.Select") }, + { "BoxROI", Moved("v22.06", "SofaEngine", Sofa.Component.Engine.Select) }, // SofaGeneralEngine was deprecated in #2812 - { "AverageCoord", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "BoxROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "ClusteringEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "ComplementaryROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "DifferenceEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "DilateEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "DisplacementTransformEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "ExtrudeEdgesAndGenerateQuads", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "ExtrudeQuadsAndGenerateHexas", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "ExtrudeSurface", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "GenerateCylinder", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "GenerateGrid", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "GenerateRigidMass", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "GenerateSphere", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "GroupFilterYoungModulus", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "HausdorffDistance", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "IndexValueMapper", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "Indices2ValuesMapper", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "IndicesFromValues", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "InvertTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "JoinPoints", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MapIndices", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "MathOp", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "MergeMeshes", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MergePoints", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MergeROIs", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "MergeSets", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MergeVectors", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MeshBarycentricMapperEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MeshBoundaryROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "MeshClosingEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "MeshROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "MeshSampler", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "MeshSplittingEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "MeshSubsetEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "NearestPointROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "NormEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "NormalsFromPoints", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "PairBoxROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "PlaneROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "PointsFromIndices", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "ProximityROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "QuatToRigidEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "ROIValueMapper", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "RandomPointDistributionInSurface", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "RigidToQuatEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "RotateTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "ScaleTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "SelectConnectedLabelsROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "SelectLabelROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "ShapeMatching", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "SmoothMeshEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "SphereROI", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "Spiral", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Generate") }, - { "SubsetTopology", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "SumEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "TransformEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "TransformPosition", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "TranslateTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "ValuesFromIndices", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "ValuesFromPositions", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Select") }, - { "Vertex2Frame", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, + { "AverageCoord", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "BoxROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "ClusteringEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "ComplementaryROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "DifferenceEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "DilateEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "DisplacementTransformEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "ExtrudeEdgesAndGenerateQuads", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "ExtrudeQuadsAndGenerateHexas", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "ExtrudeSurface", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "GenerateCylinder", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "GenerateGrid", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "GenerateRigidMass", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "GenerateSphere", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "GroupFilterYoungModulus", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "HausdorffDistance", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "IndexValueMapper", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "Indices2ValuesMapper", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "IndicesFromValues", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "InvertTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "JoinPoints", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MapIndices", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "MathOp", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "MergeMeshes", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MergePoints", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MergeROIs", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "MergeSets", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MergeVectors", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MeshBarycentricMapperEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MeshBoundaryROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "MeshClosingEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "MeshROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "MeshSampler", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "MeshSplittingEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "MeshSubsetEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "NearestPointROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "NormEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "NormalsFromPoints", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "PairBoxROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "PlaneROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "PointsFromIndices", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "ProximityROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "QuatToRigidEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "ROIValueMapper", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "RandomPointDistributionInSurface", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "RigidToQuatEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "RotateTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "ScaleTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "SelectConnectedLabelsROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "SelectLabelROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "ShapeMatching", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "SmoothMeshEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "SphereROI", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "Spiral", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Generate) }, + { "SubsetTopology", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "SumEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "TransformEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "TransformPosition", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "TranslateTransformMatrixEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "ValuesFromIndices", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "ValuesFromPositions", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Select) }, + { "Vertex2Frame", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, // SofaMiscEngine was deprecated in #2812 - { "Distances", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Analyze") }, - { "DisplacementMatrixEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, - { "ProjectiveTransformEngine", Moved("v22.06", "SofaGeneralEngine", "Sofa.Component.Engine.Transform") }, + { "Distances", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Analyze) }, + { "DisplacementMatrixEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, + { "ProjectiveTransformEngine", Moved("v22.06", "SofaGeneralEngine", Sofa.Component.Engine.Transform) }, // SofaMiscExtra was deprecated in #2917 - { "MeshTetraStuffing", Moved("v22.06", "SofaMiscExtra", "Sofa.Component.Engine.Generate") }, + { "MeshTetraStuffing", Moved("v22.06", "SofaMiscExtra", Sofa.Component.Engine.Generate) }, // SofaMiscCollision was deprecated in #2813 and #2820 { "OBBModel", Moved("v22.06", "SofaMiscCollision", "CollisionOBBCapsule") }, { "RigidCapsuleCollisionModel", Moved("v22.06", "SofaMiscCollision", "CollisionOBBCapsule") }, { "CapsuleCollisionModel", Moved("v22.06", "SofaMiscCollision", "CollisionOBBCapsule") }, - { "TriangleModelInRegularGrid", Moved("v22.06", "SofaMiscCollision", "Sofa.Component.Collision.Geometry") }, - { "TetrahedronCollisionModel", Moved("v22.06", "SofaMiscCollision", "Sofa.Component.Collision.Geometry") }, - { "RuleBasedContactManager", Moved("v22.06", "SofaMiscCollision", "Sofa.Component.Collision.Response.Contact") }, + { "TriangleModelInRegularGrid", Moved("v22.06", "SofaMiscCollision", Sofa.Component.Collision.Geometry) }, + { "TetrahedronCollisionModel", Moved("v22.06", "SofaMiscCollision", Sofa.Component.Collision.Geometry) }, + { "RuleBasedContactManager", Moved("v22.06", "SofaMiscCollision", Sofa.Component.Collision.Response.Contact) }, // SofaHaptics was deprecated in #3039 - { "ForceFeedback", Moved("v22.06", "SofaHaptics", "Sofa.Component.Haptics") }, - { "LCPForceFeedback", Moved("v22.06", "SofaHaptics", "Sofa.Component.Haptics") }, - { "MechanicalStateForceFeedback", Moved("v22.06", "SofaHaptics", "Sofa.Component.Haptics") }, - { "NullForceFeedback", Moved("v22.06", "SofaHaptics", "Sofa.Component.Haptics") }, + { "ForceFeedback", Moved("v22.06", "SofaHaptics", Sofa.Component.Haptics) }, + { "LCPForceFeedback", Moved("v22.06", "SofaHaptics", Sofa.Component.Haptics) }, + { "MechanicalStateForceFeedback", Moved("v22.06", "SofaHaptics", Sofa.Component.Haptics) }, + { "NullForceFeedback", Moved("v22.06", "SofaHaptics", Sofa.Component.Haptics) }, // SofaValidation was deprecated in #3039 - { "CompareState", Moved("v22.06", "SofaValidation", "Sofa.Component.Playback") }, - { "CompareTopology", Moved("v22.06", "SofaValidation", "Sofa.Component.Playback") }, + { "CompareState", Moved("v22.06", "SofaValidation", Sofa.Component.Playback) }, + { "CompareTopology", Moved("v22.06", "SofaValidation", Sofa.Component.Playback) }, // Removed in #4040, deprecated in #2777 { "MechanicalMatrixMapper", Removed("v23.06", "v23.12") }, { "MappingGeometricStiffnessForceField", Removed("v23.06", "v23.12") }, // Moved to CSparseSolvers - { "SparseCholeskySolver", Moved("v23.12", "Sofa.Component.LinearSolver.Direct", "CSparseSolvers") }, - { "SparseLUSolver", Moved("v23.12", "Sofa.Component.LinearSolver.Direct", "CSparseSolvers") }, + { "SparseCholeskySolver", Moved("v23.12", Sofa.Component.LinearSolver.Direct, "CSparseSolvers") }, + { "SparseLUSolver", Moved("v23.12", Sofa.Component.LinearSolver.Direct, "CSparseSolvers") }, // Moved to Sofa.Component.MechanicalLoad - { "Gravity", Moved("v24.12", "SofaGraphComponent", "Sofa.Component.Mechanicalload") } + { "Gravity", Moved("v24.12", "SofaGraphComponent", Sofa.Component.MechanicalLoad) }, + + { "OglCylinderModel", Moved("v24.12", "Sofa.GL.Component.Rendering3D", "Sofa.Component.Visual")} }; const std::map > uncreatableComponents = { @@ -760,8 +762,8 @@ const std::map< std::string, Renamed, std::less<> > renamedComponents = { {"UnilateralInteractionConstraint", Renamed("v24.06","v25.06","UnilateralLagrangianConstraint")}, {"StiffSpringForceField", Renamed("v24.06","v25.06","SpringForceField")}, {"ParallelStiffSpringForceField", Renamed("v24.06","v25.06","ParallelSpringForceField")}, - {"ShewchukPCGLinearSolver", Renamed("v24.12","v25.12","PCGLinearSolver")} - + {"ShewchukPCGLinearSolver", Renamed("v24.12","v25.12","PCGLinearSolver")}, + {"OglCylinderModel", Renamed("v24.12", "v25.06", "CylinderVisualModel")} }; diff --git a/Sofa/framework/Helper/src/sofa/helper/OptionsGroup.h b/Sofa/framework/Helper/src/sofa/helper/OptionsGroup.h index a6fa39ac04b..d53707e4e9a 100644 --- a/Sofa/framework/Helper/src/sofa/helper/OptionsGroup.h +++ b/Sofa/framework/Helper/src/sofa/helper/OptionsGroup.h @@ -28,7 +28,6 @@ #include #include -#include namespace sofa::helper { @@ -58,7 +57,7 @@ public : explicit OptionsGroup(int nbofRadioButton,...); ///generic constructor taking other string container like list, set, vector - template ::value> > + template explicit OptionsGroup(const T& list); template OptionsGroup(const std::initializer_list& list); @@ -114,7 +113,7 @@ public : type::vector textItems ; unsigned int selectedItem ; - template void buildFromContainer(const T& list); + template void buildFromContainer(const T& list); public: @@ -137,7 +136,7 @@ inline std::istream & operator >>(std::istream& in, OptionsGroup& m_trick) return in; } -template +template OptionsGroup::OptionsGroup(const T& list) { buildFromContainer(list); @@ -159,7 +158,7 @@ void OptionsGroup::setNames(const std::initializer_list& list) selectedItem=0; } -template +template void OptionsGroup::buildFromContainer(const T& list) { textItems.reserve(list.size()); diff --git a/Sofa/framework/Helper/src/sofa/helper/SelectableItem.h b/Sofa/framework/Helper/src/sofa/helper/SelectableItem.h index 87a32ecedd9..06a86c4cc9b 100644 --- a/Sofa/framework/Helper/src/sofa/helper/SelectableItem.h +++ b/Sofa/framework/Helper/src/sofa/helper/SelectableItem.h @@ -1,4 +1,4 @@ -/****************************************************************************** +/****************************************************************************** * SOFA, Simulation Open-Framework Architecture * * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * * * @@ -87,9 +87,9 @@ struct BaseSelectableItem [[nodiscard]] virtual std::size_t getNumberOfItems() const { return 0; } [[nodiscard]] virtual const Item* getItemsData() const { return nullptr; } [[nodiscard]] virtual std::size_t getSelectedId() const { return 0; } - virtual void setSelectedId(std::size_t id) {} - virtual void print(std::ostream& out) const {} - virtual void readFromStream(std::istream& stream) {} + virtual void setSelectedId(std::size_t /* id */) {} + virtual void print(std::ostream& /* out */) const {} + virtual void readFromStream(std::istream& /* stream */) {} }; inline std::ostream& operator<<(std::ostream& out, const BaseSelectableItem& selectableItem) @@ -240,27 +240,20 @@ class SelectableItem : public BaseSelectableItem static constexpr id_type findId(const std::string_view key) { - return findId_impl(key, std::make_index_sequence{}); - } - - template - static constexpr id_type findId_impl(const std::string_view key, std::index_sequence) - { - id_type result = static_cast(-1); - ((Derived::s_items[Is].key == key ? (result = Is, true) : false) || ...); - return result; + //use std::ranges::enumerate in C++23 + for (id_type i = 0; i < numberOfItems(); ++i) + { + if (key == Derived::s_items[i].key) + { + return i; + } + } + return static_cast(-1); } - template > - struct has_deprecation_map : std::false_type {}; - - // Specialization when T has a static member s_foo - template - struct has_deprecation_map> : std::true_type {}; - void keyError(const std::string_view key) { - if constexpr (has_deprecation_map::value) + if constexpr (requires {Derived::s_deprecationMap;}) { static_assert(std::is_same_v, std::map>); const auto it = Derived::s_deprecationMap.find(key); diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessor.h b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessor.h index 624990800b3..fdf801a9ed6 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessor.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessor.h @@ -72,8 +72,8 @@ class ReadAccessor const_reference operator* () const { return *vref; } }; -template -class ReadAccessor::value>> +template +class ReadAccessor : public ReadAccessorFixedArray< FixedArrayLikeType > { public: @@ -82,9 +82,8 @@ class ReadAccessor -class ReadAccessor::value> > +template +class ReadAccessor : public ReadAccessorVector< VectorLikeType > { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorFixedArray.h b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorFixedArray.h index 62e493e45eb..71cf83fac57 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorFixedArray.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorFixedArray.h @@ -28,7 +28,7 @@ namespace sofa::helper { ////////////////////////// ReadAccessor for wrapping around fixed array like object ////////////////////// /// ReadAccessor implementation class for fixed array types -template +template class ReadAccessorFixedArray { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorVector.h b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorVector.h index 7e41acfd7c5..1563e8af637 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorVector.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/ReadAccessorVector.h @@ -28,7 +28,7 @@ namespace sofa::helper { ////////////////////////// ReadAccessor for wrapping around vector like object ////////////////////// /// ReadAccessor implementation class for vector types -template +template class ReadAccessorVector { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessor.h b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessor.h index e1abe8b7442..23b4695b7ef 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessor.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessor.h @@ -83,8 +83,8 @@ class WriteAccessor } }; -template -class WriteAccessor::value>> +template +class WriteAccessor : public WriteAccessorFixedArray< FixedArrayLikeType > { public: @@ -93,9 +93,8 @@ class WriteAccessor -class WriteAccessor::value>> +template +class WriteAccessor : public WriteAccessorVector< VectorLikeType > { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorFixedArray.h b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorFixedArray.h index 0953e07da48..5f6cc826d3c 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorFixedArray.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorFixedArray.h @@ -27,7 +27,7 @@ namespace sofa::helper { /// WriteAccessor implementation class for fixed array types -template +template class WriteAccessorFixedArray { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorVector.h b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorVector.h index a1036e867b6..0b699c93a01 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorVector.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteAccessorVector.h @@ -27,7 +27,7 @@ namespace sofa::helper { /// WriteAccessor implementation class for vector types -template +template class WriteAccessorVector { public: @@ -72,6 +72,7 @@ class WriteAccessorVector ////// Modifiers ////// void clear() { vref->clear(); } void resize(Size s) { vref->resize(s); } + void resize(Size s, const value_type& value) { vref->resize(s, value); } iterator insert(const_iterator pos, const T& value) { return vref->insert(pos, value); } iterator erase(iterator pos) { return vref->erase(pos); } diff --git a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteOnlyAccessor.h b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteOnlyAccessor.h index c333ef19b21..9004581c784 100644 --- a/Sofa/framework/Helper/src/sofa/helper/accessor/WriteOnlyAccessor.h +++ b/Sofa/framework/Helper/src/sofa/helper/accessor/WriteOnlyAccessor.h @@ -39,9 +39,8 @@ class WriteOnlyAccessor : public WriteAccessor explicit WriteOnlyAccessor(container_type& container) : WriteAccessor(container) {} }; -template -class WriteOnlyAccessor::value> > +template +class WriteOnlyAccessor : public WriteAccessorVector< VectorLikeType > { public: diff --git a/Sofa/framework/Helper/src/sofa/helper/system/FileRepository.cpp b/Sofa/framework/Helper/src/sofa/helper/system/FileRepository.cpp index 9fbef88b423..dfd888f7de4 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/FileRepository.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/FileRepository.cpp @@ -86,7 +86,6 @@ FileRepository PluginRepository( { Utils::getSofaPathTo("bin"), Utils::getSofaPathTo("plugins"), - Utils::getSofaPathTo("collections"), Utils::getExecutableDirectory(), } ); @@ -94,9 +93,8 @@ FileRepository PluginRepository( FileRepository PluginRepository( "SOFA_PLUGIN_PATH", { - Utils::getSofaPathTo("plugins"), - Utils::getSofaPathTo("collections"), Utils::getSofaPathTo("lib"), + Utils::getSofaPathTo("plugins"), } ); #endif diff --git a/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp b/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp index bf4df3e3c7b..35ec52d97b1 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp @@ -40,6 +40,48 @@ using sofa::helper::system::FileSystem; #include #include +#ifdef SOFA_BUILD_CONFIGURATION +constexpr std::string_view SOFA_BUILD_CONFIGURATION_STR = sofa_tostring(SOFA_BUILD_CONFIGURATION); +#else +constexpr std::string_view SOFA_BUILD_CONFIGURATION_STR = "NONE"; +#endif + +constexpr std::string_view GetSofaBuildConfigurationString() +{ + return SOFA_BUILD_CONFIGURATION_STR; +} + +enum class SofaBuildConfiguration +{ + Release, + RelWithDebInfo, + Debug, + MinSizeRel, + NonStandard +}; + +constexpr SofaBuildConfiguration GetSofaBuildConfiguration() +{ + if constexpr (GetSofaBuildConfigurationString() == "Release") + { + return SofaBuildConfiguration::Release; + } + if constexpr (GetSofaBuildConfigurationString() == "RelWithDebInfo") + { + return SofaBuildConfiguration::RelWithDebInfo; + } + if constexpr (GetSofaBuildConfigurationString() == "Debug") + { + return SofaBuildConfiguration::Debug; + } + if constexpr (GetSofaBuildConfigurationString() == "MinSizeRel") + { + return SofaBuildConfiguration::MinSizeRel; + } + + return SofaBuildConfiguration::NonStandard; +} + namespace sofa::helper::system { @@ -146,11 +188,14 @@ void PluginManager::writeToIniFile(const std::string& path) /// (depends on platform, version, debug/release build) std::string PluginManager::getDefaultSuffix() { -#ifdef SOFA_LIBSUFFIX - return sofa_tostring(SOFA_LIBSUFFIX); -#else - return std::string(); -#endif + if constexpr(GetSofaBuildConfiguration() == SofaBuildConfiguration::Debug) + { + return "_d"; + } + else + { + return ""; + } } PluginManager::PluginLoadStatus PluginManager::loadPluginByPath(const std::string& pluginPath, std::ostream* errlog) @@ -469,17 +514,46 @@ std::string PluginManager::findPlugin(const std::string& pluginName, const std:: } } } - - // Second try: case-insensitive and recursive + + // Second try: case-insensitive and non-recursive + if (ignoreCase) + { + const std::string downcaseLibName = helper::downcaseString(libName); + + for (const auto & dir : searchPaths) + { + const std::array paths = + { + dir, // Non-Multi-Config build, install + FileSystem::append(dir, GetSofaBuildConfigurationString()) // Multi-Config build + }; + + for (const auto & path : paths) + { + if ( fs::exists(path) ) + { + for (auto const& dirEntry : std::filesystem::directory_iterator{path}) + { + const std::string filename = dirEntry.path().filename().string(); + const std::string downcaseFilename = helper::downcaseString(filename); + if (downcaseFilename == downcaseLibName) + { + return FileSystem::cleanPath(dirEntry.path().string()); + } + } + } + } + } + } + + // Last try: case-insensitive and recursive if (ignoreCase) { if(!recursive) maxRecursiveDepth = 0; const std::string downcaseLibName = helper::downcaseString(libName); - - for (std::vector::iterator i = searchPaths.begin(); i!=searchPaths.end(); i++) + + for (const auto & dir : searchPaths) { - const std::string& dir = *i; - fs::recursive_directory_iterator iter(dir); fs::recursive_directory_iterator end; diff --git a/Sofa/framework/Helper/test/io/MeshOBJ_test.cpp b/Sofa/framework/Helper/test/io/MeshOBJ_test.cpp index 8f785fe1706..b673a6e933f 100644 --- a/Sofa/framework/Helper/test/io/MeshOBJ_test.cpp +++ b/Sofa/framework/Helper/test/io/MeshOBJ_test.cpp @@ -32,11 +32,11 @@ namespace sofa { class MeshOBJ_test : public BaseTest { protected: - void SetUp() override + void doSetUp() override { sofa::helper::system::DataRepository.addFirstPath(SOFA_TESTING_RESOURCES_DIR); } - void TearDown() override + void doTearDown() override { sofa::helper::system::DataRepository.removePath(SOFA_TESTING_RESOURCES_DIR); } diff --git a/Sofa/framework/Helper/test/io/STBImage_test.cpp b/Sofa/framework/Helper/test/io/STBImage_test.cpp index df88da8b06a..cd05d8dbc99 100644 --- a/Sofa/framework/Helper/test/io/STBImage_test.cpp +++ b/Sofa/framework/Helper/test/io/STBImage_test.cpp @@ -43,11 +43,11 @@ class STBImage_test : public BaseTest } - void SetUp() override + void doSetUp() override { sofa::helper::system::DataRepository.addFirstPath(STBIMAGETEST_RESOURCES_DIR); } - void TearDown() override + void doTearDown() override { sofa::helper::system::DataRepository.removePath(STBIMAGETEST_RESOURCES_DIR); } diff --git a/Sofa/framework/Helper/test/io/XspLoader_test.cpp b/Sofa/framework/Helper/test/io/XspLoader_test.cpp index c7d1476d54e..eb3acc1574c 100644 --- a/Sofa/framework/Helper/test/io/XspLoader_test.cpp +++ b/Sofa/framework/Helper/test/io/XspLoader_test.cpp @@ -85,11 +85,11 @@ class XspLoader_test : public BaseTest } }; - void SetUp() override + void doSetUp() override { sofa::helper::system::DataRepository.addFirstPath(SOFA_TESTING_RESOURCES_DIR); } - void TearDown() override + void doTearDown() override { sofa::helper::system::DataRepository.removePath(SOFA_TESTING_RESOURCES_DIR); } diff --git a/Sofa/framework/Helper/test/system/PluginManager_test.cpp b/Sofa/framework/Helper/test/system/PluginManager_test.cpp index ec780e35207..7d9ebf95dad 100644 --- a/Sofa/framework/Helper/test/system/PluginManager_test.cpp +++ b/Sofa/framework/Helper/test/system/PluginManager_test.cpp @@ -64,7 +64,7 @@ struct PluginManager_test: public BaseTest // This list of paths will be deleted when cleaning-up the test sofa::type::vector createdFilesToDelete; - void SetUp() override + void doSetUp() override { // Set pluginDir by searching pluginFileName in the PluginRepository for ( std::string path : sofa::helper::system::PluginRepository.getPaths() ) @@ -83,7 +83,7 @@ struct PluginManager_test: public BaseTest << std::endl; } - void TearDown() override + void doTearDown() override { for (const auto& file : createdFilesToDelete) { @@ -122,12 +122,22 @@ TEST_F(PluginManager_test, loadTestPluginAByPath) /// Check that existing plugins are correctly handled and returns no /// error/warning message. { - EXPECT_MSG_NOEMIT(Warning, Error); - + EXPECT_MSG_NOEMIT(Error, Warning); + std::cout << "PluginManager_test.loadTestPluginAByPath: " - << "pm.getPluginMap().size() = " << pm.getPluginMap().size() - << std::endl; + << "pm.getPluginMap().size() = " << pm.getPluginMap().size() + << std::endl; + } + { + EXPECT_MSG_NOEMIT(Error); + // Plugin A still uses the deprecated registration mechanism + // and is expected to throw a warning when loaded + EXPECT_MSG_EMIT(Warning); + ASSERT_EQ(pm.loadPluginByPath(pluginPath), PluginManager::PluginLoadStatus::SUCCESS); + } + { + EXPECT_MSG_NOEMIT(Error, Warning); ASSERT_GT(pm.findPlugin(pluginAName).size(), 0u); } diff --git a/Sofa/framework/LinearAlgebra/Testing/src/Sofa.LinearAlgebra.Testing/BaseMatrix_test.h b/Sofa/framework/LinearAlgebra/Testing/src/Sofa.LinearAlgebra.Testing/BaseMatrix_test.h index c092397e04d..4767da3fe64 100644 --- a/Sofa/framework/LinearAlgebra/Testing/src/Sofa.LinearAlgebra.Testing/BaseMatrix_test.h +++ b/Sofa/framework/LinearAlgebra/Testing/src/Sofa.LinearAlgebra.Testing/BaseMatrix_test.h @@ -47,7 +47,7 @@ class TestBaseMatrix : public sofa::testing::NumericTest static constexpr sofa::Index NbRows = T::NbRows; static constexpr sofa::Index NbCols = T::NbCols; - void onSetUp() override + void doSetUp() override { m_testedMatrix = std::make_unique(); m_testedMatrix->resize(NbRows, NbCols); @@ -55,7 +55,7 @@ class TestBaseMatrix : public sofa::testing::NumericTest m_modelMatrix.clear(); } - void onTearDown() override + void doTearDown() override { m_testedMatrix.reset(); } diff --git a/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixConstraintEigenUtils.h b/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixConstraintEigenUtils.h index 434d8758e37..3096d8d1c49 100644 --- a/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixConstraintEigenUtils.h +++ b/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixConstraintEigenUtils.h @@ -68,7 +68,7 @@ struct CompressedRowSparseMatrixToEigenSparseVec if (row.index() < eigenMat.rows()) { const auto colInsertion = colIndex + i; - if (colInsertion < eigenMat.cols()) + if (colInsertion < (std::size_t)eigenMat.cols()) { triplets.emplace_back(row.index(), colInsertion, vec[i]); } diff --git a/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixMechanical.h b/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixMechanical.h index 37784038f99..5dd349255a6 100644 --- a/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixMechanical.h +++ b/Sofa/framework/LinearAlgebra/src/sofa/linearalgebra/CompressedRowSparseMatrixMechanical.h @@ -1199,7 +1199,7 @@ class CompressedRowSparseMatrixMechanical final // final is used to allow the co /// equal result = this * v /// @warning The block sizes must be compatible ie v.size() must be a multiple of block size. - template< typename V1, typename V2, std::enable_if_t::value && sofa::type::trait::is_vector::value, int> = 0 > + template< sofa::type::trait::is_vector V1, sofa::type::trait::is_vector V2> void mul( V2& result, const V1& v ) const { this-> template tmul< Real, V2, V1 >(result, v); diff --git a/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp b/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp index f9c26dfccd7..2ce3a2cbb08 100644 --- a/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp +++ b/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp @@ -38,7 +38,7 @@ bool SimpleApi_test::testParamAPI() const Simulation::SPtr simu = createSimulation("DAG") ; const Node::SPtr root = createRootNode(simu, "root") ; - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); const auto meca1 = createObject(root, "MechanicalObject", { {"name", "aMechanicalObject1"}, @@ -62,7 +62,7 @@ bool SimpleApi_test::testParamString() const Simulation::SPtr simu = createSimulation("DAG") ; const Node::SPtr root = createRootNode(simu, "root") ; - simpleapi::importPlugin("Sofa.Component.StateContainer"); + simpleapi::importPlugin(Sofa.Component.StateContainer); const auto meca1 = createObject(root, "MechanicalObject", { {"name", "aMechanicalObject1"}, diff --git a/Sofa/framework/Simulation/Core/simutest/NodeContext_test.cpp b/Sofa/framework/Simulation/Core/simutest/NodeContext_test.cpp index 188d5daa5cd..0ee595d2963 100644 --- a/Sofa/framework/Simulation/Core/simutest/NodeContext_test.cpp +++ b/Sofa/framework/Simulation/Core/simutest/NodeContext_test.cpp @@ -41,8 +41,8 @@ class NodeContext_test: public BaseSimulationTest NodeContext_test() { - sofa::simpleapi::importPlugin("Sofa.Component.StateContainer"); - sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); } void testGetNodeObjects() diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/MechanicalOperations.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/MechanicalOperations.h index 0a52f314f56..0bf43392655 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/MechanicalOperations.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/MechanicalOperations.h @@ -156,7 +156,7 @@ class SOFA_SIMULATION_CORE_API MechanicalOperations void addMBKdx(core::MultiVecDerivId df, SReal m, SReal b, SReal k, bool clear = true, bool accumulate = true); SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_ADDMBKV() void addMBKv(core::MultiVecDerivId df, SReal m, SReal b, SReal k, bool clear = true, bool accumulate = true); - SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX() + SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX_OTHER() void setSystemMBKMatrix(SReal mFact, SReal bFact, SReal kFact, core::behavior::LinearSolver* linearSolver); protected: diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp index f3c4f3d34ec..f4f2ce91e80 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp @@ -100,6 +100,7 @@ Node::Node(const std::string& name) , animationManager(initLink("animationLoop","The AnimationLoop attached to this node (only valid for root node)")) , visualLoop(initLink("visualLoop", "The VisualLoop attached to this node (only valid for root node)")) + , visualStyle(initLink("visualStyle", "The VisualStyle(s) attached to this node")) , topology(initLink("topology", "The Topology attached to this node")) , meshTopology(initLink("meshTopology", "The MeshTopology / TopologyContainer attached to this node")) , state(initLink("state", "The State attached to this node (storing vectors such as position, velocity)")) @@ -930,6 +931,7 @@ void Node::printComponents() using core::objectmodel::ContextObject; using core::collision::Pipeline; using core::BaseState; + using core::visual::BaseVisualStyle; std::stringstream sstream; @@ -987,6 +989,9 @@ void Node::printComponents() sstream << "\n" << "VisualModel: "; for (NodeSequence::iterator i = visualModel.begin(), iend = visualModel.end(); i != iend; ++i) sstream << (*i)->getName() << " "; + sstream << "\n" << "BaseVisualStyle: "; + for (NodeSingle::iterator i = visualStyle.begin(), iend = visualStyle.end(); i != iend; ++i) + sstream << (*i)->getName() << " "; sstream << "\n" << "CollisionModel: "; for (NodeSequence::iterator i = collisionModel.begin(), iend = collisionModel.end(); i != iend; ++i) sstream << (*i)->getName() << " "; @@ -1045,6 +1050,7 @@ NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::objectmodel::ContextObject, ContextOb NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::objectmodel::ConfigurationSetting, ConfigurationSetting, configurationSetting ) NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::visual::Shader, Shader, shaders ) NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::visual::VisualModel, VisualModel, visualModel ) +NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::visual::BaseVisualStyle, VisualStyle, visualStyle ) NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::visual::VisualManager, VisualManager, visualManager ) NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::CollisionModel, CollisionModel, collisionModel ) NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::collision::Pipeline, CollisionPipeline, collisionPipeline ) @@ -1071,6 +1077,7 @@ template class NodeSequence; template class NodeSingle; template class NodeSingle; +template class NodeSingle; template class NodeSingle; template class NodeSingle; template class NodeSingle; diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.h index 0f6d4aa7d54..2318c243d9f 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.h @@ -127,6 +127,7 @@ extern template class NodeSequence; extern template class NodeSingle; extern template class NodeSingle; +extern template class NodeSingle; extern template class NodeSingle; extern template class NodeSingle; extern template class NodeSingle; @@ -255,6 +256,7 @@ class SOFA_SIMULATION_CORE_API Node : public sofa::core::objectmodel::BaseNode, NodeSingle animationManager; NodeSingle visualLoop; + NodeSingle visualStyle; NodeSingle topology; NodeSingle meshTopology; NodeSingle state; @@ -599,6 +601,7 @@ class SOFA_SIMULATION_CORE_API Node : public sofa::core::objectmodel::BaseNode, NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::objectmodel::ConfigurationSetting, ConfigurationSetting, configurationSetting ) NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::visual::Shader, Shader, shaders ) NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::visual::VisualModel, VisualModel, visualModel ) + NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::visual::BaseVisualStyle, VisualStyle, visualStyle ) NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::visual::VisualManager, VisualManager, visualManager ) NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::CollisionModel, CollisionModel, collisionModel ) NODE_DECLARE_SEQUENCE_ACCESSOR( sofa::core::collision::Pipeline, CollisionPipeline, collisionPipeline ) diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp index 088e72f3251..32e49c43ebe 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/RequiredPlugin.cpp @@ -136,17 +136,16 @@ bool RequiredPlugin::loadPlugin() objectFactory->registerObjectsFromPlugin(name); // fail-safe to check if potential components have been registered (implicitly or explicitly) - // SOFA_ATTRIBUTE_DEPRECATED__REGISTEROBJECT() std::vector entries; objectFactory->getEntriesFromTarget(entries, name); if (entries.empty()) { -// msg_warning() << "No component has been registered from " << name << ".\n" -// << "It could be because: \n" -// << " - the entrypoint registerObjects() has not been implemented;\n" -// << " - (deprecated) no sofa::core::RegisterObject() has been called;\n" -// << " - your plugin does not add any component (i.e BaseObject) into the factory. In that case, RequiredPlugin is not useful for this kind of plugin."; + msg_warning() << "No component has been registered from " << name << ".\n" + << "It could be because: \n" + << " - the entrypoint registerObjects() has not been implemented;\n" + << " - (deprecated since v24.12) no sofa::core::RegisterObject() has been called;\n" + << " - your plugin does not add any component (i.e BaseObject) into the factory. In that case, RequiredPlugin is not useful for this kind of plugin."; } if (d_stopAfterFirstSuffixFound.getValue()) break; diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/Simulation.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/Simulation.cpp index 337ac2008ce..79579eae660 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/Simulation.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/Simulation.cpp @@ -230,7 +230,8 @@ void animate(Node* root, SReal dt) void updateVisual(Node* root) { SCOPED_TIMER("Simulation::updateVisual"); - + + sofa::core::visual::VisualParams* vparams = sofa::core::visual::visualparams::defaultInstance(); if (sofa::core::visual::VisualLoop* vloop = root->getVisualLoop()) diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.cpp index cde01030ab4..3c048b2568f 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.cpp @@ -46,14 +46,34 @@ Visitor::Result VisualVisitor::processNodeTopDown(simulation::Node* node) } -Visitor::Result VisualDrawVisitor::processNodeTopDown(simulation::Node* node) +void VisualVisitor::fwdProcessVisualStyle(simulation::Node* node, core::visual::BaseVisualStyle* vm) { + SOFA_UNUSED(node); + vm-> updateVisualFlags(vparams); +} + + +void VisualVisitor::bwdProcessVisualStyle(simulation::Node* node, core::visual::BaseVisualStyle* vm) +{ + SOFA_UNUSED(node); + vm-> applyBackupFlags(vparams); +} + +Visitor::Result VisualDrawVisitor::processNodeTopDown(simulation::Node* node) +{ // NB: hasShader is only used when there are visual models and getShader does a graph search when there is no shader, // which will most probably be the case when there are no visual models, so we skip the search unless we have visual models. hasShader = !node->visualModel.empty() && (node->getShader()!=nullptr); + if(node->visualStyle.get()) + { + fwdProcessVisualStyle(node,node->visualStyle.get()); + } + + for_each(this, node, node->visualModel, &VisualDrawVisitor::fwdVisualModel); + this->VisualVisitor::processNodeTopDown(node); return RESULT_CONTINUE; @@ -65,6 +85,12 @@ void VisualDrawVisitor::processNodeBottomUp(simulation::Node* node) if (!vparams->displayFlags().getShowVisualModels()) return; + if(node->visualStyle.get()) + { + bwdProcessVisualStyle(node,node->visualStyle.get()); + } + + for_each(this, node, node->visualModel, &VisualDrawVisitor::bwdVisualModel); } @@ -149,11 +175,27 @@ void VisualDrawVisitor::processVisualModel(simulation::Node* node, core::visual: Visitor::Result VisualUpdateVisitor::processNodeTopDown(simulation::Node* node) { - for_each(this, node, node->visualModel, &VisualUpdateVisitor::processVisualModel); + //Necessary check for first draw + if(node->visualStyle.get()) + { + fwdProcessVisualStyle(node,node->visualStyle.get()); + } + + for_each(this, node, node->visualModel, &VisualUpdateVisitor::processVisualModel); return RESULT_CONTINUE; } +void VisualUpdateVisitor::processNodeBottomUp(simulation::Node* node) +{ + //Necessary check for first draw + if(node->visualStyle.get()) + { + bwdProcessVisualStyle(node,node->visualStyle.get()); + } +} + + void VisualUpdateVisitor::processVisualModel(simulation::Node*, core::visual::VisualModel* vm) { helper::ScopedAdvancedTimer timer("VisualUpdateVisitor process: " + vm->getName()); diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.h index 44ca10602b6..f44a98cef82 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/VisualVisitor.h @@ -24,6 +24,7 @@ #include #include +#include namespace sofa::simulation @@ -38,6 +39,8 @@ class SOFA_SIMULATION_CORE_API VisualVisitor : public Visitor {} virtual void processVisualModel(simulation::Node* node, core::visual::VisualModel* vm) = 0; + virtual void fwdProcessVisualStyle(simulation::Node* node, core::visual::BaseVisualStyle* vm); + virtual void bwdProcessVisualStyle(simulation::Node* node, core::visual::BaseVisualStyle* vm); virtual void processObject(simulation::Node* /*node*/, core::objectmodel::BaseObject* /*o*/) {} Result processNodeTopDown(simulation::Node* node) override; @@ -54,14 +57,14 @@ class SOFA_SIMULATION_CORE_API VisualVisitor : public Visitor core::visual::VisualParams* vparams; }; + class SOFA_SIMULATION_CORE_API VisualDrawVisitor : public VisualVisitor { public: bool hasShader; VisualDrawVisitor(core::visual::VisualParams* params) - : VisualVisitor(params) - { - } + : VisualVisitor(params) + {}; Result processNodeTopDown(simulation::Node* node) override; void processNodeBottomUp(simulation::Node* node) override; virtual void fwdVisualModel(simulation::Node* node, core::visual::VisualModel* vm); @@ -83,11 +86,10 @@ class SOFA_SIMULATION_CORE_API VisualUpdateVisitor : public VisualVisitor virtual void processVisualModel(simulation::Node*, core::visual::VisualModel* vm) override; Result processNodeTopDown(simulation::Node* node) override; + void processNodeBottomUp(simulation::Node* node) override; const char* getClassName() const override { return "VisualUpdateVisitor"; } -protected: - core::visual::VisualParams* m_vparams; }; class SOFA_SIMULATION_CORE_API VisualInitVisitor : public VisualVisitor diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/config.h.in b/Sofa/framework/Simulation/Core/src/sofa/simulation/config.h.in index 0497c54b26d..53ed3e67af5 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/config.h.in +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/config.h.in @@ -296,9 +296,9 @@ SOFA_ATTRIBUTE_DISABLED("v23.12", "v24.06", "rootdata/nodedata feature was never #endif // SOFA_BUILD_SOFA_SIMULATION_CORE #ifdef SOFA_BUILD_SOFA_SIMULATION_CORE -#define SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX() +#define SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX_OTHER() #else -#define SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX() \ +#define SOFA_ATTRIBUTE_DEPRECATED_MECHANICALOPERATIONS_SETSYSTEMMBKMATRIX_OTHER() \ SOFA_ATTRIBUTE_DEPRECATED( \ "v24.12", "v25.06", "Use the other setSystemMBKMatrix overload instead.") #endif // SOFA_BUILD_SOFA_SIMULATION_CORE diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyPositionAndVelocityVisitor.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyPositionAndVelocityVisitor.h index 96e8060eaf6..a037c9d18b7 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyPositionAndVelocityVisitor.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyPositionAndVelocityVisitor.h @@ -45,7 +45,7 @@ class SOFA_SIMULATION_CORE_API MechanicalPropagateOnlyPositionAndVelocityVisitor sofa::core::MultiVecDerivId v; MechanicalPropagateOnlyPositionAndVelocityVisitor(const sofa::core::MechanicalParams* mparams, SReal time=0, - sofa::core::MultiVecCoordId x = sofa::core::VecId::position(), sofa::core::MultiVecDerivId v = sofa::core::VecId::velocity()); + sofa::core::MultiVecCoordId x = sofa::core::vec_id::write_access::position, sofa::core::MultiVecDerivId v = sofa::core::vec_id::write_access::velocity); Result fwdMechanicalState(simulation::Node* /*node*/,sofa::core::behavior::BaseMechanicalState* mm) override; Result fwdMechanicalMapping(simulation::Node* /*node*/, sofa::core::BaseMapping* map) override; diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyVelocityVisitor.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyVelocityVisitor.h index 330a457fa48..dbdcf3d6d08 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyVelocityVisitor.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/mechanicalvisitor/MechanicalPropagateOnlyVelocityVisitor.h @@ -43,7 +43,7 @@ class SOFA_SIMULATION_CORE_API MechanicalPropagateOnlyVelocityVisitor : public M sofa::core::MultiVecDerivId v; MechanicalPropagateOnlyVelocityVisitor(const sofa::core::MechanicalParams* mparams, SReal time=0, - sofa::core::MultiVecDerivId v = sofa::core::VecId::velocity()); + sofa::core::MultiVecDerivId v = sofa::core::vec_id::write_access::velocity); Result fwdMechanicalState(simulation::Node* /*node*/,sofa::core::behavior::BaseMechanicalState* mm) override; Result fwdMechanicalMapping(simulation::Node* /*node*/, sofa::core::BaseMapping* map) override; diff --git a/Sofa/framework/Simulation/Core/test/RequiredPlugin_test.cpp b/Sofa/framework/Simulation/Core/test/RequiredPlugin_test.cpp index c9349748989..1013581b97a 100644 --- a/Sofa/framework/Simulation/Core/test/RequiredPlugin_test.cpp +++ b/Sofa/framework/Simulation/Core/test/RequiredPlugin_test.cpp @@ -85,7 +85,7 @@ struct RequiredPlugin_test : public BaseSimulationTest void testLoadPluginB() { - EXPECT_MSG_EMIT(Warning); // // TestPluginB does not register any component + EXPECT_MSG_EMIT(Warning); // TestPluginB does not register any component std::stringstream scene; scene << "" @@ -101,7 +101,7 @@ struct RequiredPlugin_test : public BaseSimulationTest void testLoadPluginC() { - EXPECT_MSG_NOEMIT(Warning); // // TestPluginC registers its component explicitly + EXPECT_MSG_NOEMIT(Warning); // TestPluginC registers its component explicitly std::stringstream scene; scene << "" @@ -118,8 +118,8 @@ struct RequiredPlugin_test : public BaseSimulationTest TEST_F(RequiredPlugin_test, testNotExistingPlugin ) { testNotExistingPlugin(); } TEST_F(RequiredPlugin_test, testNoParameter ) { testNoParameter(); } -TEST_F(RequiredPlugin_test, DISABLED_testLoadPluginA) { testLoadPluginA(); } // disabled because testLoadPluginA() should throw a warning (but this warning is commented for the moment) -TEST_F(RequiredPlugin_test, DISABLED_testLoadPluginB) { testLoadPluginB(); }// disabled because testLoadPluginB() should throw a warning (but this warning is commented for the moment) +TEST_F(RequiredPlugin_test, testLoadPluginA) { testLoadPluginA(); } +TEST_F(RequiredPlugin_test, testLoadPluginB) { testLoadPluginB(); } TEST_F(RequiredPlugin_test, testLoadPluginC) { testLoadPluginC(); } } diff --git a/Sofa/framework/Simulation/Graph/test/MutationListener_test.cpp b/Sofa/framework/Simulation/Graph/test/MutationListener_test.cpp index 1ffcafa8813..c2d20e7bc9c 100644 --- a/Sofa/framework/Simulation/Graph/test/MutationListener_test.cpp +++ b/Sofa/framework/Simulation/Graph/test/MutationListener_test.cpp @@ -411,14 +411,14 @@ struct MutationListener_test : public BaseTest listener.log); } - void SetUp() override + void doSetUp() override { sofa::simulation::Simulation* simu = sofa::simulation::getSimulation(); root = simu->createNewGraph("root"); root->addListener(&listener); } - void TearDown() override + void doTearDown() override { } }; diff --git a/Sofa/framework/Simulation/simutest/parallel_scenes_test.cpp b/Sofa/framework/Simulation/simutest/parallel_scenes_test.cpp index 8ed14089499..5bb847fea9e 100644 --- a/Sofa/framework/Simulation/simutest/parallel_scenes_test.cpp +++ b/Sofa/framework/Simulation/simutest/parallel_scenes_test.cpp @@ -29,9 +29,6 @@ using sofa::simulation::Node ; #include using sofa::component::sceneutility::InfoComponent; -#include -using sofa::helper::system::PluginManager ; - #include using sofa::simulation::SceneLoaderXML ; @@ -47,10 +44,36 @@ class ParallelScenesTest : public virtual sofa::testing::BaseTest { } + void doSetUp() override + { + EXPECT_MSG_NOEMIT(Error, Warning); + + sofa::simpleapi::importPlugin(Sofa.Component.AnimationLoop); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Detection.Algorithm); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Detection.Intersection); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Geometry); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Response.Contact); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Lagrangian.Correction); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Lagrangian.Solver); + sofa::simpleapi::importPlugin(Sofa.Component.Constraint.Projective); + sofa::simpleapi::importPlugin(Sofa.Component.IO.Mesh); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.Mapping.Linear); + sofa::simpleapi::importPlugin(Sofa.Component.Mass); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Constant); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Dynamic); + sofa::simpleapi::importPlugin(Sofa.Component.Topology.Container.Grid); + sofa::simpleapi::importPlugin(Sofa.Component.Visual); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Rendering3D); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSystem); + } + void executeInParallel(const char* sceneStr, const std::size_t nbScenes, const std::size_t nbSteps) { - EXPECT_MSG_NOEMIT(Error); - EXPECT_MSG_NOEMIT(Warning); + EXPECT_MSG_NOEMIT(Error, Warning); std::vector groots; groots.resize(nbScenes); @@ -104,21 +127,6 @@ class ParallelScenesTest : public virtual sofa::testing::BaseTest const std::string sceneStr = R"( - - - - - - - - - - - - - - - @@ -160,29 +168,6 @@ class ParallelScenesTest : public virtual sofa::testing::BaseTest const std::string sceneStr = R"( - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Sofa/framework/Testing/CMakeLists.txt b/Sofa/framework/Testing/CMakeLists.txt index a4152a1925c..22b0a88b2ea 100644 --- a/Sofa/framework/Testing/CMakeLists.txt +++ b/Sofa/framework/Testing/CMakeLists.txt @@ -65,6 +65,7 @@ set(HEADER_FILES ${SOFATESTINGSRC_ROOT}/BaseTest.h ${SOFATESTINGSRC_ROOT}/LinearCongruentialRandomGenerator.h ${SOFATESTINGSRC_ROOT}/NumericTest.h + ${SOFATESTINGSRC_ROOT}/ScopedPlugin.h ${SOFATESTINGSRC_ROOT}/TestMessageHandler.h ${SOFATESTINGSRC_ROOT}/BaseSimulationTest.h ) @@ -74,6 +75,7 @@ set(SOURCE_FILES ${SOFATESTINGSRC_ROOT}/BaseTest.cpp ${SOFATESTINGSRC_ROOT}/LinearCongruentialRandomGenerator.cpp ${SOFATESTINGSRC_ROOT}/NumericTest.cpp + ${SOFATESTINGSRC_ROOT}/ScopedPlugin.cpp ${SOFATESTINGSRC_ROOT}/TestMessageHandler.cpp ${SOFATESTINGSRC_ROOT}/BaseSimulationTest.cpp ) diff --git a/Sofa/framework/Testing/src/sofa/testing/BaseTest.cpp b/Sofa/framework/Testing/src/sofa/testing/BaseTest.cpp index 618a974466a..f4c6de7a263 100644 --- a/Sofa/framework/Testing/src/sofa/testing/BaseTest.cpp +++ b/Sofa/framework/Testing/src/sofa/testing/BaseTest.cpp @@ -93,14 +93,21 @@ BaseTest::BaseTest() : BaseTest::~BaseTest() {} +void BaseTest::loadPlugins( + const std::initializer_list& pluginNames) +{ + m_loadedPlugins.emplace_back(pluginNames.begin(), pluginNames.end()); +} + void BaseTest::SetUp() { - onSetUp(); + doSetUp(); } void BaseTest::TearDown() { - onTearDown(); + m_loadedPlugins.clear(); + doTearDown(); } diff --git a/Sofa/framework/Testing/src/sofa/testing/BaseTest.h b/Sofa/framework/Testing/src/sofa/testing/BaseTest.h index 1ec7c55dd14..303421e0ba3 100644 --- a/Sofa/framework/Testing/src/sofa/testing/BaseTest.h +++ b/Sofa/framework/Testing/src/sofa/testing/BaseTest.h @@ -21,10 +21,13 @@ ******************************************************************************/ #pragma once +#include #include +#include #include #include +#include namespace sofa::testing { @@ -45,15 +48,25 @@ class SOFA_TESTING_API BaseTest : public ::testing::Test BaseTest() ; ~BaseTest() override; + virtual void doSetUp() { onSetUp(); } + virtual void doTearDown() { onTearDown(); } + + SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONSETUP() virtual void onSetUp() {} + + SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONTEARDOWN() virtual void onTearDown() {} /// Seed value static int seed; + void loadPlugins(const std::initializer_list& pluginNames); + private: - void SetUp() override ; - void TearDown() override ; + void SetUp() final ; + void TearDown() final ; + + std::deque m_loadedPlugins; }; } // namespace sofa::testing diff --git a/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.cpp b/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.cpp new file mode 100644 index 00000000000..e0eee3ed616 --- /dev/null +++ b/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.cpp @@ -0,0 +1,60 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +namespace sofa::testing +{ + +ScopedPlugin::ScopedPlugin(const std::string& pluginName, + helper::system::PluginManager* pluginManager) +: m_pluginManager(pluginManager) +{ + addPlugin(pluginName); +} + +ScopedPlugin::~ScopedPlugin() +{ + if (m_pluginManager) + { + for (const auto& pluginName : m_loadedPlugins) + { + const auto [path, isLoaded] = m_pluginManager->isPluginLoaded(pluginName); + if (isLoaded) + { + m_pluginManager->unloadPlugin(path); + } + } + } +} + +void ScopedPlugin::addPlugin(const std::string& pluginName) +{ + const auto status = m_pluginManager->loadPlugin(pluginName); + if(status == helper::system::PluginManager::PluginLoadStatus::SUCCESS) + { + m_loadedPlugins.insert(pluginName); + sofa::core::ObjectFactory::getInstance()->registerObjectsFromPlugin(pluginName); + } +} + +} diff --git a/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.h b/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.h new file mode 100644 index 00000000000..4d1e24afe0e --- /dev/null +++ b/Sofa/framework/Testing/src/sofa/testing/ScopedPlugin.h @@ -0,0 +1,68 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include +#include + +namespace sofa::testing +{ + +struct SOFA_TESTING_API ScopedPlugin +{ + ScopedPlugin() = delete; + ScopedPlugin(const ScopedPlugin&) = delete; + void operator=(const ScopedPlugin&) = delete; + + explicit ScopedPlugin( + const std::string& pluginName, + helper::system::PluginManager* pluginManager = &helper::system::PluginManager::getInstance()); + + template + ScopedPlugin( + InputIt first, InputIt last, + helper::system::PluginManager* pluginManager = &helper::system::PluginManager::getInstance()) + : m_pluginManager(pluginManager) + { + while (first != last) + { + addPlugin(*first++); + } + } + + ~ScopedPlugin(); + +private: + helper::system::PluginManager* m_pluginManager { nullptr }; + + std::set m_loadedPlugins; + + void addPlugin(const std::string& pluginName); +}; + + +inline std::unique_ptr makeScopedPlugin(const std::initializer_list& pluginNames) +{ + return std::make_unique(pluginNames.begin(), pluginNames.end()); +} + + +} diff --git a/Sofa/framework/Testing/src/sofa/testing/config.h.in b/Sofa/framework/Testing/src/sofa/testing/config.h.in index 35221eb58fe..04dedf7c8fb 100644 --- a/Sofa/framework/Testing/src/sofa/testing/config.h.in +++ b/Sofa/framework/Testing/src/sofa/testing/config.h.in @@ -43,3 +43,20 @@ constexpr char SOFA_TESTING_RESOURCES_DIR[] = "@SOFA_TESTING_RESOURCES_DIR@"; SOFA_ATTRIBUTE_DEPRECATED( \ "v24.06", "v24.12", "Use sofa::simpleapi::importPlugin() instead.") #endif // SOFA_BUILD_SOFA_TESTING + + +#ifdef SOFA_BUILD_SOFA_TESTING +#define SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONSETUP() +#else +#define SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONSETUP() \ + SOFA_ATTRIBUTE_DEPRECATED( \ + "v25.06", "v25.12", "Use doSetUp instead.") +#endif // SOFA_BUILD_SOFA_TESTING + +#ifdef SOFA_BUILD_SOFA_TESTING +#define SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONTEARDOWN() +#else +#define SOFA_ATTRIBUTE_DEPRECATED__TESTING_ONTEARDOWN() \ + SOFA_ATTRIBUTE_DEPRECATED( \ + "v25.06", "v25.12", "Use doTearDown instead.") +#endif // SOFA_BUILD_SOFA_TESTING diff --git a/Sofa/framework/Testing/test/CMakeLists.txt b/Sofa/framework/Testing/test/CMakeLists.txt index 7d24aab0b58..3b0abcc8063 100644 --- a/Sofa/framework/Testing/test/CMakeLists.txt +++ b/Sofa/framework/Testing/test/CMakeLists.txt @@ -3,7 +3,8 @@ cmake_minimum_required(VERSION 3.22) project(Sofa.Testing_test) set(SOURCE_FILES - TestMessageHandler_test.cpp + ScopedPlugin_test.cpp + TestMessageHandler_test.cpp ) add_executable(${PROJECT_NAME} ${SOURCE_FILES}) diff --git a/Sofa/framework/Testing/test/ScopedPlugin_test.cpp b/Sofa/framework/Testing/test/ScopedPlugin_test.cpp new file mode 100644 index 00000000000..3519649f2b9 --- /dev/null +++ b/Sofa/framework/Testing/test/ScopedPlugin_test.cpp @@ -0,0 +1,59 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +TEST(ScopedPlugin, test) +{ + static std::string pluginName = "Sofa.Component.AnimationLoop"; + auto& pluginManager = sofa::helper::system::PluginManager::getInstance(); + + //make sure that pluginName is not already loaded + { + const auto [path, isLoaded] = pluginManager.isPluginLoaded(pluginName); + if (isLoaded) + { + pluginManager.unloadPlugin(path); + } + } + + { + const auto [path, isLoaded] = pluginManager.isPluginLoaded(pluginName); + EXPECT_FALSE(isLoaded); + } + + { + const sofa::testing::ScopedPlugin plugin(pluginName); + + { + const auto [path, isLoaded] = pluginManager.isPluginLoaded(pluginName); + EXPECT_TRUE(isLoaded); + } + + //end of scope: plugin should be unloaded + } + + { + const auto [path, isLoaded] = pluginManager.isPluginLoaded(pluginName); + EXPECT_FALSE(isLoaded); + } +} diff --git a/Sofa/framework/Type/src/sofa/type/BoundingBox.cpp b/Sofa/framework/Type/src/sofa/type/BoundingBox.cpp index 08c9121191e..b2d5e391af3 100644 --- a/Sofa/framework/Type/src/sofa/type/BoundingBox.cpp +++ b/Sofa/framework/Type/src/sofa/type/BoundingBox.cpp @@ -36,56 +36,23 @@ BoundingBox::bbox_t make_neutralBBox() return std::make_pair(minBBox,maxBBox); } -BoundingBox::BoundingBox() - :bbox(make_neutralBBox()) -{ -} - -BoundingBox::BoundingBox(const bbox_t& bbox) - :bbox(bbox) -{ -} - -BoundingBox::BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox) - :bbox(std::make_pair(minBBox,maxBBox)) -{ -} - -BoundingBox::BoundingBox(SReal xmin, SReal xmax, SReal ymin, SReal ymax, SReal zmin, SReal zmax ) - :bbox(std::make_pair(sofa::type::Vec3((SReal)xmin, (SReal)ymin, (SReal)zmin),sofa::type::Vec3( (SReal)xmax, (SReal)ymax, (SReal)zmax))) -{ -} - - -BoundingBox::BoundingBox(const Vec6f& v ) - :bbox(std::make_pair(sofa::type::Vec3(v[0],v[2],v[4]),sofa::type::Vec3(v[1],v[3],v[5]))) -{ -} - -BoundingBox::BoundingBox(const Vec6d& v ) - :bbox(std::make_pair(sofa::type::Vec3((SReal)v[0],(SReal)v[2],(SReal)v[4]),sofa::type::Vec3((SReal)v[1],(SReal)v[3],(SReal)v[5]))) -{ -} - - -/*static*/ -BoundingBox BoundingBox::neutral_bbox() -{ - return BoundingBox(make_neutralBBox()); -} - void BoundingBox::invalidate() { this->bbox = make_neutralBBox(); } -bool BoundingBox::isNegligeable() const +bool BoundingBox::isNegligible() const { return minBBox().x() >= maxBBox().x() && minBBox().y() >= maxBBox().y() && minBBox().z() >= maxBBox().z(); } +bool BoundingBox::isNegligeable() const +{ + return isNegligible(); +} + bool BoundingBox::isValid() const { return minBBox().x() <= maxBBox().x() && @@ -112,6 +79,11 @@ BoundingBox::operator bbox_t() const return bbox; } +bool BoundingBox::operator==(const BoundingBox& other) const +{ + return this->bbox == other.bbox; +} + SReal* BoundingBox::minBBoxPtr() { return bbox.first.ptr(); diff --git a/Sofa/framework/Type/src/sofa/type/BoundingBox.h b/Sofa/framework/Type/src/sofa/type/BoundingBox.h index fd7a4bcdd85..d868b56fff4 100644 --- a/Sofa/framework/Type/src/sofa/type/BoundingBox.h +++ b/Sofa/framework/Type/src/sofa/type/BoundingBox.h @@ -35,41 +35,68 @@ class SOFA_TYPE_API BoundingBox public: typedef std::pair< sofa::type::Vec3, sofa::type::Vec3 > bbox_t; + using Real = sofa::type::Vec3::value_type; - BoundingBox(); - /// Define using the endpoints of the main diagonal - BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox); - BoundingBox(const bbox_t& bbox); - /// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order - BoundingBox(SReal xmin, SReal xmax, SReal ymin, SReal ymax, SReal zmin, SReal zmax ); - /// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order - BoundingBox(const Vec6f& bbox); - /// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order - BoundingBox(const Vec6d& bbox); + constexpr BoundingBox() + : BoundingBox(neutral_bbox().bbox) + {} - static BoundingBox neutral_bbox(); + /// Define using the endpoints of the main diagonal + constexpr BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox) + : bbox({minBBox, maxBBox}) {} + + constexpr explicit BoundingBox(const bbox_t& bbox) + : bbox(bbox) + {} + + /// Define using xMin, xMax, yMin, yMax, zMin, zMax in this order + constexpr BoundingBox( + const Real xMin, const Real xMax, + const Real yMin, const Real yMax, + const Real zMin, const Real zMax ) + : BoundingBox({xMin, yMin, zMin}, {xMax, yMax, zMax}) + {} + + template + constexpr explicit BoundingBox(const Vec<6, Scalar>& bbox) + : BoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]) + {} + + static constexpr BoundingBox neutral_bbox() + { + constexpr Real max_real = std::numeric_limits::max(); + constexpr Real min_real = std::numeric_limits::lowest(); + return BoundingBox{ + {max_real, max_real, max_real}, + {min_real, min_real, min_real} + }; + } operator bbox_t() const; + [[nodiscard]] bool operator==(const BoundingBox& other) const; + void invalidate(); - bool isValid() const; - bool isFlat() const; - bool isNegligeable() const; // !valid || flat - bool isNull() const; + [[nodiscard]] bool isValid() const; + [[nodiscard]] bool isFlat() const; + [[nodiscard]] bool isNegligible() const; // !valid || flat + SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO() + [[nodiscard]] bool isNegligeable() const; + [[nodiscard]] bool isNull() const; SReal* minBBoxPtr(); SReal* maxBBoxPtr(); - const SReal* minBBoxPtr() const; - const SReal* maxBBoxPtr() const; - const sofa::type::Vec3& minBBox() const; - const sofa::type::Vec3& maxBBox() const; + [[nodiscard]] const SReal* minBBoxPtr() const; + [[nodiscard]] const SReal* maxBBoxPtr() const; + [[nodiscard]] const sofa::type::Vec3& minBBox() const; + [[nodiscard]] const sofa::type::Vec3& maxBBox() const; sofa::type::Vec3& minBBox(); sofa::type::Vec3& maxBBox(); - bool contains( const sofa::type::Vec3& point) const; - bool contains( const BoundingBox& other) const; + [[nodiscard]] bool contains( const sofa::type::Vec3& point) const; + [[nodiscard]] bool contains( const BoundingBox& other) const; - bool intersect( const BoundingBox& other) const; + [[nodiscard]] bool intersect( const BoundingBox& other) const; void intersection( const BoundingBox& other); void include( const sofa::type::Vec3& point); @@ -77,10 +104,10 @@ class SOFA_TYPE_API BoundingBox void inflate( SReal amount ); - BoundingBox getIntersection( const BoundingBox& other ) const; - BoundingBox getInclude( const sofa::type::Vec3& point ) const; - BoundingBox getInclude( const BoundingBox& other ) const; - BoundingBox getInflate( SReal amount ) const; + [[nodiscard]] BoundingBox getIntersection( const BoundingBox& other ) const; + [[nodiscard]] BoundingBox getInclude( const sofa::type::Vec3& point ) const; + [[nodiscard]] BoundingBox getInclude( const BoundingBox& other ) const; + [[nodiscard]] BoundingBox getInflate( SReal amount ) const; friend std::ostream& operator << ( std::ostream& out, const BoundingBox& bbox) { diff --git a/Sofa/framework/Type/src/sofa/type/MatSym.h b/Sofa/framework/Type/src/sofa/type/MatSym.h index 8a4140fdfb4..5de7389e6d1 100644 --- a/Sofa/framework/Type/src/sofa/type/MatSym.h +++ b/Sofa/framework/Type/src/sofa/type/MatSym.h @@ -137,7 +137,7 @@ class MatSym : public VecNoInit { for (sofa::Size j = 0; j < D; j++) { - for (int i = 0; i <= j; i++) + for (sofa::Size i = 0; i <= j; i++) { W(i, j) = (M(i, j) + M(j, i)) / 2; } diff --git a/Sofa/framework/Type/src/sofa/type/Quat.h b/Sofa/framework/Type/src/sofa/type/Quat.h index 739fa6e5f59..05b534d7e33 100644 --- a/Sofa/framework/Type/src/sofa/type/Quat.h +++ b/Sofa/framework/Type/src/sofa/type/Quat.h @@ -116,7 +116,7 @@ class Quat static Quat identity() { - return Quat(0,0,0,1); + return Quat(0, 0, 0, 1); } void set(Real x, Real y, Real z, Real w) @@ -147,7 +147,7 @@ class Quat void clear() { - set(0.0,0.0,0.0,1); + set(0, 0, 0, 1); } /// Convert the reference frame orientation into an orientation quaternion @@ -311,6 +311,30 @@ class Quat return _q[index]; } + template< std::size_t I > + [[nodiscard]] constexpr Real& get() & noexcept requires (I < 4) + { + return _q[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr const Real& get() const& noexcept requires (I < 4) + { + return _q[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr Real&& get() && noexcept requires (I < 4) + { + return std::move(_q[I]); + } + + template< std::size_t I > + [[nodiscard]] constexpr const Real&& get() const&& noexcept requires (I < 4) + { + return std::move(_q[I]); + } + auto inverse() const -> Quat; auto quatToRotationVector() const -> Vec3; @@ -462,3 +486,17 @@ extern template class SOFA_TYPE_API Quat; #endif } // namespace sofa::type + +namespace std +{ + +template +struct tuple_size<::sofa::type::Quat > : integral_constant {}; + +template +struct tuple_element > +{ + using type = typename::sofa::type::Quat::value_type; +}; + +} diff --git a/Sofa/framework/Type/src/sofa/type/RGBAColor.h b/Sofa/framework/Type/src/sofa/type/RGBAColor.h index 44fefc4eacc..0d4af4739a8 100644 --- a/Sofa/framework/Type/src/sofa/type/RGBAColor.h +++ b/Sofa/framework/Type/src/sofa/type/RGBAColor.h @@ -33,6 +33,8 @@ #include #include +#include + namespace sofa::type { @@ -45,8 +47,9 @@ namespace sofa::type class SOFA_TYPE_API RGBAColor { public: + using value_type = float; static constexpr sofa::Size NumberOfComponents = 4; - using ComponentArray = std::array; + using ComponentArray = std::array; constexpr RGBAColor() : m_components{ 1.f, 1.f, 1.f, 1.f } {} @@ -132,6 +135,30 @@ class SOFA_TYPE_API RGBAColor return m_components[i]; } + template< std::size_t I > + [[nodiscard]] constexpr float& get() & noexcept requires (I < 4) + { + return m_components[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr const float& get() const& noexcept requires (I < 4) + { + return m_components[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr float&& get() && noexcept requires (I < 4) + { + return std::move(m_components[I]); + } + + template< std::size_t I > + [[nodiscard]] constexpr const float&& get() const&& noexcept requires (I < 4) + { + return std::move(m_components[I]); + } + void set(float r, float g, float b, float a) ; bool operator==(const RGBAColor& b) const @@ -209,7 +236,6 @@ class SOFA_TYPE_API RGBAColor static constexpr sofa::Size static_size = NumberOfComponents; static constexpr sofa::Size size() { return static_size; } - using value_type = float; using size_type = sofa::Size; private: @@ -285,3 +311,18 @@ constexpr const RGBAColor& RGBAColor::gold() { return g_gold ; } } // namespace sofa::type + + +namespace std +{ + +template<> +struct tuple_size<::sofa::type::RGBAColor > : integral_constant {}; + +template +struct tuple_element +{ + using type = ::sofa::type::RGBAColor::value_type; +}; + +} diff --git a/Sofa/framework/Type/src/sofa/type/Vec.h b/Sofa/framework/Type/src/sofa/type/Vec.h index 48e38f038b2..7c0b5a7ff23 100644 --- a/Sofa/framework/Type/src/sofa/type/Vec.h +++ b/Sofa/framework/Type/src/sofa/type/Vec.h @@ -613,6 +613,30 @@ class Vec return elems[i]; } + template< std::size_t I > + [[nodiscard]] constexpr reference get() & noexcept requires( I < N ) + { + return elems[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr const_reference get() const& noexcept requires( I < N ) + { + return elems[I]; + } + + template< std::size_t I > + [[nodiscard]] constexpr ValueType&& get() && noexcept requires( I < N ) + { + return std::move(elems[I]); + } + + template< std::size_t I > + [[nodiscard]] constexpr const ValueType&& get() const&& noexcept requires( I < N ) + { + return std::move(elems[I]); + } + // direct access to data constexpr const ValueType* data() const noexcept { @@ -782,4 +806,13 @@ struct less< sofa::type::Vec > } }; +template +struct tuple_size<::sofa::type::Vec > : integral_constant {}; + +template +struct tuple_element > +{ + using type = T; +}; + } // namespace std diff --git a/Sofa/framework/Type/src/sofa/type/config.h.in b/Sofa/framework/Type/src/sofa/type/config.h.in index 3fc2d71b07b..2bb528f7e5f 100644 --- a/Sofa/framework/Type/src/sofa/type/config.h.in +++ b/Sofa/framework/Type/src/sofa/type/config.h.in @@ -41,3 +41,21 @@ "v23.12", "v24.06", \ "RGBAColor does not inherit anymore from sofa::type::fixed_array. Use respective functions accordingly.") #endif + +#ifdef SOFA_BUILD_SOFA_TYPE +#define SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO() +#else +#define SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO() \ + SOFA_ATTRIBUTE_DISABLED( \ + "v24.12", "v25.06", \ + "Use isNegligible instead.") +#endif + +#ifdef SOFA_BUILD_SOFA_TYPE +#define SOFA_ATTRIBUTE_DEPRECATED__IS_CONTAINER() +#else +#define SOFA_ATTRIBUTE_DEPRECATED__IS_CONTAINER() \ + SOFA_ATTRIBUTE_DISABLED( \ + "v25.06", "v25.12", \ + "Use std::ranges::ranges concept instead.") +#endif diff --git a/Sofa/framework/Type/src/sofa/type/fixed_array.h b/Sofa/framework/Type/src/sofa/type/fixed_array.h index ec1e711ca9d..edbffaa367d 100644 --- a/Sofa/framework/Type/src/sofa/type/fixed_array.h +++ b/Sofa/framework/Type/src/sofa/type/fixed_array.h @@ -83,18 +83,16 @@ class fixed_array constexpr fixed_array() {} /// Specific constructor for 1-element vectors. - template::type = 0> explicit constexpr fixed_array(value_type r1) noexcept + requires (N == 1) { elems[0] = r1; } - template && ...) >, - typename = std::enable_if_t< (sizeof...(ArgsT) == N && sizeof...(ArgsT) > 1) > - > + template constexpr fixed_array(ArgsT&&... r) noexcept - : elems{static_cast(std::forward< ArgsT >(r))...} + requires ((std::convertible_to && ...) && sizeof...(ArgsT) == N && sizeof...(ArgsT) > 1) + : elems{static_cast(std::forward(r))...} {} // iterator support diff --git a/Sofa/framework/Type/src/sofa/type/isRigidType.h b/Sofa/framework/Type/src/sofa/type/isRigidType.h index 41e17b5f9de..f43631703f9 100644 --- a/Sofa/framework/Type/src/sofa/type/isRigidType.h +++ b/Sofa/framework/Type/src/sofa/type/isRigidType.h @@ -1,31 +1,41 @@ -// -// Created by hugo on 28/11/23. -// - -#ifndef SOFA_ISRIGIDTYPE_H -#define SOFA_ISRIGIDTYPE_H +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once namespace sofa::type { - // Boiler-plate code to test if a type implements a method - // explanation https://stackoverflow.com/a/30848101 - - template - using void_t = void; - - // Primary template handles all types not supporting the operation. - template class, typename = void_t<>> - struct detect : std::false_type {}; - // Specialization recognizes/validates only types supporting the archetype. - template class Op> - struct detect>> : std::true_type {}; - - // Actual test if DataType::Coord implements getOrientation() (hence is a RigidType) - template - using isRigid_t = decltype(std::declval().getOrientation()); +/** + * A type T satisfies the isRigidType concept if: + * - T has a nested type named Coord. + * - An object of type T::Coord has a member function getOrientation that can be + * invoked without arguments. + * + * It allows to identify types such as StdRigidTypes and CudaRigidTypes at compile-time. + */ +template +concept isRigidType = requires +{ + std::declval().getOrientation(); +}; - template - using isRigidType = detect; } -#endif //SOFA_ISRIGIDTYPE_H diff --git a/Sofa/framework/Type/src/sofa/type/trait/Rebind.h b/Sofa/framework/Type/src/sofa/type/trait/Rebind.h index c462e08a1f4..994158d70b8 100644 --- a/Sofa/framework/Type/src/sofa/type/trait/Rebind.h +++ b/Sofa/framework/Type/src/sofa/type/trait/Rebind.h @@ -23,19 +23,18 @@ namespace sofa::type { - // primary template handles types that have no nested ::rebind_to member: - template< class T, class OtherType, class = void > - struct HasRebindTypedef : std::false_type { }; + template + concept CanTypeRebind = requires + { + typename T::template rebind_to; + }; - // specialization recognizes types that do have a nested ::rebind_to member: - template< class T, class OtherType > - struct HasRebindTypedef > > : std::true_type { }; /** * Depending on the type _T, has a public member typedef to. Otherwise, there is no member typedef (this is the * case of this implementation). */ - template + template struct Rebind {}; /** @@ -45,33 +44,20 @@ namespace sofa::type * \tparam _T Type that does have a nested ::rebind_to member */ template - struct Rebind<_T, _OtherType, std::enable_if_t::value > > + requires CanTypeRebind<_T, _OtherType> + struct Rebind<_T, _OtherType> { using to = typename _T::template rebind_to<_OtherType>; }; - template - inline constexpr auto deny = false; - - /** - * \brief Specialization for types that do NOT have a nested ::rebind_to member. In this implementation, Rebind has - * no public member typedef \ref to. If this implementation is chosen by the compiler (the number of template - * parameters is probably different from 1), a compilation error occurs. - * \tparam _T Type that does NOT have a nested ::rebind_to member - */ - template - struct Rebind<_T, _OtherType, std::enable_if_t::value > > - { - static_assert(deny<_T>, "_T must match _T"); - }; - /** * \brief Specialization for types that do NOT have a nested ::rebind_to member. In this implementation, Rebind has * a public member typedef \ref to. * \tparam _T Type that does NOT have a nested ::rebind_to member */ template class _T, class A, class _OtherType> - struct Rebind<_T, _OtherType, std::enable_if_t, _OtherType >::value > > + requires (!CanTypeRebind<_T, _OtherType>) + struct Rebind<_T, _OtherType> { using to = _T<_OtherType>; }; @@ -83,7 +69,7 @@ namespace sofa::type * 1) sofa::type::rebind_to< sofa::type::vector, float> is of type sofa::type::vector. In this example, * sofa::type::vector has a typedef rebind_to that will be used to deduce the type. * 2) sofa::type::rebind_to< sofa::type::Quat, double> is of type sofa::type::Quat. In this example, - * sofa::type::Quat does not have a typdef rebind_to. + * sofa::type::Quat does not have a typedef rebind_to. * 3) It makes no sense to use sofa::type::rebind on types having more than one template parameter, such as * sofa::type::fixed_array. A compilation error would occur. */ diff --git a/Sofa/framework/Type/src/sofa/type/trait/is_container.h b/Sofa/framework/Type/src/sofa/type/trait/is_container.h index 7ce8867ee55..52537fa767f 100644 --- a/Sofa/framework/Type/src/sofa/type/trait/is_container.h +++ b/Sofa/framework/Type/src/sofa/type/trait/is_container.h @@ -21,12 +21,17 @@ ******************************************************************************/ #pragma once #include +#include + +SOFA_HEADER_DEPRECATED_NOT_REPLACED("v25.06", "v25.12") + namespace sofa::type::trait { /// Detect if a type T has iterator/const iterator function. template +SOFA_ATTRIBUTE_DEPRECATED__IS_CONTAINER() struct is_container { typedef typename std::remove_const::type test_type; diff --git a/Sofa/framework/Type/src/sofa/type/trait/is_fixed_array.h b/Sofa/framework/Type/src/sofa/type/trait/is_fixed_array.h index 48a1e5166a1..f84787d514d 100644 --- a/Sofa/framework/Type/src/sofa/type/trait/is_fixed_array.h +++ b/Sofa/framework/Type/src/sofa/type/trait/is_fixed_array.h @@ -27,39 +27,17 @@ namespace sofa::type::trait /// Detect if a type T has iterator/const iterator function, operator[](size_t) and defines a static size template -struct is_fixed_array +concept is_fixed_array = requires(std::remove_cv_t t, const std::remove_cv_t ct) { - typedef typename std::remove_const::type test_type; + T::static_size; - template - static constexpr bool test( - A * pt, - A const * cpt = nullptr, - decltype(pt->begin()) * = nullptr, - decltype(pt->end()) * = nullptr, - decltype(cpt->begin()) * = nullptr, - decltype(cpt->end()) * = nullptr, - typename std::decay::type * = nullptr, ///< Is there an operator[] ? - decltype(A::static_size) * = nullptr, ///< fixed array containers define static_size - typename A::iterator * = nullptr, - typename A::const_iterator * = nullptr, - typename A::value_type * = nullptr) - { + {t.begin()} -> std::convertible_to; + {t.end()} -> std::convertible_to; - typedef typename A::iterator iterator; - typedef typename A::const_iterator const_iterator; - return std::is_samebegin()),iterator>::value - && std::is_sameend()),iterator>::value - && std::is_samebegin()),const_iterator>::value - && std::is_sameend()),const_iterator>::value; - } + {ct.begin()} -> std::convertible_to; + {ct.end()} -> std::convertible_to; - template - static constexpr bool test(...) { - return false; - } - - static const bool value = test(nullptr); + { t[0] } -> std::convertible_to; }; } diff --git a/Sofa/framework/Type/src/sofa/type/trait/is_vector.h b/Sofa/framework/Type/src/sofa/type/trait/is_vector.h index d2be28d54a9..bc7aa2c0861 100644 --- a/Sofa/framework/Type/src/sofa/type/trait/is_vector.h +++ b/Sofa/framework/Type/src/sofa/type/trait/is_vector.h @@ -27,38 +27,16 @@ namespace sofa::type::trait /// Detect if a type T has iterator/const iterator function, operator[](size_t) and is dynamically resizable (resize function) template -struct is_vector +concept is_vector = requires(std::remove_cv_t t, const std::remove_cv_t ct) { - typedef typename std::remove_const::type test_type; + {t.begin()} -> std::convertible_to; + {t.end()} -> std::convertible_to; - template - static constexpr bool test( - A * pt, - A const * cpt = nullptr, - decltype(pt->begin()) * = nullptr, - decltype(pt->end()) * = nullptr, - decltype(cpt->begin()) * = nullptr, - decltype(cpt->end()) * = nullptr, - typename std::decay::type * = nullptr, ///< Is there an operator[] ? - decltype(pt->resize(1)) * = nullptr, - typename A::iterator * = nullptr, - typename A::const_iterator * = nullptr, - typename A::value_type * = nullptr) { + {ct.begin()} -> std::convertible_to; + {ct.end()} -> std::convertible_to; - typedef typename A::iterator iterator; - typedef typename A::const_iterator const_iterator; - return std::is_samebegin()),iterator>::value - && std::is_sameend()),iterator>::value - && std::is_samebegin()),const_iterator>::value - && std::is_sameend()),const_iterator>::value; - } - - template - static constexpr bool test(...) { - return false; - } - - static const bool value = test(nullptr); + { t[0] } -> std::convertible_to; + t.resize(1); }; } diff --git a/Sofa/framework/Type/test/BoundingBox_test.cpp b/Sofa/framework/Type/test/BoundingBox_test.cpp new file mode 100644 index 00000000000..6b10e77db15 --- /dev/null +++ b/Sofa/framework/Type/test/BoundingBox_test.cpp @@ -0,0 +1,123 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +namespace sofa +{ + +using sofa::type::BoundingBox; +using sofa::type::Vec3; + +TEST(BoundingBoxTest, DefaultConstructor) +{ + static constexpr BoundingBox bbox; + EXPECT_TRUE(bbox.isNegligible()); // Default neutral box should be negligible +} + +TEST(BoundingBoxTest, ConstructorWithEndpoints) { + static constexpr Vec3 minVec(0.0, 0.0, 0.0); + static constexpr Vec3 maxVec(1.0, 1.0, 1.0); + static constexpr BoundingBox bbox(minVec, maxVec); + + EXPECT_EQ(bbox.minBBox(), minVec); + EXPECT_EQ(bbox.maxBBox(), maxVec); +} + +TEST(BoundingBoxTest, ConstructorWithLimits) { + static constexpr BoundingBox bbox(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); + EXPECT_EQ(bbox.minBBox(), Vec3(0.0, 0.0, 0.0)); + EXPECT_EQ(bbox.maxBBox(), Vec3(1.0, 1.0, 1.0)); +} + +TEST(BoundingBoxTest, NeutralBoundingBox) { + static constexpr auto neutral = BoundingBox::neutral_bbox(); + EXPECT_FALSE(neutral.isValid()); // Neutral bbox is invalid +} + +TEST(BoundingBoxTest, Invalidate) { + BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + bbox.invalidate(); + EXPECT_FALSE(bbox.isValid()); +} + +TEST(BoundingBoxTest, IsFlat) { + static constexpr BoundingBox flatBBox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 0.0)); + EXPECT_TRUE(flatBBox.isFlat()); + + static constexpr BoundingBox nonFlatBBox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + EXPECT_FALSE(nonFlatBBox.isFlat()); +} + +TEST(BoundingBoxTest, ContainsPoint) { + static constexpr BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + static constexpr Vec3 pointInside(0.5, 0.5, 0.5); + static constexpr Vec3 pointOutside(1.5, 1.5, 1.5); + + EXPECT_TRUE(bbox.contains(pointInside)); + EXPECT_FALSE(bbox.contains(pointOutside)); +} + +TEST(BoundingBoxTest, ContainsBoundingBox) { + static constexpr BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(2.0, 2.0, 2.0)); + static constexpr BoundingBox containedBBox(Vec3(0.5, 0.5, 0.5), Vec3(1.5, 1.5, 1.5)); + static constexpr BoundingBox outsideBBox(Vec3(2.5, 2.5, 2.5), Vec3(3.0, 3.0, 3.0)); + + EXPECT_TRUE(bbox.contains(containedBBox)); + EXPECT_FALSE(bbox.contains(outsideBBox)); +} + +TEST(BoundingBoxTest, Intersection) { + static constexpr BoundingBox bbox1(Vec3(0.0, 0.0, 0.0), Vec3(2.0, 2.0, 2.0)); + static constexpr BoundingBox bbox2(Vec3(1.0, 1.0, 1.0), Vec3(3.0, 3.0, 3.0)); + static constexpr BoundingBox expectedIntersection(Vec3(1.0, 1.0, 1.0), Vec3(2.0, 2.0, 2.0)); + + EXPECT_TRUE(bbox1.intersect(bbox2)); + EXPECT_EQ(bbox1.getIntersection(bbox2), expectedIntersection); +} + +TEST(BoundingBoxTest, Inflate) { + BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + bbox.inflate(1.0); + + EXPECT_EQ(bbox.minBBox(), Vec3(-1.0, -1.0, -1.0)); + EXPECT_EQ(bbox.maxBBox(), Vec3(2.0, 2.0, 2.0)); +} + +TEST(BoundingBoxTest, IncludePoint) { + BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + static constexpr Vec3 point(2.0, 2.0, 2.0); + bbox.include(point); + + EXPECT_EQ(bbox.maxBBox(), point); +} + +TEST(BoundingBoxTest, IncludeBoundingBox) { + BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0)); + static constexpr BoundingBox other(Vec3(-1.0, -1.0, -1.0), Vec3(2.0, 2.0, 2.0)); + bbox.include(other); + + EXPECT_EQ(bbox.minBBox(), other.minBBox()); + EXPECT_EQ(bbox.maxBBox(), other.maxBBox()); +} + +} diff --git a/Sofa/framework/Type/test/CMakeLists.txt b/Sofa/framework/Type/test/CMakeLists.txt index 84f70ddc9d4..7e9ba83bd72 100644 --- a/Sofa/framework/Type/test/CMakeLists.txt +++ b/Sofa/framework/Type/test/CMakeLists.txt @@ -3,10 +3,12 @@ cmake_minimum_required(VERSION 3.22) project(Sofa.Type_test) set(SOURCE_FILES + BoundingBox_test.cpp MatSym_test.cpp MatTypes_test.cpp Material_test.cpp Quater_test.cpp + Rebind_test.cpp RGBAColor_test.cpp StrongType_test.cpp SVector_test.cpp diff --git a/Sofa/framework/Type/test/MatSym_test.cpp b/Sofa/framework/Type/test/MatSym_test.cpp index f91f864460a..6e7926f3766 100644 --- a/Sofa/framework/Type/test/MatSym_test.cpp +++ b/Sofa/framework/Type/test/MatSym_test.cpp @@ -43,7 +43,7 @@ class MatSymTest : public testing::NumericTest using Real = typename ParameterPack::Real; static constexpr auto Size = ParameterPack::Size; - void onSetUp() override + void doSetUp() override { sofa::testing::LinearCongruentialRandomGenerator lcg(96547); diff --git a/Sofa/framework/Type/test/Quater_test.cpp b/Sofa/framework/Type/test/Quater_test.cpp index 7fdf2a0849b..408dfa53a01 100644 --- a/Sofa/framework/Type/test/Quater_test.cpp +++ b/Sofa/framework/Type/test/Quater_test.cpp @@ -707,4 +707,12 @@ TEST(QuaterTest, QuaterdFromUnitVectors) EXPECT_NEAR(0.5894552112230939, quat1[3], errorThreshold); } - +TEST(QuaterTest, StructuredBindings) +{ + Quat quat1; + const auto& [a,b,c,d] = quat1; + EXPECT_NEAR(0., a, errorThreshold); + EXPECT_NEAR(0., b, errorThreshold); + EXPECT_NEAR(0., c, errorThreshold); + EXPECT_NEAR(1., d, errorThreshold); +} diff --git a/Sofa/framework/Type/test/RGBAColor_test.cpp b/Sofa/framework/Type/test/RGBAColor_test.cpp index 1f4d37dc5b1..a31e3582a96 100644 --- a/Sofa/framework/Type/test/RGBAColor_test.cpp +++ b/Sofa/framework/Type/test/RGBAColor_test.cpp @@ -44,6 +44,7 @@ class Color_Test : public BaseTest, void checkStreamingOperator(const std::vector&) ; void checkDoubleStreamingOperator(const std::vector&) ; void testEnlight(); + void testStructuredBindings(); }; void Color_Test::testEnlight() @@ -54,6 +55,15 @@ void Color_Test::testEnlight() EXPECT_EQ( RGBAColor::lighten(RGBAColor::red(), 0.5), RGBAColor(1.0,0.5,0.5,1.0) ) ; } +void Color_Test::testStructuredBindings() +{ + const auto& [r, g, b, a] = RGBAColor::red(); + EXPECT_EQ(r, 1.); + EXPECT_EQ(g, 0.); + EXPECT_EQ(b, 0.); + EXPECT_EQ(a, 1.); +} + void Color_Test::checkCreateFromString() { EXPECT_EQ( RGBAColor::fromString("white"), RGBAColor(1.0,1.0,1.0,1.0) ) ; @@ -277,6 +287,11 @@ TEST_F(Color_Test, checkEnlight) this->testEnlight() ; } +TEST_F(Color_Test, testStructuredBindings) +{ + this->testStructuredBindings(); +} + std::vector> testvalues = { {" 0 0 0 0","0 0 0 0", "S"}, diff --git a/Sofa/framework/Type/test/Rebind_test.cpp b/Sofa/framework/Type/test/Rebind_test.cpp new file mode 100644 index 00000000000..5ef91da5aea --- /dev/null +++ b/Sofa/framework/Type/test/Rebind_test.cpp @@ -0,0 +1,59 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +static_assert(sofa::type::CanTypeRebind, int>); +static_assert(sofa::type::CanTypeRebind, int>); + +static_assert( + std::is_same_v< + sofa::type::rebind_to, int>, + sofa::type::vector + >); +static_assert( + std::is_same_v< + sofa::type::rebind_to, int>, + sofa::type::vector + >); + +template +struct DummyNoRebind{}; + +static_assert(!sofa::type::CanTypeRebind, int>); + +static_assert( + std::is_same_v< + sofa::type::rebind_to, int>, + DummyNoRebind + >); + +template +struct DummyWithConstraintRebind +{ + template + requires std::is_integral_v + using rebind_to = U; +}; + +static_assert(sofa::type::CanTypeRebind, int>); +static_assert(!sofa::type::CanTypeRebind, std::string>); diff --git a/Sofa/framework/Type/test/StrongType_test.cpp b/Sofa/framework/Type/test/StrongType_test.cpp index 767813b0baa..e18426be54e 100644 --- a/Sofa/framework/Type/test/StrongType_test.cpp +++ b/Sofa/framework/Type/test/StrongType_test.cpp @@ -31,6 +31,7 @@ TEST(StrongType, constructor) // myint a; //this is not possible as the default constructor is explicit constexpr myint a ( 2 ); + EXPECT_EQ(a.get(), 2); } TEST(StrongType, preIncrementable) diff --git a/Sofa/framework/Type/test/VecTypes_test.cpp b/Sofa/framework/Type/test/VecTypes_test.cpp index a4f10dab1ab..ed3460a56ce 100644 --- a/Sofa/framework/Type/test/VecTypes_test.cpp +++ b/Sofa/framework/Type/test/VecTypes_test.cpp @@ -23,4 +23,11 @@ #include #include - +TEST(VecTest, StructuredBindings) +{ + constexpr sofa::type::Vec3 vec { 1.0, 2.0, 3.0 }; + const auto& [a, b, c] = vec; + EXPECT_EQ(a, 1.); + EXPECT_EQ(b, 2.); + EXPECT_EQ(c, 3.); +} diff --git a/Sofa/framework/Type/test/vector_test.cpp b/Sofa/framework/Type/test/vector_test.cpp index 11fa007a3a7..4322c605587 100644 --- a/Sofa/framework/Type/test/vector_test.cpp +++ b/Sofa/framework/Type/test/vector_test.cpp @@ -49,7 +49,7 @@ class vector_test : public NumericTest<>, void checkVector(const std::vector& params) ; void checkVectorAccessFailure() const; - void checkRebind(); + void checkRebind() const; }; template @@ -103,14 +103,18 @@ void vector_test::checkVectorAccessFailure() const } template -void vector_test::checkRebind() +void vector_test::checkRebind() const { - constexpr bool hasRebind = sofa::type::HasRebindTypedef, int>::value; + constexpr bool hasRebind = sofa::type::CanTypeRebind, int>; + static_assert(hasRebind); EXPECT_TRUE(hasRebind); - using rebinded = typename sofa::type::Rebind, int >::to; - using vec_int = vector; - constexpr bool isRebindOK = std::is_same_v; - EXPECT_TRUE(isRebindOK); + if constexpr (hasRebind) + { + using rebinded = typename sofa::type::Rebind, int >::to; + using vec_int = vector; + constexpr bool isRebindOK = std::is_same_v; + EXPECT_TRUE(isRebindOK); + } } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/applications/plugins/CImgPlugin/CImgPlugin_test/ImageCImg_test.cpp b/applications/plugins/CImgPlugin/CImgPlugin_test/ImageCImg_test.cpp index f830e0834de..20b2be44f5a 100644 --- a/applications/plugins/CImgPlugin/CImgPlugin_test/ImageCImg_test.cpp +++ b/applications/plugins/CImgPlugin/CImgPlugin_test/ImageCImg_test.cpp @@ -42,11 +42,11 @@ class ImageCImg_test : public BaseTest } - void SetUp() override + void doSetUp() override { sofa::helper::system::DataRepository.addFirstPath(CIMGPLUGIN_RESOURCES_DIR); } - void TearDown() override + void doTearDown() override { sofa::helper::system::DataRepository.removePath(CIMGPLUGIN_RESOURCES_DIR); } diff --git a/applications/plugins/CMakeLists.txt b/applications/plugins/CMakeLists.txt index cfd74c7f771..56af63924fc 100644 --- a/applications/plugins/CMakeLists.txt +++ b/applications/plugins/CMakeLists.txt @@ -25,7 +25,6 @@ sofa_add_subdirectory(directory SofaPython3 SofaPython3 EXTERNAL GIT_REF master) sofa_add_subdirectory(plugin CGALPlugin CGALPlugin EXTERNAL GIT_REF master) # Depends on image sofa_add_subdirectory(plugin Registration Registration EXTERNAL GIT_REF master) # Depends on image, SofaPython, SofaGui and SofaDistanceGrid sofa_add_subdirectory(plugin BulletCollisionDetection BulletCollisionDetection) # Depends on Compliant and LMConstraint -sofa_add_subdirectory(plugin InvertibleFVM InvertibleFVM EXTERNAL GIT_REF master) sofa_add_subdirectory(plugin MeshSTEPLoader MeshSTEPLoader EXTERNAL GIT_REF master) sofa_add_subdirectory(plugin PluginExample PluginExample EXTERNAL GIT_REF master) sofa_add_subdirectory(plugin ManifoldTopologies ManifoldTopologies EXTERNAL GIT_REF master) @@ -35,7 +34,6 @@ sofa_add_subdirectory(plugin Xitact Xitact) sofa_add_subdirectory(plugin Haption Haption) sofa_add_subdirectory(plugin PersistentContact PersistentContact) sofa_add_subdirectory(plugin Sensable Sensable) -sofa_add_subdirectory(plugin SensableEmulation SensableEmulation) sofa_add_subdirectory(plugin SofaHAPI SofaHAPI) sofa_add_subdirectory(plugin SofaCarving SofaCarving) sofa_add_subdirectory(plugin LeapMotion LeapMotion) @@ -66,10 +64,9 @@ sofa_add_subdirectory(plugin SofaCUDA SofaCUDA) sofa_find_package(Sofa.GL QUIET) if(Sofa.GL_FOUND) - sofa_add_subdirectory(plugin SofaSimpleGUI SofaSimpleGUI) # SofaSimpleGUI plugin can't work without OPENGL sofa_add_subdirectory(plugin VolumetricRendering VolumetricRendering) # VolumetricRendering plugin can't work without OPENGL else() - message("Sofa.GL not found; disabling SofaSimpleGUI and VolumetricRendering plugins") + message("Sofa.GL not found; disabling VolumetricRendering plugin") endif() sofa_add_subdirectory(plugin SofaDistanceGrid SofaDistanceGrid) # Also defines SofaDistanceGrid.CUDA diff --git a/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/CapsuleContact.cpp b/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/CapsuleContact.cpp index e667cbfc1c5..29eb62b3706 100644 --- a/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/CapsuleContact.cpp +++ b/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/CapsuleContact.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace sofa::core::collision; @@ -79,6 +80,18 @@ template class COLLISIONOBBCAPSULE_API BarycentricPenalityContact, CapsuleCollisionModel>; template class COLLISIONOBBCAPSULE_API BarycentricPenalityContact, CylinderCollisionModel>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, CapsuleCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, TriangleCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, SphereCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, RigidSphereModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, CapsuleCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, CapsuleCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, TriangleCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, SphereCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, RigidSphereModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, OBBCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API BaseUnilateralContactResponse, OBBCollisionModel, sofa::component::constraint::lagrangian::model::UnilateralLagrangianContactParameters>; + template class COLLISIONOBBCAPSULE_API FrictionContact, CapsuleCollisionModel>; template class COLLISIONOBBCAPSULE_API FrictionContact, TriangleCollisionModel>; template class COLLISIONOBBCAPSULE_API FrictionContact, SphereCollisionModel>; diff --git a/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/OBBContact.cpp b/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/OBBContact.cpp index fe3f0a79efd..15fcd595c99 100644 --- a/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/OBBContact.cpp +++ b/applications/plugins/CollisionOBBCapsule/src/CollisionOBBCapsule/response/contact/OBBContact.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,12 @@ template class COLLISIONOBBCAPSULE_API response::contact::BarycentricPenalityCon template class COLLISIONOBBCAPSULE_API response::contact::BarycentricPenalityContact, OBBCollisionModel>; template class COLLISIONOBBCAPSULE_API response::contact::BarycentricPenalityContact, OBBCollisionModel>; + +template class COLLISIONOBBCAPSULE_API response::contact::BaseUnilateralContactResponse, OBBCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API response::contact::BaseUnilateralContactResponse, OBBCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API response::contact::BaseUnilateralContactResponse, OBBCollisionModel,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; +template class COLLISIONOBBCAPSULE_API response::contact::BaseUnilateralContactResponse,constraint::lagrangian::model::UnilateralLagrangianContactParameters>; + template class COLLISIONOBBCAPSULE_API response::contact::FrictionContact, OBBCollisionModel>; template class COLLISIONOBBCAPSULE_API response::contact::FrictionContact, OBBCollisionModel>; template class COLLISIONOBBCAPSULE_API response::contact::FrictionContact, OBBCollisionModel>; diff --git a/applications/plugins/InvertibleFVM/ExternalProjectConfig.cmake.in b/applications/plugins/InvertibleFVM/ExternalProjectConfig.cmake.in deleted file mode 100644 index 3ae32c83c66..00000000000 --- a/applications/plugins/InvertibleFVM/ExternalProjectConfig.cmake.in +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.22) - -include(ExternalProject) -ExternalProject_Add(InvertibleFVM - GIT_REPOSITORY https://github.com/sofa-framework/InvertibleFVM - GIT_TAG origin/@ARG_GIT_REF@ - SOURCE_DIR "${CMAKE_SOURCE_DIR}/applications/plugins/InvertibleFVM" - BINARY_DIR "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" - GIT_CONFIG "remote.origin.fetch=+refs/pull/*:refs/remotes/origin/pr/*" -) diff --git a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.cpp b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.cpp index 1a7e71ce619..dbe0d4f11cf 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/DataExchange.cpp @@ -33,25 +33,25 @@ namespace sofa::core SOFA_EVENT_CPP(DataExchangeEvent) -// Register in the Factory -int DataExchangeClass = core::RegisterObject("DataExchange") -.add< DataExchange< sofa::type::vector > >(true) -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::Vec3d > >() -.add< DataExchange< double > >() - -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::Vec3f > >() -.add< DataExchange< float > >() +void registerDataExchange(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Component for data memory sharing in the context of multi-threading applications") + .add< DataExchange< sofa::type::vector > >(true) + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::Vec3d > >() + .add< DataExchange< double > >() -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< sofa::type::vector > >() -.add< DataExchange< bool > >() -; + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::Vec3f > >() + .add< DataExchange< float > >() + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< sofa::type::vector > >() + .add< DataExchange< bool > >()); +} template class SOFA_MULTITHREADING_PLUGIN_API DataExchange< sofa::type::vector >; template class SOFA_MULTITHREADING_PLUGIN_API DataExchange< sofa::type::vector >; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/MeanComputation.cpp b/applications/plugins/MultiThreading/src/MultiThreading/MeanComputation.cpp index 4fb6c374091..3d4fcbac040 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/MeanComputation.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/MeanComputation.cpp @@ -29,13 +29,15 @@ namespace sofa::component::engine { -int MeanComputationEngineClass = core::RegisterObject("Compute the mean of the input elements") - .add< MeanComputation >(true) // default template - .add< MeanComputation >() - .add< MeanComputation >() - .add< MeanComputation >() - .add< MeanComputation >() - ; +void registerMeanComputationEngine(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Compute the mean of the input elements.") + .add< MeanComputation >(true) // default template + .add< MeanComputation >() + .add< MeanComputation >() + .add< MeanComputation >() + .add< MeanComputation >()); +} template class SOFA_MULTITHREADING_PLUGIN_API MeanComputation< defaulttype::Vec3Types >; template class SOFA_MULTITHREADING_PLUGIN_API MeanComputation< defaulttype::Vec1Types >; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.cpp index 1698d38bc96..636f04472d5 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.cpp @@ -39,9 +39,11 @@ namespace multithreading::component::animationloop { -int AnimationLoopParallelSchedulerClass = sofa::core::RegisterObject("parallel animation loop, using intel tbb library") - .add< AnimationLoopParallelScheduler >() - ; +void registerAnimationLoopParallelScheduler(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel animation loop, using the Intel tbb library.") + .add< AnimationLoopParallelScheduler >()); +} AnimationLoopParallelScheduler::AnimationLoopParallelScheduler(sofa::simulation::Node* _gnode) : Inherit() diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBVHNarrowPhase.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBVHNarrowPhase.cpp index 3cf5782a58d..3c1a0a06af7 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBVHNarrowPhase.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBVHNarrowPhase.cpp @@ -36,13 +36,14 @@ namespace multithreading::component::collision::detection::algorithm const bool isParallelBVHNarrowPhaseImplementationRegistered = multithreading::ParallelImplementationsRegistry::addEquivalentImplementations("BVHNarrowPhase", "ParallelBVHNarrowPhase"); +void registerParallelBVHNarrowPhase(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel version of the narrow phase collision detection based on boundary volume hierarchy.") + .add< ParallelBVHNarrowPhase >()); +} using sofa::helper::ScopedAdvancedTimer; -int ParallelBVHNarrowPhaseClass = sofa::core::RegisterObject("Narrow phase collision detection based on boundary volume hierarchy") - .add< ParallelBVHNarrowPhase >() -; - ParallelBVHNarrowPhase::ParallelBVHNarrowPhase() {} @@ -131,22 +132,10 @@ void ParallelBVHNarrowPhase::initializeTopology(sofa::core::topology::BaseMeshTo auto insertionIt = m_initializedTopology.insert(topology); if (insertionIt.second) { - // The following calls force the creation of some topology arrays before the concurrent computing. - // Those arrays cannot be created on the fly, in a concurrent environment, + // We need to make sure all topology buffers are well created. + // Those arrays cannot be created on the fly later, in a concurrent environment, // due to possible race conditions. - // Depending on the scene graph, it is possible that those calls are not enough. - if (topology->getNbPoints()) - { - topology->getTrianglesAroundVertex(0); - } - if (topology->getNbTriangles()) - { - topology->getEdgesInTriangle(0); - } - if (topology->getNbEdges()) - { - topology->getTrianglesAroundEdge(0); - } + topology->computeCrossElementBuffers(); } } diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBruteForceBroadPhase.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBruteForceBroadPhase.cpp index 72cf9d8b848..242d543a303 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBruteForceBroadPhase.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/collision/detection/algorithm/ParallelBruteForceBroadPhase.cpp @@ -34,11 +34,13 @@ namespace multithreading::component::collision::detection::algorithm const bool isParallelParallelBruteForceBroadPhaseImplementationRegistered = multithreading::ParallelImplementationsRegistry::addEquivalentImplementations("BruteForceBroadPhase", "ParallelBruteForceBroadPhase"); -using sofa::helper::ScopedAdvancedTimer; +void registerParallelBruteForceBroadPhase(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel version of the collision detection using extensive pair-wise tests performed concurrently.") + .add< ParallelBruteForceBroadPhase >()); +} -int ParallelBruteForceBroadPhaseClass = sofa::core::RegisterObject("Collision detection using extensive pair-wise tests performed in parallel") - .add< ParallelBruteForceBroadPhase >() -; +using sofa::helper::ScopedAdvancedTimer; ParallelBruteForceBroadPhase::ParallelBruteForceBroadPhase() : BruteForceBroadPhase() diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/linearsolver/iterative/ParallelCGLinearSolver.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/linearsolver/iterative/ParallelCGLinearSolver.cpp index 22cd5f3569b..5838bb7295c 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/linearsolver/iterative/ParallelCGLinearSolver.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/linearsolver/iterative/ParallelCGLinearSolver.cpp @@ -1,4 +1,4 @@ -/****************************************************************************** +/****************************************************************************** * SOFA, Simulation Open-Framework Architecture * * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * * * @@ -59,9 +59,12 @@ ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical, sofa template class SOFA_MULTITHREADING_PLUGIN_API ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical>, sofa::linearalgebra::FullVector >; -int ParallelCGLinearSolverClass = sofa::core::RegisterObject("Linear system solver using the conjugate gradient iterative algorithm in parallel") - .add< ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical, sofa::linearalgebra::FullVector > >(true) - .add< ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical>, sofa::linearalgebra::FullVector > >(); +void registerParallelCGLinearSolver(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel version of the linear solver using the conjugate gradient iterative algorithm.") + .add< ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical, sofa::linearalgebra::FullVector > >(true) + .add< ParallelCGLinearSolver< ParallelCompressedRowSparseMatrixMechanical>, sofa::linearalgebra::FullVector > >()); +} const bool isParallelCGLinearSolverImplementationRegistered = ParallelImplementationsRegistry::addEquivalentImplementations("CGLinearSolver", "ParallelCGLinearSolver"); diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/mapping/linear/BeamLinearMapping_mt.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/mapping/linear/BeamLinearMapping_mt.cpp index dbd167d2989..20013a22c14 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/mapping/linear/BeamLinearMapping_mt.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/mapping/linear/BeamLinearMapping_mt.cpp @@ -32,11 +32,11 @@ namespace multithreading::component::mapping::linear const bool isBeamLinearMapping_mtImplementationRegistered = multithreading::ParallelImplementationsRegistry::addEquivalentImplementations("BeamLinearMapping", "BeamLinearMapping_mt"); -//using namespace defaulttype; -// Register in the Factory -int BeamLinearMapping_mtClass = sofa::core::RegisterObject("Set the positions and velocities of points attached to a beam using linear interpolation between DOFs") - .add< BeamLinearMapping_mt< Rigid3Types, Vec3Types > >() - ; +void registerBeamLinearMapping_mt(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Set the positions and velocities of points attached to a beam using linear interpolation between DOFs.") + .add< BeamLinearMapping_mt< Rigid3Types, Vec3Types > >()); +} template class BeamLinearMapping_mt< Rigid3Types, Vec3Types >; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelHexahedronFEMForceField.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelHexahedronFEMForceField.cpp index e8f55a188f7..e1d5b7c737a 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelHexahedronFEMForceField.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelHexahedronFEMForceField.cpp @@ -29,14 +29,16 @@ namespace multithreading::component::forcefield::solidmechanics::fem::elastic { +using namespace sofa::defaulttype; + const bool isParallelHexahedronFEMForceFieldImplementationRegistered = multithreading::ParallelImplementationsRegistry::addEquivalentImplementations("HexahedronFEMForceField", "ParallelHexahedronFEMForceField"); -using namespace sofa::defaulttype; - -// Register in the Factory -int ParallelHexahedronFEMForceFieldClass = sofa::core::RegisterObject("Parallel hexahedral finite elements") - .add < ParallelHexahedronFEMForceField < Vec3Types > > (); +void registerParallelHexahedronFEMForceField(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel implementation of a linear elastic material using hexahedral finite elements.") + .add < ParallelHexahedronFEMForceField < Vec3Types > > ()); +} template class SOFA_MULTITHREADING_PLUGIN_API ParallelHexahedronFEMForceField; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.cpp index bf73f5b1fa1..cc0d876f5fa 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.cpp @@ -26,7 +26,7 @@ #include -namespace multithreading::component::solidmechanics::fem::elastic +namespace multithreading::component::forcefield::solidmechanics::fem::elastic { using namespace sofa::defaulttype; @@ -34,9 +34,11 @@ using namespace sofa::defaulttype; const bool isParallelTetrahedronFEMForceFieldImplementationRegistered = multithreading::ParallelImplementationsRegistry::addEquivalentImplementations("TetrahedronFEMForceField", "ParallelTetrahedronFEMForceField"); -// Register in the Factory -int ParallelTetrahedronFEMForceFieldClass = sofa::core::RegisterObject("Parallel tetrahedral finite elements") - .add < ParallelTetrahedronFEMForceField < Vec3Types > > (); +void registerParallelTetrahedronFEMForceField(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel implementation of a linear elastic material using tetrahedral finite elements..") + .add < ParallelTetrahedronFEMForceField < Vec3Types > > ()); +} template class SOFA_MULTITHREADING_PLUGIN_API ParallelTetrahedronFEMForceField; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.h b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.h index 0e9cb332cbd..be6a9186b19 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.h +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.h @@ -30,7 +30,7 @@ #include -namespace multithreading::component::solidmechanics::fem::elastic +namespace multithreading::component::forcefield::solidmechanics::fem::elastic { /** diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.inl b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.inl index e144a95b764..f2f620b5505 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.inl +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/fem/elastic/ParallelTetrahedronFEMForceField.inl @@ -27,7 +27,7 @@ #include #include -namespace multithreading::component::solidmechanics::fem::elastic +namespace multithreading::component::forcefield::solidmechanics::fem::elastic { template diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelMeshSpringForceField.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelMeshSpringForceField.cpp index dcfd24c396a..132a645626e 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelMeshSpringForceField.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelMeshSpringForceField.cpp @@ -25,10 +25,13 @@ namespace multithreading::component::solidmechanics::spring { -int ParallelMeshSpringForceFieldClass = sofa::core::RegisterObject("Parallel stiff springs acting along the edges of a mesh") - .add< ParallelMeshSpringForceField >() - .add< ParallelMeshSpringForceField >() - .add< ParallelMeshSpringForceField >(); +void registerParallelMeshSpringForceField(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel stiff springs acting along the edges of a mesh.") + .add< ParallelMeshSpringForceField >() + .add< ParallelMeshSpringForceField >() + .add< ParallelMeshSpringForceField >()); +} template class SOFA_MULTITHREADING_PLUGIN_API ParallelMeshSpringForceField; template class SOFA_MULTITHREADING_PLUGIN_API ParallelMeshSpringForceField; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelSpringForceField.cpp b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelSpringForceField.cpp index 6c2b2d858b0..682b67ae414 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelSpringForceField.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/solidmechanics/spring/ParallelSpringForceField.cpp @@ -25,12 +25,15 @@ namespace multithreading::component::solidmechanics::spring { -int ParallelSpringForceFieldClass = sofa::core::RegisterObject("Parallel stiff springs") - .add< ParallelSpringForceField >() - .add< ParallelSpringForceField >() - .add< ParallelSpringForceField >() - .add< ParallelSpringForceField >() - .add< ParallelSpringForceField >(); +void registerParallelSpringForceField(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData("Parallel stiff springs.") + .add< ParallelSpringForceField >() + .add< ParallelSpringForceField >() + .add< ParallelSpringForceField >() + .add< ParallelSpringForceField >() + .add< ParallelSpringForceField >()); +} template class SOFA_MULTITHREADING_PLUGIN_API ParallelSpringForceField; template class SOFA_MULTITHREADING_PLUGIN_API ParallelSpringForceField; diff --git a/applications/plugins/MultiThreading/src/MultiThreading/config.h.in b/applications/plugins/MultiThreading/src/MultiThreading/config.h.in index e00cd0f836f..8b2f185328b 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/config.h.in +++ b/applications/plugins/MultiThreading/src/MultiThreading/config.h.in @@ -19,8 +19,7 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#ifndef MULTITHREADING_CONFIG_H -#define MULTITHREADING_CONFIG_H +#pragma once #include @@ -31,7 +30,11 @@ # define SOFA_MULTITHREADING_PLUGIN_API SOFA_IMPORT_DYNAMIC_LIBRARY #endif -#endif +namespace multithreading +{ + constexpr const char* MODULE_NAME = "@PROJECT_NAME@"; + constexpr const char* MODULE_VERSION = "@PROJECT_VERSION@"; +} // namespace multithreading #ifdef SOFA_BUILD_MULTITHREADING #define SOFA_ATTRIBUTE_DISABLED__TASKSCHEDULERUSER_DATANAME(msg) diff --git a/applications/plugins/MultiThreading/src/MultiThreading/initMultiThreading.cpp b/applications/plugins/MultiThreading/src/MultiThreading/initMultiThreading.cpp index d14bb740f10..853e1ddfc68 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/initMultiThreading.cpp +++ b/applications/plugins/MultiThreading/src/MultiThreading/initMultiThreading.cpp @@ -24,16 +24,63 @@ #include +#include +#include + +namespace sofa::core +{ +extern void registerDataExchange(sofa::core::ObjectFactory* factory); +} + +namespace sofa::component::engine +{ +extern void registerMeanComputationEngine(sofa::core::ObjectFactory* factory); +} + namespace multithreading { +namespace component::animationloop +{ +extern void registerAnimationLoopParallelScheduler(sofa::core::ObjectFactory* factory); +} + +namespace component::collision::detection::algorithm +{ +extern void registerParallelBVHNarrowPhase(sofa::core::ObjectFactory* factory); +extern void registerParallelBruteForceBroadPhase(sofa::core::ObjectFactory* factory); +} + +namespace component::linearsolver::iterative +{ +extern void registerParallelCGLinearSolver(sofa::core::ObjectFactory* factory); +} + +namespace component::mapping::linear +{ +extern void registerBeamLinearMapping_mt(sofa::core::ObjectFactory* factory); +} + +namespace component::forcefield::solidmechanics::fem::elastic +{ +extern void registerParallelHexahedronFEMForceField(sofa::core::ObjectFactory* factory); +extern void registerParallelTetrahedronFEMForceField(sofa::core::ObjectFactory* factory); +} + +namespace component::solidmechanics::spring +{ +extern void registerParallelMeshSpringForceField(sofa::core::ObjectFactory* factory); +extern void registerParallelSpringForceField(sofa::core::ObjectFactory* factory); +} + extern "C" { SOFA_MULTITHREADING_PLUGIN_API void initExternalModule(); SOFA_MULTITHREADING_PLUGIN_API const char* getModuleName(); SOFA_MULTITHREADING_PLUGIN_API const char* getModuleVersion(); SOFA_MULTITHREADING_PLUGIN_API const char* getModuleLicense(); SOFA_MULTITHREADING_PLUGIN_API const char* getModuleDescription(); +SOFA_MULTITHREADING_PLUGIN_API void registerObjects(sofa::core::ObjectFactory* factory); } void init() @@ -41,6 +88,9 @@ void init() static bool first = true; if (first) { + // make sure that this plugin is registered into the PluginManager + sofa::helper::system::PluginManager::getInstance().registerPlugin(MODULE_NAME); + sofa::component::linearsolver::iterative::init(); first = false; } @@ -53,12 +103,12 @@ void initExternalModule() const char* getModuleName() { - return "MultiThreading"; + return MODULE_NAME; } const char* getModuleVersion() { - return "1.0"; + return MODULE_VERSION; } const char* getModuleLicense() @@ -71,4 +121,20 @@ const char* getModuleDescription() return "MultiThreading SOFA Framework"; } +void registerObjects(sofa::core::ObjectFactory* factory) +{ + sofa::core::registerDataExchange(factory); + sofa::component::engine::registerMeanComputationEngine(factory); + multithreading::component::animationloop::registerAnimationLoopParallelScheduler(factory); + multithreading::component::collision::detection::algorithm::registerParallelBVHNarrowPhase(factory); + multithreading::component::collision::detection::algorithm::registerParallelBruteForceBroadPhase(factory); + multithreading::component::linearsolver::iterative::registerParallelCGLinearSolver(factory); + multithreading::component::mapping::linear::registerBeamLinearMapping_mt(factory); + multithreading::component::forcefield::solidmechanics::fem::elastic::registerParallelHexahedronFEMForceField(factory); + multithreading::component::forcefield::solidmechanics::fem::elastic::registerParallelTetrahedronFEMForceField(factory); + multithreading::component::solidmechanics::spring::registerParallelMeshSpringForceField(factory); + multithreading::component::solidmechanics::spring::registerParallelSpringForceField(factory); + +} + } diff --git a/applications/plugins/MultiThreading/test/ParallelImplementationsRegistry_test.cpp b/applications/plugins/MultiThreading/test/ParallelImplementationsRegistry_test.cpp index e93fcf403df..6bb03c78cdf 100644 --- a/applications/plugins/MultiThreading/test/ParallelImplementationsRegistry_test.cpp +++ b/applications/plugins/MultiThreading/test/ParallelImplementationsRegistry_test.cpp @@ -1,4 +1,4 @@ -/****************************************************************************** +/****************************************************************************** * SOFA, Simulation Open-Framework Architecture * * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * * * @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -32,10 +33,11 @@ namespace multithreading TEST(ParallelImplementationsRegistry, existInObjectFactory) { // sequential versions will be added to the ObjectFactory - sofa::simpleapi::importPlugin("Sofa.Component.LinearSolver.Iterative"); - sofa::simpleapi::importPlugin("Sofa.Component.Collision.Detection.Algorithm"); - sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.FEM.Elastic"); - sofa::simpleapi::importPlugin("Sofa.Component.Mapping.Linear"); + sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); + sofa::simpleapi::importPlugin(Sofa.Component.Collision.Detection.Algorithm); + sofa::simpleapi::importPlugin(Sofa.Component.SolidMechanics.FEM.Elastic); + sofa::simpleapi::importPlugin(Sofa.Component.Mapping.Linear); + sofa::simpleapi::importPlugin("MultiThreading"); const auto implementations = ParallelImplementationsRegistry::getImplementations(); diff --git a/applications/plugins/SceneCreator/SceneCreator_test/SceneCreator_test.cpp b/applications/plugins/SceneCreator/SceneCreator_test/SceneCreator_test.cpp index 4168eec9f92..5fc3bdbb1ab 100644 --- a/applications/plugins/SceneCreator/SceneCreator_test/SceneCreator_test.cpp +++ b/applications/plugins/SceneCreator/SceneCreator_test/SceneCreator_test.cpp @@ -58,10 +58,10 @@ using sofa::simulation::Node; class SceneCreator_test : public BaseSimulationTest { public: - void SetUp() override + void doSetUp() override { - sofa::simpleapi::importPlugin("Sofa.Component"); - sofa::simpleapi::importPlugin("Sofa.GL.Component.Rendering3D"); + sofa::simpleapi::importPlugin(Sofa.Component); + sofa::simpleapi::importPlugin(Sofa.GL.Component.Rendering3D); } bool createCubeFailed(); diff --git a/applications/plugins/SceneCreator/src/SceneCreator/SceneCreator.cpp b/applications/plugins/SceneCreator/src/SceneCreator/SceneCreator.cpp index e1519db54d7..943f28fbb1c 100644 --- a/applications/plugins/SceneCreator/src/SceneCreator/SceneCreator.cpp +++ b/applications/plugins/SceneCreator/src/SceneCreator/SceneCreator.cpp @@ -21,6 +21,7 @@ ******************************************************************************/ #include "SceneCreator.h" #include +#include #include #include @@ -87,15 +88,15 @@ Node::SPtr createEulerSolverNode(Node::SPtr parent, const std::string& name, co if (scheme == "Explicit") { - simpleapi::createObject(parent, "RequiredPlugin", {{"name", "Sofa.Component.ODESolver.Forward"}}); + simpleapi::createObject(parent, "RequiredPlugin", {{"name", Sofa.Component.ODESolver.Forward}}); simpleapi::createObject(node, "EulerExplicitSolver", {{"name","Euler Explicit"}}); return node ; } if (scheme == "Implicit") { - simpleapi::createObject(parent, "RequiredPlugin", {{"name", "Sofa.Component.ODESolver.Backward"}}); - simpleapi::createObject(parent, "RequiredPlugin", {{"name", "Sofa.Component.LinearSolver.Iterative"}}); + simpleapi::createObject(parent, "RequiredPlugin", {{"name", Sofa.Component.ODESolver.Backward}}); + simpleapi::createObject(parent, "RequiredPlugin", {{"name", Sofa.Component.LinearSolver.Iterative}}); simpleapi::createObject(node, "EulerImplicitSolver", {{"name","Euler Implicit"}, {"rayleighStiffness","0.01"}, {"rayleighMass", "1.0"}}) ; @@ -109,8 +110,8 @@ Node::SPtr createEulerSolverNode(Node::SPtr parent, const std::string& name, co if (scheme == "Implicit_SparseLDL") { - simpleapi::createObject(parent, "RequiredPlugin", {{"name", "Sofa.Component.ODESolver.Backward"}}); - simpleapi::createObject(parent, "RequiredPlugin", {{"name", "Sofa.Component.LinearSolver.Direct"}}); + simpleapi::createObject(parent, "RequiredPlugin", {{"name", Sofa.Component.ODESolver.Backward}}); + simpleapi::createObject(parent, "RequiredPlugin", {{"name", Sofa.Component.LinearSolver.Direct}}); simpleapi::createObject(node, "EulerImplicitSolver", {{"name","Euler Implicit"}, {"rayleighStiffness","0.01"}, {"rayleighMass", "1.0"}}) ; diff --git a/applications/plugins/SensableEmulation/CMakeLists.txt b/applications/plugins/SensableEmulation/CMakeLists.txt deleted file mode 100644 index 33002d04038..00000000000 --- a/applications/plugins/SensableEmulation/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -cmake_minimum_required(VERSION 3.22) -project(SensableEmulation) - - -set(HEADER_FILES - OmniDriverEmu.h - config.h -) - -set(SOURCE_FILES - OmniDriverEmu.cpp - initSensableEmulation.cpp -) - -set(README_FILES PluginSensableEmulation.txt) - -find_package(Sofa.Config REQUIRED) -sofa_find_package(Sofa.Component.Haptics REQUIRED) -sofa_find_package(Sofa.Component.Controller REQUIRED) -sofa_find_package(Sofa.GL.Component.Rendering3D REQUIRED) -sofa_find_package(Boost COMPONENTS thread REQUIRED) - -include_directories(${Boost_INCLUDE_DIRS}) - -add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES} ${README_FILES}) -set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-DSOFA_BUILD_SENSABLEEMULATIONPLUGIN") -target_link_libraries(${PROJECT_NAME} Sofa.Component.Haptics Sofa.Component.Controller Sofa.GL.Component.Rendering3D Boost::thread) - -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/..") - -# Seems to be required by boost::asio -if(UNIX) - target_link_libraries(${PROJECT_NAME} pthread) -endif() - -install(TARGETS ${PROJECT_NAME} - COMPONENT SensableEmulation_libraries - EXPORT SensableEmulationTargets - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - -install(DIRECTORY examples/ DESTINATION share/sofa/plugins/${PROJECT_NAME}) diff --git a/applications/plugins/SensableEmulation/NewOmniDriverEmu.cpp b/applications/plugins/SensableEmulation/NewOmniDriverEmu.cpp deleted file mode 100644 index 95c5d1065b5..00000000000 --- a/applications/plugins/SensableEmulation/NewOmniDriverEmu.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "NewOmniDriverEmu.h" - -#include -#include -#include -// -////force feedback -#include -#include -// -#include -#include - -#include -// -#include -#include - -#include -#include -#include -#include -//sensable namespace -#include -#include - - - -double prevTime; - -namespace sofa -{ - -namespace component -{ - -namespace controller -{ - -using namespace sofa::defaulttype; -using namespace core::behavior; -using namespace sofa::defaulttype; - -NewOmniDriverEmu::NewOmniDriverEmu() - : forceScale(initData(&forceScale, 1.0, "forceScale","Default scaling factor applied to the force feedback")) - , scale(initData(&scale, 1.0, "scale","Default scale applied to the Phantom Coordinates. ")) - , positionBase(initData(&positionBase, Vec3d(0,0,0), "positionBase","Position of the interface base in the scene world coordinates")) - , orientationBase(initData(&orientationBase, Quat(0,0,0,1), "orientationBase","Orientation of the interface base in the scene world coordinates")) - , positionTool(initData(&positionTool, Vec3d(0,0,0), "positionTool","Position of the tool in the omni end effector frame")) - , orientationTool(initData(&orientationTool, Quat(0,0,0,1), "orientationTool","Orientation of the tool in the omni end effector frame")) - , permanent(initData(&permanent, false, "permanent" , "Apply the force feedback permanently")) - , omniVisu(initData(&omniVisu, false, "omniVisu", "Visualize the position of the interface in the virtual scene")) - , simuFreq(initData(&simuFreq, 1000, "simuFreq", "frequency of the \"simulated Omni\"")) - , simulateTranslation(initData(&simulateTranslation, false, "simulateTranslation", "do very naive \"translation simulation\" of omni, with constant orientation <0 0 0 1>")) - , trajPts(initData(&trajPts, "trajPoints","Trajectory positions")) - , trajTim(initData(&trajTim, "trajTiming","Trajectory timing")) - , visu_base(NULL) - , visu_end(NULL) -{ - - this->f_listening.setValue(true); - data.forceFeedback = new NullForceFeedback(); - noDevice = false; - moveOmniBase = false; - executeAsynchro = false; - omniSimThreadCreated = false; -} - -NewOmniDriverEmu::~NewOmniDriverEmu() -{ - if (visu_base) - { - delete visu_base; - } - if (visu_end) - { - delete visu_end; - } - -} - -void NewOmniDriverEmu::cleanup() -{ - sout << "NewOmniDriverEmu::cleanup()" << sendl; -} - -void NewOmniDriverEmu::init() -{ - std::cout << "[NewOmniEmu] init" << endl; -} - -void *hapticSimuExecute( void *ptr ) -{ - - NewOmniDriverEmu *omniDrv = (NewOmniDriverEmu*)ptr; - double timeScale = 1.0 / (double)CTime::getTicksPerSec(); - double startTime, endTime, totalTime, realTimePrev = -1.0, realTimeAct; - double requiredTime = 1.0/double(omniDrv->simuFreq.getValue()) * 1.0/timeScale; // [us] - double timeCorrection = 0.1 * requiredTime; - int timeToSleep; - - // construct the "trajectory" - NewOmniDriverEmu::VecCoord pts = omniDrv->trajPts.getValue(); - unsigned int numPts = pts.size(); - type::vector tmg = omniDrv->trajTim.getValue(); - unsigned int numSegs = tmg.size(); - double stepTime = 1.0/omniDrv->simuFreq.getValue(); - - if (numSegs != (2*numPts - 1)) - { - std::cerr << "Bad trajectory specification " << std::endl; - return(0); - } - NewOmniDriverEmu::VecCoord stepDiff; - type::vector stepNum; - - unsigned int seg = 0; - for (unsigned int np = 0; np < numPts; np++) - { - //for the point - unsigned int n = tmg[seg]*omniDrv->simuFreq.getValue(); - stepNum.push_back(n); - cout << "N pts = " << n << endl; - NewOmniDriverEmu::Coord crd; - cout << " adding " << crd << endl; - stepDiff.push_back(crd); - - //for the line - if (np < numPts-1) - { - seg++; - n = tmg[seg]*omniDrv->simuFreq.getValue(); - cout << "N lin = " << n << endl; - stepNum.push_back(n); - Vec3d dx = (pts[np+1].getCenter() - pts[np].getCenter())/double(n); - type::Quat dor; ///TODO difference for rotations!!! - NewOmniDriverEmu::Coord crd(dx, dor); - cout << "adding " << crd << endl; - stepDiff.push_back(crd); - } - seg++; - } - - std::cout << " stepNum = " << stepNum << std::endl; - std::cout << " stepDiff = " << stepDiff << std::endl; - - //trajectory done - - std::cout << "TimeScale = " << timeScale << std::endl; - - SolidTypes::SpatialVector temp1, temp2; - - long long unsigned asynchroStep=0; - double averageFreq = 0.0, minimalFreq=1e10; - - unsigned int actSeg = 0; - unsigned int actStep = 0; - - sofa::type::Quat actualRot; - sofa::type::Vec3d actualPos = pts[0].getCenter(); - - cout << "numSegs = " << numSegs << endl; - cout << "numSegs = " << numSegs << endl; - - while (true) - { - if (omniDrv->executeAsynchro) - { - startTime = double(omniDrv->thTimer->getTime()); - - //compute the actual position - if (actSeg < numSegs) - { - if (actStep < stepNum[actSeg]) - { - actualPos += stepDiff[actSeg].getCenter(); - //cout << "Adding [" << actStep << "] " << stepDiff[actSeg] << endl; - actStep++; - } - else - { - actStep=0; - actSeg++; - //cout << "Changing " << endl; - } - } - //else - // cout << "Finished" << endl; - - - omniDrv->data.servoDeviceData.pos = actualPos; - omniDrv->data.servoDeviceData.quat = actualRot; - SolidTypes::Transform baseOmni_H_endOmni(actualPos * omniDrv->data.scale, actualRot); - SolidTypes::Transform world_H_virtualTool = omniDrv->data.world_H_baseOmni * baseOmni_H_endOmni * omniDrv->data.endOmni_H_virtualTool; - - omniDrv->data.forceFeedback->computeWrench(world_H_virtualTool,temp1,temp2); - - realTimeAct = double(omniDrv->thTimer->getTime()); - if (asynchroStep > 0) - { - double realFreq = 1.0/( (realTimeAct - realTimePrev)*timeScale ); - averageFreq += realFreq; - //std::cout << "actual frequency = " << realFreq << std::endl; - if (realFreq < minimalFreq) - minimalFreq = realFreq; - - if ( ((asynchroStep+1) % 1000) == 0) - { - std::cout << "Average frequency of the loop = " << averageFreq/double(asynchroStep) << " Hz " << std::endl; - std::cout << "Minimal frequency of the loop = " << minimalFreq << " Hz " << std::endl; - } - } - - realTimePrev = realTimeAct; - asynchroStep++; - - endTime = double(omniDrv->thTimer->getTime()); //[s] - totalTime = (endTime - startTime); // [us] - timeToSleep = int( (requiredTime - totalTime) - timeCorrection); // [us] - if (timeToSleep > 0) - { - std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep)); - } - else - { - std::cout << "Cannot achieve desired frequency, computation too slow: " << totalTime << std::endl; - } - - } - else - { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - } -} - -void NewOmniDriverEmu::bwdInit() -{ - sout<<"NewOmniDriverEmu::bwdInit() is called"<(this->getContext()); // access to current node - ForceFeedback *ff = context->getTreeObject(); - - data.forceFeedback = ff; - - setDataValue(); - - if (!omniSimThreadCreated) - { - sout << "Not initializing phantom, starting emulating thread..." << sendl; - pthread_t hapSimuThread; - - if (thTimer == NULL) - thTimer = new(CTime); - - if ( pthread_create( &hapSimuThread, NULL, hapticSimuExecute, (void*)this) == 0 ) - { - sout << "Thread created for Omni simulation" << sendl; - omniSimThreadCreated=true; - } - } - else - sout << "Emulating thread already running" << sendl; -} - - -void NewOmniDriverEmu::setDataValue() -{ - data.scale = scale.getValue(); - data.forceScale = forceScale.getValue(); - Quat q = orientationBase.getValue(); - q.normalize(); - orientationBase.setValue(q); - data.world_H_baseOmni.set( positionBase.getValue(), q ); - q=orientationTool.getValue(); - q.normalize(); - data.endOmni_H_virtualTool.set(positionTool.getValue(), q); - data.permanent_feedback = permanent.getValue(); -} - -void NewOmniDriverEmu::reset() -{ - std::cout<<"NewOmniDriver::reset() is called" <reinit(); -} - -void NewOmniDriverEmu::reinitVisual() -{ - cout << "NewOmniDriver::reinitVisual() is called " << endl; - if(visu_base!=NULL) - { - cout << "visu_base = " << visu_base << endl; - delete(visu_base); - visu_base = new sofa::component::visualmodel::OglModel(); - visu_base->fileMesh.setValue("mesh/omni_test2.obj"); - visu_base->m_scale.setValue(type::Vector3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_end->setColor(1.0f,1.0f,1.0f,1.0f); - visu_base->init(); - visu_base->initVisual(); - visu_base->updateVisual(); - visu_base->applyRotation(orientationBase.getValue()); - visu_base->applyTranslation( positionBase.getValue()[0],positionBase.getValue()[1], positionBase.getValue()[2]); - - } - - if (visu_end != NULL) - { - //serr<<"create visual model for NewOmniDriver end"<m_scale.setValue(type::Vector3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_end->setColor(1.0f,0.3f,0.0f,1.0f); - visu_end->init(); - visu_end->initVisual(); - visu_end->updateVisual(); - } - - -} - -void NewOmniDriverEmu::reinit() -{ - std::cout<<"NewOmniDriver::reinit() is called" <cleanup(); - this->bwdInit(); - this->reinitVisual(); - std::cout<<"NewOmniDriver::reinit() done" <getRigidX(); - // x_rigid->resize(1); - //(*x_rigid)[0].getOrientation() = q; - //(*x_rigid)[0].getCenter() = positionBase.getValue(); - //double s = - //this->scale=Vector3(this->) - -} - -void NewOmniDriverEmu::draw() -{ - //cout << "NewOmniDriver::draw is called" << endl; - if(omniVisu.getValue()) - { - if (visu_base == NULL) - { - cout << "Creating visu_base" << endl; - // create visual object - //serr<<"create visual model for NewOmniDriver base"<fileMesh.setValue("mesh/omni_test2.obj"); - visu_base->m_scale.setValue(type::Vector3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_base->init(); - visu_base->initVisual(); - visu_base->updateVisual(); - visu_base->applyRotation(orientationBase.getValue()); - visu_base->applyTranslation( positionBase.getValue()[0],positionBase.getValue()[1], positionBase.getValue()[2]); - //getContext()->addObject(visu_base); - } - - - if (visu_end == NULL) - { - //serr<<"create visual model for NewOmniDriver end"<fileMesh.setValue("mesh/stylus.obj"); - visu_end->m_scale.setValue(type::Vector3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_end->setColor(1.0f,0.3f,0.0f,1.0f); - visu_end->init(); - visu_end->initVisual(); - visu_end->updateVisual(); - } - - // compute position of the endOmni in worldframe - SolidTypes::Transform baseOmni_H_endOmni(data.deviceData.pos*data.scale, data.deviceData.quat); - SolidTypes::Transform world_H_endOmni = data.world_H_baseOmni * baseOmni_H_endOmni ; - - - visu_end->xforms.resize(1); - (visu_end->xforms)[0].getOrientation() = world_H_endOmni.getOrientation(); - (visu_end->xforms)[0].getCenter() = world_H_endOmni.getOrigin(); - - // draw the 2 visual models - visu_base->drawVisual(); - visu_end->drawVisual(); - } -} - -void NewOmniDriverEmu::copyDeviceDataCallback(OmniData *pUserData) -{ - OmniData *data = pUserData; // static_cast(pUserData); - memcpy(&data->deviceData, &data->servoDeviceData, sizeof(DeviceData)); - data->servoDeviceData.nupdates = 0; - data->servoDeviceData.ready = true; -} - -void NewOmniDriverEmu::stopCallback(OmniData *pUserData) -{ - OmniData *data = pUserData; // static_cast(pUserData); - data->servoDeviceData.stop = true; -} - -void NewOmniDriverEmu::onKeyPressedEvent(core::objectmodel::KeypressedEvent *kpe) -{ - - - -} - -void NewOmniDriverEmu::onKeyReleasedEvent(core::objectmodel::KeyreleasedEvent *kre) -{ - - //omniVisu.setValue(false); - -} - -void NewOmniDriverEmu::handleEvent(core::objectmodel::Event *event) -{ - - //std::cout<<"NewEvent detected !!"<(event)) - { - //getData(); // copy data->servoDeviceData to gDeviceData - //if (!simulateTranslation.getValue()) { - copyDeviceDataCallback(&data); - if (data.deviceData.ready) - { - cout << "Data ready, event" << endl; - data.deviceData.quat.normalize(); - //sout << "driver is working ! " << data->servoDeviceData.transform[12+0] << endl; - - - /// COMPUTATION OF THE vituralTool 6D POSITION IN THE World COORDINATES - SolidTypes::Transform baseOmni_H_endOmni(data.deviceData.pos*data.scale, data.deviceData.quat); - SolidTypes::Transform world_H_virtualTool = data.world_H_baseOmni * baseOmni_H_endOmni * data.endOmni_H_virtualTool; - - - // store actual position of interface for the forcefeedback (as it will be used as soon as new LCP will be computed) - data.forceFeedback->setReferencePosition(world_H_virtualTool); - - /// TODO : SHOULD INCLUDE VELOCITY !! - sofa::core::objectmodel::HapticDeviceEvent omniEvent(data.deviceData.id, world_H_virtualTool.getOrigin(), world_H_virtualTool.getOrientation() , data.deviceData.m_buttonState); - - this->getContext()->propagateEvent(sofa::core::ExecParams::defaultInstance(), &omniEvent); - - if (moveOmniBase) - { - std::cout<<" new positionBase = "<applyTranslation(positionBase_buf[0] - positionBase.getValue()[0], - positionBase_buf[1] - positionBase.getValue()[1], - positionBase_buf[2] - positionBase.getValue()[2]); - positionBase.setValue(positionBase_buf); - setDataValue(); - //this->reinitVisual(); - } - executeAsynchro=true; - } - else - std::cout<<"data not ready"<(event)) - { - core::objectmodel::KeypressedEvent *kpe = dynamic_cast(event); - if (kpe->getKey()=='Z' ||kpe->getKey()=='z' ) - { - moveOmniBase = !moveOmniBase; - std::cout<<"key z detected "<cleanup(); - positionBase_buf = positionBase.getValue(); - - } - else - { - this->reinit(); - } - } - - if(kpe->getKey()=='K' || kpe->getKey()=='k') - { - positionBase_buf.x()=0.0; - positionBase_buf.y()=0.5; - positionBase_buf.z()=2.6; - } - - if(kpe->getKey()=='L' || kpe->getKey()=='l') - { - positionBase_buf.x()=-0.15; - positionBase_buf.y()=1.5; - positionBase_buf.z()=2.6; - } - - if(kpe->getKey()=='M' || kpe->getKey()=='m') - { - positionBase_buf.x()=0.0; - positionBase_buf.y()=2.5; - positionBase_buf.z()=2.6; - } - - - - } -} - -int NewOmniDriverEmuClass = core::RegisterObject("Solver to test compliance computation for new articulated system objects") - .add< NewOmniDriverEmu >(); - -} // namespace controller - -} // namespace component - -} // namespace sofa diff --git a/applications/plugins/SensableEmulation/NewOmniDriverEmu.h b/applications/plugins/SensableEmulation/NewOmniDriverEmu.h deleted file mode 100644 index c12a68bec9d..00000000000 --- a/applications/plugins/SensableEmulation/NewOmniDriverEmu.h +++ /dev/null @@ -1,162 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#ifndef SOFA_COMPONENT_CONTROLLER_OMNIEMU_H -#define SOFA_COMPONENT_CONTROLLER_OMNIEMU_H - -//Sensable include -#include -#include - -#include -#include -#include - -#include - -namespace sofa -{ -namespace simulation { class Node; } - -namespace component -{ -namespace visualModel { class OglModel; } - -namespace controller -{ - -class ForceFeedback; - - -using namespace sofa::defaulttype; -using namespace helper::system::thread; -using core::objectmodel::Data; - -/** Holds data retrieved from HDAPI. */ -typedef struct -{ - unsigned int id; - int nupdates; - int m_buttonState; /* Has the device button has been pressed. */ - //hduVector3Dd m_devicePosition; /* Current device coordinates. */ - //HDErrorInfo m_error; - Vec3d pos; - Quat quat; - bool ready; - bool stop; -} DeviceData; - -typedef struct -{ - ForceFeedback* forceFeedback; - simulation::Node *context; - - sofa::defaulttype::SolidTypes::Transform endOmni_H_virtualTool; - //Transform baseOmni_H_endOmni; - sofa::defaulttype::SolidTypes::Transform world_H_baseOmni; - double forceScale; - double scale; - bool permanent_feedback; - - // API OMNI // - DeviceData servoDeviceData; // for the haptic loop - DeviceData deviceData; // for the simulation loop - -} OmniData; - -/** -* Omni driver -*/ -class NewOmniDriverEmu : public Controller -{ - -public: - typedef Rigid3dTypes::Coord Coord; - typedef Rigid3dTypes::VecCoord VecCoord; - - SOFA_CLASS(NewOmniDriverEmu, Controller); - Data scale; ///< Default scale applied to the Phantom Coordinates. - Data forceScale; ///< Default scaling factor applied to the force feedback - Data simuFreq; ///< frequency of the "simulated Omni" - Data positionBase; ///< Position of the interface base in the scene world coordinates - Data orientationBase; ///< Orientation of the interface base in the scene world coordinates - Data positionTool; ///< Position of the tool in the omni end effector frame - Data orientationTool; ///< Orientation of the tool in the omni end effector frame - Data permanent; ///< Apply the force feedback permanently - Data omniVisu; ///< Visualize the position of the interface in the virtual scene - Data simulateTranslation; ///< do very naive "translation simulation" of omni, with constant orientation <0 0 0 1> - - OmniData data; - - - NewOmniDriverEmu(); - virtual ~NewOmniDriverEmu(); - - virtual void init(); - virtual void bwdInit(); - virtual void reset(); - void reinit(); - - int initDevice(OmniData& data); - - void cleanup(); - virtual void draw(); - - void onKeyPressedEvent(core::objectmodel::KeypressedEvent *); - void onKeyReleasedEvent(core::objectmodel::KeyreleasedEvent *); - - void setDataValue(); - void reinitVisual(); - - bool afterFirstStep; - SolidTypes::Transform prevPosition; - - //neede for "omni simulation" - CTime *thTimer; - double lastStep; - bool executeAsynchro; - Data trajPts; ///< Trajectory positions - Data > trajTim; ///< Trajectory timing - -private: - void handleEvent(core::objectmodel::Event *); - void copyDeviceDataCallback(OmniData *pUserData); - void stopCallback(OmniData *pUserData); - sofa::component::visualmodel::OglModel *visu_base, *visu_end; - bool noDevice; - - bool moveOmniBase; - Vec3d positionBase_buf; - bool omniSimThreadCreated; - - - - -}; - - -} // namespace controller - -} // namespace component - -} // namespace sofa - -#endif // SOFA_COMPONENT_CONTROLLER_OMNIEMU_H diff --git a/applications/plugins/SensableEmulation/OmniDriverEmu.cpp b/applications/plugins/SensableEmulation/OmniDriverEmu.cpp deleted file mode 100644 index cbfe2cfd3bc..00000000000 --- a/applications/plugins/SensableEmulation/OmniDriverEmu.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "OmniDriverEmu.h" - -#include -#include -#include - -#include - -////force feedback -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#include - -#include -using sofa::simulation::mechanicalvisitor::MechanicalPropagateOnlyPositionAndVelocityVisitor; - -#include - -namespace sofa -{ - -namespace component -{ - -namespace controller -{ - -using namespace sofa::type; -using namespace sofa::defaulttype; -using namespace core::behavior; -using type::vector; - -OmniDriverEmu::OmniDriverEmu() - : forceScale(initData(&forceScale, 1.0, "forceScale","Default scaling factor applied to the force feedback")) - , scale(initData(&scale, 1.0, "scale","Default scale applied to the Phantom Coordinates. ")) - , positionBase(initData(&positionBase, Vec3d(0,0,0), "positionBase","Position of the interface base in the scene world coordinates")) - , orientationBase(initData(&orientationBase, Quat(0,0,0,1), "orientationBase","Orientation of the interface base in the scene world coordinates")) - , positionTool(initData(&positionTool, Vec3d(0,0,0), "positionTool","Position of the tool in the omni end effector frame")) - , orientationTool(initData(&orientationTool, Quat(0,0,0,1), "orientationTool","Orientation of the tool in the omni end effector frame")) - , permanent(initData(&permanent, false, "permanent" , "Apply the force feedback permanently")) - , omniVisu(initData(&omniVisu, false, "omniVisu", "Visualize the position of the interface in the virtual scene")) - , simuFreq(initData(&simuFreq, 1000, "simuFreq", "frequency of the \"simulated Omni\"")) - , simulateTranslation(initData(&simulateTranslation, false, "simulateTranslation", "do very naive \"translation simulation\" of omni, with constant orientation <0 0 0 1>")) - , thTimer(nullptr) - , trajPts(initData(&trajPts, "trajPoints","Trajectory positions")) - , trajTim(initData(&trajTim, "trajTiming","Trajectory timing")) - , visu_base(nullptr) - , visu_end(nullptr) - , currentToolIndex(0) - , isToolControlled(true) -{ - this->f_listening.setValue(true); - noDevice = false; - moveOmniBase = false; - executeAsynchro = false; - omniSimThreadCreated = false; - m_terminate = true; -} - - -OmniDriverEmu::~OmniDriverEmu() -{ - if (thTimer != nullptr) - delete thTimer; -} - - -void OmniDriverEmu::setForceFeedbacks(vector ffs) -{ - data.forceFeedbacks.clear(); - for (unsigned int i=0; i *> (this->getContext()->getMechanicalState()); - if (!mState) - msg_warning() << "OmniDriverEmu has no binding MechanicalState."; - else - msg_info() << "[Omni] init" ; - - if(mState->getSize()resize(toolCount.getValue()); -} - - -/** - function that is used to emulate a haptic device by interpolating the position of the tool between several points. -*/ -void hapticSimuExecute(std::atomic& terminate, void *ptr ) -{ - assert(ptr!=nullptr); - - // Initialization - OmniDriverEmu *omniDrv = static_cast(ptr); - - // Init the "trajectory" data - OmniDriverEmu::VecCoord pts = omniDrv->trajPts.getValue(); //sets of points use for interpolation - type::vector tmg = omniDrv->trajTim.getValue(); //sets of "key time" for interpolation - - if (pts.empty()) - { - msg_error(omniDrv) << "Bad trajectory specification : there are no points for interpolation. "; - return; - } - - // Add a first point ( 0 0 0 0 0 0 1 ) if the first "key time" is not 0 - if (sofa::helper::isEqual(tmg[0], 0.0)) - { - pts.insert(pts.begin(), OmniDriverEmu::Coord()); - tmg.insert(tmg.begin(), 0); - } - - size_t numPts = pts.size(); - size_t numSegs = tmg.size(); - - // test if "trajectory" data are correct - if (numSegs != numPts) - { - msg_error(omniDrv) << "Bad trajectory specification : the number of trajectory timing does not match the number of trajectory points. "; - return; - } - - type::vector< unsigned int > stepNum; - // Init the Step list - for (unsigned int i = 0; i < numPts; i++) - { - stepNum.push_back(tmg[i] * omniDrv->simuFreq.getValue()); - } - - // Init data for interpolation. - SolidTypes::SpatialVector temp1, temp2; - long long unsigned asynchroStep=0; - double averageFreq = 0.0, minimalFreq=1e10; - unsigned int actSeg = 0; - unsigned int actStep = 0; - sofa::type::Quat actualRot; - sofa::type::Vec3d actualPos = pts[0].getCenter(); - - double timeScale = 1.0 / (double)helper::system::thread::CTime::getTicksPerSec(); - double startTime, endTime, totalTime, realTimePrev = -1.0, realTimeAct; - double requiredTime = 1.0 / (double)omniDrv->simuFreq.getValue() * 1.0 / timeScale; - double timeCorrection = 0.1 * requiredTime; - int timeToSleep; - - int oneTimeMessage = 0; - // loop that updates the position tool. - while (!terminate) - { - if (omniDrv->executeAsynchro) - { - if (oneTimeMessage == 1) - { - oneTimeMessage = 0; - } - - startTime = double(omniDrv->thTimer->getTime()); - - // compute the new position and orientataion - if (actSeg < numSegs) - { - - if (actSeg > 0 && actStep < stepNum[actSeg]) - { - - //compute the coeff for interpolation - double t = ((double)(actStep-stepNum[actSeg-1]))/((double)(stepNum[actSeg]-stepNum[actSeg-1])); - - //compute the actual position - actualPos = (pts[actSeg-1].getCenter())*(1-t)+(pts[actSeg].getCenter())*t; - - //compute the actual orientation - actualRot.slerp(pts[actSeg-1].getOrientation(),pts[actSeg].getOrientation(),t,true); - - actStep++; - } - else - { - actualPos = pts[actSeg].getCenter(); - actualRot = pts[actSeg].getOrientation(); - actSeg++; - } - } - else - { - msg_info(omniDrv) << "End of the movement!" ; - return; - } - - // Update the position of the tool - omniDrv->data.servoDeviceData.pos = actualPos; - omniDrv->data.servoDeviceData.quat = actualRot; - SolidTypes::Transform baseOmni_H_endOmni(actualPos * omniDrv->data.scale, actualRot); - SolidTypes::Transform world_H_virtualTool = omniDrv->data.world_H_baseOmni * baseOmni_H_endOmni * omniDrv->data.endOmni_H_virtualTool; - - // transmit the position of the tool to the force feedback - omniDrv->data.forceFeedbackIndice= omniDrv->getCurrentToolIndex(); - // store actual position of interface for the forcefeedback (as it will be used as soon as new LCP will be computed) - for (unsigned int i=0; idata.forceFeedbacks.size(); i++) - { - if (omniDrv->data.forceFeedbacks[i]->d_indice.getValue()==omniDrv->data.forceFeedbackIndice) - { - omniDrv->data.forceFeedbacks[i]->computeWrench(world_H_virtualTool,temp1,temp2); - } - } - - realTimeAct = double(omniDrv->thTimer->getTime()); - - if (asynchroStep > 0) - { - double realFreq = 1.0/( (realTimeAct - realTimePrev)*timeScale ); - averageFreq += realFreq; - if (realFreq < minimalFreq) - minimalFreq = realFreq; - - if ( ((asynchroStep+1) % 1000) == 0) - { - msg_info(omniDrv) << "Average frequency of the loop = " << averageFreq/double(asynchroStep) << " Hz " - << "Minimal frequency of the loop = " << minimalFreq << " Hz " ; - } - } - - realTimePrev = realTimeAct; - asynchroStep++; - - endTime = (double)omniDrv->thTimer->getTime(); //[s] - totalTime = (endTime - startTime); // [us] - timeToSleep = int( ((requiredTime - totalTime) - timeCorrection) ); // [us] - - if (timeToSleep > 0) - { - std::this_thread::sleep_for(std::chrono::seconds(int(timeToSleep * timeScale))); - } - else - { - msg_info(omniDrv) << "Cannot achieve desired frequency, computation too slow : " << totalTime * timeScale << " seconds for last iteration."; - } - } - else - { - if (oneTimeMessage == 0) - { - msg_info(omniDrv) << "Running Asynchro without action" ; - oneTimeMessage = 1; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - } -} - -void OmniDriverEmu::bwdInit() -{ - msg_info()<<"OmniDriverEmu::bwdInit() is called"; - sofa::simulation::Node *context = dynamic_cast(this->getContext()); // access to current node - - // depending on toolCount, search either the first force feedback, or the feedback with indice "0" - sofa::simulation::Node *groot = dynamic_cast(context->getRootContext()); // access to current node - - vector ffs; - groot->getTreeObjects(&ffs); - msg_info() << "OmniDriver: "<m_terminate), this); - setOmniSimThreadCreated(true); - msg_info() << "OmniDriver : Thread created for Omni simulation."; -} - - -void OmniDriverEmu::setDataValue() -{ - data.forceFeedbackIndice=0; - data.scale = scale.getValue(); - data.forceScale = forceScale.getValue(); - Quat q = orientationBase.getValue(); - q.normalize(); - orientationBase.setValue(q); - data.world_H_baseOmni.set( positionBase.getValue(), q ); - q=orientationTool.getValue(); - q.normalize(); - data.endOmni_H_virtualTool.set(positionTool.getValue(), q); - data.permanent_feedback = permanent.getValue(); -} - -void OmniDriverEmu::reinit() -{ - msg_info()<<"OmniDriverEmu::reinit() is called"; - this->cleanup(); - this->bwdInit(); - msg_info()<<"OmniDriverEmu::reinit() done"; -} - -void OmniDriverEmu::draw(const core::visual::VisualParams *) -{ - using sofa::gl::component::rendering3d::OglModel; - if(omniVisu.getValue()) - { - static bool isInited=false; - if(!isInited) - { - // compute position of the endOmni in worldframe - defaulttype::SolidTypes::Transform baseOmni_H_endOmni(data.deviceData.pos*data.scale, data.deviceData.quat); - defaulttype::SolidTypes::Transform world_H_endOmni = data.world_H_baseOmni * baseOmni_H_endOmni ; - - visu_base = sofa::core::objectmodel::New(); - visu_base->d_fileMesh.setValue("mesh/omni_test2.obj"); - visu_base->d_scale.setValue(type::Vec3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_base->setColor(1.0f,1.0f,1.0f,1.0f); - visu_base->init(); - visu_base->initVisual(sofa::core::visual::visualparams::defaultInstance()); - visu_base->updateVisual(sofa::core::visual::visualparams::defaultInstance()); - visu_base->applyRotation(orientationBase.getValue()); - visu_base->applyTranslation( positionBase.getValue()[0],positionBase.getValue()[1], positionBase.getValue()[2]); - - visu_end = sofa::core::objectmodel::New(); - visu_end->d_fileMesh.setValue("mesh/stylus.obj"); - visu_end->d_scale.setValue(type::Vec3(scale.getValue(),scale.getValue(),scale.getValue())); - visu_end->setColor(1.0f,0.3f,0.0f,1.0f); - visu_end->init(); - visu_end->initVisual(sofa::core::visual::visualparams::defaultInstance()); - visu_end->updateVisual(sofa::core::visual::visualparams::defaultInstance()); - visu_end->applyRotation(world_H_endOmni.getOrientation()); - visu_end->applyTranslation(world_H_endOmni.getOrigin()[0],world_H_endOmni.getOrigin()[1],world_H_endOmni.getOrigin()[2]); - isInited=true; - } - - // draw the 2 visual models - visu_base->doDrawVisual(sofa::core::visual::VisualParams::defaultInstance()); - visu_end->doDrawVisual(sofa::core::visual::VisualParams::defaultInstance()); - } -} - -void OmniDriverEmu::copyDeviceDataCallback(OmniData *pUserData) -{ - OmniData *data = pUserData; - memcpy(&data->deviceData, &data->servoDeviceData, sizeof(DeviceData)); - data->servoDeviceData.ready = true; - data->servoDeviceData.nupdates = 0; -} - -void OmniDriverEmu::stopCallback(OmniData *pUserData) -{ - OmniData *data = pUserData; - data->servoDeviceData.stop = true; -} - -void OmniDriverEmu::handleEvent(core::objectmodel::Event *event) -{ - if (dynamic_cast(event)) - { - msg_info() << "Test handle event "; - - copyDeviceDataCallback(&data); - - msg_info() << data.deviceData.ready; - - if (data.deviceData.ready) - { - msg_info() << "Data ready, event 2"; - - data.deviceData.quat.normalize(); - - if (isToolControlled) // ignore haptic device if tool is unselected - { - /// COMPUTATION OF THE vituralTool 6D POSITION IN THE World COORDINATES - SolidTypes< double >::Transform baseOmni_H_endOmni(data.deviceData.pos*data.scale, data.deviceData.quat); - SolidTypes< double >::Transform world_H_virtualTool = data.world_H_baseOmni * baseOmni_H_endOmni * data.endOmni_H_virtualTool; - - //---------------------------- - data.forceFeedbackIndice=currentToolIndex; - // store actual position of interface for the forcefeedback (as it will be used as soon as new LCP will be computed) - //data.forceFeedback->setReferencePosition(world_H_virtualTool); - for (unsigned int i=0; id_indice.getValue()==data.forceFeedbackIndice) - data.forceFeedbacks[i]->setReferencePosition(world_H_virtualTool); - - //----------------------------- - //TODO : SHOULD INCLUDE VELOCITY !! - //sofa::core::objectmodel::HapticDeviceEvent omniEvent(data.deviceData.id, world_H_virtualTool.getOrigin(), world_H_virtualTool.getOrientation() , data.deviceData.m_buttonState); - //this->getContext()->propagateEvent(sofa::core::ExecParams::defaultInstance(), &omniEvent); - helper::WriteAccessor > > > x = *this->mState->write(core::VecCoordId::position()); - this->getContext()->getMechanicalState()->vRealloc( sofa::core::MechanicalParams::defaultInstance(), core::VecCoordId::freePosition() ); // freePosition is not allocated by default - helper::WriteAccessor > > > xfree = *this->mState->write(core::VecCoordId::freePosition()); - - /// FIX : check if the mechanical state is empty, if true, resize it - /// otherwise: crash when accessing xfree[] and x[] - if(xfree.size() == 0) - xfree.resize(1); - if(x.size() == 0) - x.resize(1); - - if((size_t)currentToolIndex >= xfree.size() || (size_t)currentToolIndex >= x.size()) - msg_warning()<<"currentToolIndex exceed the size of xfree/x vectors"; - else - { - xfree[currentToolIndex].getCenter() = world_H_virtualTool.getOrigin(); - x[currentToolIndex].getCenter() = world_H_virtualTool.getOrigin(); - - xfree[currentToolIndex].getOrientation() = world_H_virtualTool.getOrientation(); - x[currentToolIndex].getOrientation() = world_H_virtualTool.getOrientation(); - } - - sofa::simulation::Node *node = dynamic_cast (this->getContext()); - if (node != nullptr) - { - MechanicalPropagateOnlyPositionAndVelocityVisitor mechaVisitor(sofa::core::MechanicalParams::defaultInstance()); mechaVisitor.execute(node); - sofa::simulation::UpdateMappingVisitor updateVisitor(sofa::core::ExecParams::defaultInstance()); updateVisitor.execute(node); - } - } - else - { - data.forceFeedbackIndice = -1; - } - - if (moveOmniBase) - { - msg_info()<<" new positionBase = "<applyTranslation(positionBase_buf[0]-positionBase.getValue()[0], - positionBase_buf[1]-positionBase.getValue()[1], - positionBase_buf[2]-positionBase.getValue()[2]); - positionBase.setValue(positionBase_buf); - setDataValue(); - } - - executeAsynchro = true; - } - else - msg_info()<<"data not ready"; - } - - if (dynamic_cast(event)) - { - core::objectmodel::KeypressedEvent *kpe = dynamic_cast(event); - if (kpe->getKey()=='Z' ||kpe->getKey()=='z' ) - { - moveOmniBase = !moveOmniBase; - msg_info()<<"key z detected "; - omniVisu.setValue(moveOmniBase); - - if(moveOmniBase) - { - this->cleanup(); - positionBase_buf = positionBase.getValue(); - } - else - { - this->reinit(); - } - } - - if(kpe->getKey()=='K' || kpe->getKey()=='k') - { - positionBase_buf.x()=0.0; - positionBase_buf.y()=0.5; - positionBase_buf.z()=2.6; - } - - if(kpe->getKey()=='L' || kpe->getKey()=='l') - { - positionBase_buf.x()=-0.15; - positionBase_buf.y()=1.5; - positionBase_buf.z()=2.6; - } - - if(kpe->getKey()=='M' || kpe->getKey()=='m') - { - positionBase_buf.x()=0.0; - positionBase_buf.y()=2.5; - positionBase_buf.z()=2.6; - } - - // emulated haptic buttons B=btn1, N=btn2 - if (kpe->getKey()=='H' || kpe->getKey()=='h') - { - msg_info() << "emulated button 1 pressed"; - Vec3 dummyVector; - Quat dummyQuat; - sofa::core::objectmodel::HapticDeviceEvent event(currentToolIndex,dummyVector,dummyQuat, - sofa::core::objectmodel::HapticDeviceEvent::Button1StateMask); - sofa::simulation::Node *groot = dynamic_cast(getContext()->getRootContext()); // access to current node - groot->propagateEvent(core::ExecParams::defaultInstance(), &event); - } - if (kpe->getKey()=='J' || kpe->getKey()=='j') - { - std::cout << "emulated button 2 pressed" << std::endl; - Vec3 dummyVector; - Quat dummyQuat; - sofa::core::objectmodel::HapticDeviceEvent event(currentToolIndex,dummyVector,dummyQuat, - sofa::core::objectmodel::HapticDeviceEvent::Button2StateMask); - sofa::simulation::Node *groot = dynamic_cast(getContext()->getRootContext()); // access to current node - groot->propagateEvent(core::ExecParams::defaultInstance(), &event); - } - - } - if (dynamic_cast(event)) - { - core::objectmodel::KeyreleasedEvent *kre = dynamic_cast(event); - // emulated haptic buttons B=btn1, N=btn2 - if (kre->getKey()=='H' || kre->getKey()=='h' - || kre->getKey()=='J' || kre->getKey()=='j') - { - msg_info() << "emulated button released" ; - Vec3 dummyVector; - Quat dummyQuat; - sofa::core::objectmodel::HapticDeviceEvent event(currentToolIndex,dummyVector,dummyQuat,0); - sofa::simulation::Node *groot = dynamic_cast(getContext()->getRootContext()); // access to current node - groot->propagateEvent(core::ExecParams::defaultInstance(), &event); - } - } -} - - -static int OmniDriverEmuClass = core::RegisterObject("Solver to test compliance computation for new articulated system objects") - .add< OmniDriverEmu >(); - -} // namespace controller - -} // namespace component - -} // namespace sofa diff --git a/applications/plugins/SensableEmulation/OmniDriverEmu.h b/applications/plugins/SensableEmulation/OmniDriverEmu.h deleted file mode 100644 index 0590808fa47..00000000000 --- a/applications/plugins/SensableEmulation/OmniDriverEmu.h +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#ifndef SOFA_COMPONENT_CONTROLLER_OMNIEMU_H -#define SOFA_COMPONENT_CONTROLLER_OMNIEMU_H - -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - -namespace sofa::gl::component::rendering3d -{ - class OglModel; - -} // namespace sofa::gl::component::rendering3d - -namespace sofa::component::haptics -{ - class ForceFeedback; -} - -namespace sofa::component::controller -{ - -/** Holds data retrieved from HDAPI. */ -typedef struct -{ - int nupdates; - int m_buttonState; /* Has the device button has been pressed. */ - type::Vec3d pos; - type::Quat quat; - bool ready; - bool stop; -} DeviceData; - -typedef struct -{ - type::vector forceFeedbacks; - int forceFeedbackIndice; - simulation::Node *context; - - sofa::defaulttype::SolidTypes::Transform endOmni_H_virtualTool; - sofa::defaulttype::SolidTypes::Transform world_H_baseOmni; - double forceScale; - double scale; - bool permanent_feedback; - - // API OMNI // - DeviceData servoDeviceData; // for the haptic loop - DeviceData deviceData; // for the simulation loop - -} OmniData; - -/** -* Omni driver emulator you can add to your scene. -* -* Controller's actions: -* key z: reset to base position -* key k, l, m: move base position -* key h: emulate button 1 press/release -* key i: emulate button 2 press/release -*/ -class SOFA_SENSABLEEMUPLUGIN_API OmniDriverEmu : public Controller -{ - -public: - typedef defaulttype::Rigid3dTypes::Coord Coord; - typedef defaulttype::Rigid3dTypes::VecCoord VecCoord; - - using Vec3d = sofa::type::Vec3d; - using Quat = sofa::type::Quat; - - SOFA_CLASS(OmniDriverEmu, Controller); - Data forceScale; ///< Default scaling factor applied to the force feedback - Data scale; ///< Default scale applied to the Phantom Coordinates. - Data positionBase; ///< Position of the interface base in the scene world coordinates - Data orientationBase; ///< Orientation of the interface base in the scene world coordinates - Data positionTool; ///< Position of the tool in the omni end effector frame - Data orientationTool; ///< Orientation of the tool in the omni end effector frame - Data permanent; ///< Apply the force feedback permanently - Data omniVisu; ///< Visualize the position of the interface in the virtual scene - Data simuFreq; ///< frequency of the "simulated Omni" - Data simulateTranslation; ///< do very naive "translation simulation" of omni, with constant orientation <0 0 0 1> - Data toolSelector; - Data toolCount; - - OmniData data; - - OmniDriverEmu(); - ~OmniDriverEmu() override; - - void init() override; - void bwdInit() override; - void reinit() override; - void cleanup() override; - void draw(const core::visual::VisualParams*) override; - - int initDevice(OmniData& data); - void setForceFeedbacks(type::vector ffs); - - void setDataValue(); - - void setOmniSimThreadCreated(bool b) { omniSimThreadCreated = b;} - - bool afterFirstStep; - defaulttype::SolidTypes::Transform prevPosition; - - //need for "omni simulation" - helper::system::thread::CTime *thTimer; - - /// Thread object - std::thread hapSimuThread; - - /// Bool to notify thread to stop work - std::atomic m_terminate; - - double lastStep; - bool executeAsynchro; - Data trajPts; ///< Trajectory positions - Data > trajTim; ///< Trajectory timing - - int getCurrentToolIndex() { return currentToolIndex;} - void handleEvent(core::objectmodel::Event *) override ; - -private: - - void copyDeviceDataCallback(OmniData *pUserData); - void stopCallback(OmniData *pUserData); - gl::component::rendering3d::OglModel::SPtr visu_base, visu_end; - bool noDevice; - - bool moveOmniBase; - Vec3d positionBase_buf; - - core::behavior::MechanicalState *mState; ///< Controlled MechanicalState. - - bool omniSimThreadCreated; - int currentToolIndex; - bool isToolControlled; -}; - - -} // namespace sofa::component::controller - -#endif // SOFA_COMPONENT_CONTROLLER_OMNIEMU_H diff --git a/applications/plugins/SensableEmulation/PluginSensableEmulation.txt b/applications/plugins/SensableEmulation/PluginSensableEmulation.txt deleted file mode 100644 index befe3d9bc7b..00000000000 --- a/applications/plugins/SensableEmulation/PluginSensableEmulation.txt +++ /dev/null @@ -1,10 +0,0 @@ -************************************ -* SensableEmulation.txt * -************************************ -AUTHOR : - - C.Duriez - -LICENCE : - - None - -OTHER COMMENTS : diff --git a/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn b/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn deleted file mode 100644 index becbb2480b0..00000000000 --- a/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn.view b/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn.view deleted file mode 100644 index 97e71316b4f..00000000000 --- a/applications/plugins/SensableEmulation/examples/SimpleBox-Method2.scn.view +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/SensableEmulation/examples/data/mesh/box.obj b/applications/plugins/SensableEmulation/examples/data/mesh/box.obj deleted file mode 100644 index 439b773295b..00000000000 --- a/applications/plugins/SensableEmulation/examples/data/mesh/box.obj +++ /dev/null @@ -1,20 +0,0 @@ -# Blender v2.68 (sub 0) OBJ File: '' -# www.blender.org -mtllib box.mtl -o Cube -v 1.000000 -1.000000 -1.000000 -v 1.000000 -1.000000 1.000000 -v -1.000000 -1.000000 1.000000 -v -1.000000 -1.000000 -1.000000 -v 1.000000 1.000000 -0.999999 -v 0.999999 1.000000 1.000001 -v -1.000000 1.000000 1.000000 -v -1.000000 1.000000 -1.000000 -usemtl Material -s off -f 1 2 3 4 -f 5 8 7 6 -f 1 5 6 2 -f 2 6 7 3 -f 3 7 8 4 -f 5 1 4 8 diff --git a/applications/plugins/SensableEmulation/examples/data/mesh/dental_instrument.obj b/applications/plugins/SensableEmulation/examples/data/mesh/dental_instrument.obj deleted file mode 100644 index 358faf79ad5..00000000000 --- a/applications/plugins/SensableEmulation/examples/data/mesh/dental_instrument.obj +++ /dev/null @@ -1,1194 +0,0 @@ -#### -# -# OBJ File Generated by LightWave3D -# LightWave3D OBJ Export v2.3 -# -#### -o dental_instrument.obj -mtllib dental_instrument.mtl -g default -v 0.020625 0.0233891 2.71688 -v 0.0350288 0.0174173 2.71666 -v 0.0409951 0.003 2.71656 -v 0.0350288 -0.0114173 2.71666 -v 0.020625 -0.0173891 2.71688 -v 0.00622117 -0.0114173 2.71709 -v 0.00025491 0.003 2.71719 -v 0.00622117 0.0174173 2.71709 -v 0.027375 0.0233891 2.85037 -v 0.0416982 0.0174173 2.84884 -v 0.0476311 0.003 2.8482 -v 0.0416982 -0.0114173 2.84884 -v 0.027375 -0.0173891 2.85037 -v 0.0130518 -0.0114173 2.85191 -v 0.00711889 0.003 2.85255 -v 0.0130518 0.0174173 2.85191 -v 0.051625 0.0233891 3.00175 -v 0.065948 0.0174173 3.00024 -v 0.0718807 0.003 2.99962 -v 0.065948 -0.0114173 3.00024 -v 0.051625 -0.0173891 3.00175 -v 0.037302 -0.0114173 3.00326 -v 0.0313693 0.003 3.00388 -v 0.037302 0.0174173 3.00326 -v 0.089375 0.0233891 3.193 -v 0.103764 0.0174173 3.19319 -v 0.109724 0.003 3.19327 -v 0.103764 -0.0114173 3.19319 -v 0.089375 -0.0173891 3.193 -v 0.0749862 -0.0114173 3.19281 -v 0.0690262 0.003 3.19273 -v 0.0749862 0.0174173 3.19281 -v 0.10075 0.0233891 3.285 -v 0.114998 0.0174173 3.28691 -v 0.1209 0.003 3.2877 -v 0.114998 -0.0114173 3.28691 -v 0.10075 -0.0173891 3.285 -v 0.0865018 -0.0114173 3.28309 -v 0.0806 0.003 3.2823 -v 0.0865018 0.0174173 3.28309 -v 0.09775 0.0233891 3.35875 -v 0.111383 0.0174173 3.36321 -v 0.11703 0.003 3.36506 -v 0.111383 -0.0114173 3.36321 -v 0.09775 -0.0173891 3.35875 -v 0.0841168 -0.0114173 3.35429 -v 0.0784698 0.003 3.35244 -v 0.0841168 0.0174173 3.35429 -v 0.077 0.0233891 3.42925 -v 0.0893074 0.0174173 3.43653 -v 0.0944051 0.003 3.43955 -v 0.0893074 -0.0114173 3.43653 -v 0.077 -0.0173891 3.42925 -v 0.0646926 -0.0114173 3.42197 -v 0.0595949 0.003 3.41895 -v 0.0646926 0.0174173 3.42197 -v 0.0335 0.0233891 3.48675 -v 0.0431682 0.0174173 3.49721 -v 0.0471728 0.003 3.50154 -v 0.0431682 -0.0114173 3.49721 -v 0.0335 -0.0173891 3.48675 -v 0.0238318 -0.0114173 3.47629 -v 0.0198272 0.003 3.47196 -v 0.0238318 0.0174173 3.47629 -v -0.029 0.0233891 3.5265 -v -0.0229674 0.0174173 3.53945 -v -0.0204688 0.003 3.54482 -v -0.0229674 -0.0114173 3.53945 -v -0.029 -0.0173891 3.5265 -v -0.0350326 -0.0114173 3.51355 -v -0.0375312 0.003 3.50818 -v -0.0350326 0.0174173 3.51355 -v -0.10025 0.0229813 3.5475 -v -0.0970845 0.0171289 3.5612 -v -0.0957734 0.003 3.56687 -v -0.0970845 -0.0111289 3.5612 -v -0.10025 -0.0169813 3.5475 -v -0.103415 -0.0111289 3.5338 -v -0.104727 0.003 3.52813 -v -0.103415 0.0171289 3.5338 -v -0.1735 0.0192929 3.556 -v -0.173106 0.0145208 3.56747 -v -0.172942 0.003 3.57223 -v -0.173106 -0.00852083 3.56747 -v -0.1735 -0.0132929 3.556 -v -0.173894 -0.00852083 3.54452 -v -0.174058 0.003 3.53977 -v -0.173894 0.0145208 3.54452 -v -0.235875 0.010649 3.557 -v -0.235943 0.00840138 3.56243 -v -0.235972 0.00297517 3.56467 -v -0.235943 -0.00245105 3.56243 -v -0.235875 -0.00469866 3.557 -v -0.235807 -0.00245105 3.55157 -v -0.235778 0.00297517 3.54933 -v -0.235807 0.00840138 3.55157 -v -0.24875 0.00281127 3.557 -v 0.02 0.0233891 -3.551 -v 0.00558274 0.0174173 -3.551 -v -0.000389087 0.003 -3.551 -v 0.00558274 -0.0114173 -3.551 -v 0.02 -0.0173891 -3.551 -v 0.0344173 -0.0114173 -3.551 -v 0.0403891 0.003 -3.551 -v 0.0344173 0.0174173 -3.551 -v -0.209024 0.0141993 3.56164 -v -0.208976 0.0141993 3.55236 -v -0.209 0.0151601 3.557 -v -0.136125 0.0202759 3.56006 -v -0.173287 0.0180056 3.56219 -v -0.209058 0.0076389 3.5682 -v -0.209044 0.0115985 3.5656 -v -0.244748 0.00733716 3.55883 -v -0.235788 0.0101966 3.55999 -v -0.134888 0.0101559 3.57003 -v -0.172986 0.00921554 3.57094 -v -0.209058 -0.0016389 3.5682 -v -0.209063 0.003 3.56916 -v -0.244748 0.00474996 3.56142 -v -0.235842 0.00596929 3.56422 -v -0.134888 -0.00415592 3.57003 -v -0.172986 -0.00321554 3.57094 -v -0.209024 -0.0081993 3.56164 -v -0.209044 -0.00559846 3.5656 -v -0.244748 0.00109111 3.56142 -v -0.235842 -9.01913e-006 3.56422 -v -0.136125 -0.0142759 3.56006 -v -0.173287 -0.0120056 3.56219 -v -0.208976 -0.0081993 3.55236 -v -0.209 -0.00916005 3.557 -v -0.244748 -0.00149609 3.55883 -v -0.235788 -0.00423632 3.55999 -v -0.137875 -0.0142759 3.54594 -v -0.173713 -0.0120056 3.54981 -v -0.208942 -0.0016389 3.5458 -v -0.208956 -0.00559846 3.5484 -v -0.244748 -0.00149609 3.55517 -v -0.235712 -0.00423632 3.55401 -v -0.139112 -0.00415592 3.53596 -v -0.174014 -0.00321554 3.54105 -v -0.208942 0.0076389 3.5458 -v -0.208937 0.003 3.54484 -v -0.244748 0.00109111 3.55258 -v -0.235658 -9.01913e-006 3.54978 -v -0.139112 0.0101559 3.53596 -v -0.174014 0.00921554 3.54105 -v -0.208956 0.0115985 3.5484 -v -0.244748 0.00474996 3.55258 -v -0.235658 0.00596929 3.54978 -v -0.137875 0.0202759 3.54594 -v -0.173713 0.0180056 3.54981 -v -0.244748 0.00733716 3.55517 -v -0.235712 0.0101966 3.55401 -v -0.246248 0.00704938 3.557 -v -0.246248 0.00583425 3.55993 -v -0.246248 0.00290067 3.56115 -v -0.246248 -3.29167e-005 3.55993 -v -0.246248 -0.00124805 3.557 -v -0.246248 -3.29167e-005 3.55407 -v -0.246248 0.00290067 3.55285 -v -0.246248 0.00583425 3.55407 -v -0.137 0.021758 3.553 -v -0.0615432 0.0217782 3.54634 -v -0.0985422 0.0214026 3.55489 -v -0.135378 0.0162639 3.56608 -v -0.0664567 0.0217782 3.53166 -v -0.064 0.0233891 3.539 -v 0.00823424 0.0217782 3.5154 -v -0.0257454 0.0217782 3.53349 -v -0.058069 0.0107782 3.55673 -v -0.0594463 0.0174173 3.55261 -v -0.000234232 0.0217782 3.5026 -v 0.00400001 0.0233891 3.509 -v 0.0640204 0.0217782 3.46479 -v 0.038716 0.0217782 3.49239 -v 0.0142223 0.0107782 3.52444 -v 0.0118484 0.0174173 3.52086 -v 0.0519796 0.0217782 3.45521 -v 0.058 0.0233891 3.46 -v 0.0970668 0.0217782 3.39815 -v 0.0836399 0.0217782 3.43318 -v 0.0725345 0.0107782 3.47156 -v 0.0691592 0.0174173 3.46888 -v 0.0829332 0.0217782 3.39185 -v 0.09 0.0233891 3.395 -v 0.108559 0.0217782 3.32368 -v 0.105105 0.0217782 3.36116 -v 0.107061 0.0107782 3.4026 -v 0.103099 0.0174173 3.40083 -v 0.0934411 0.0217782 3.32032 -v 0.101 0.0233891 3.322 -v 0.105749 0.0217782 3.24854 -v 0.108437 0.0217782 3.28603 -v 0.119249 0.0107782 3.32605 -v 0.115011 0.0174173 3.32511 -v 0.0902514 0.0217782 3.24746 -v 0.098 0.0233891 3.248 -v 0.0792486 0.0217782 3.10159 -v 0.0971378 0.0217782 3.1931 -v 0.116707 0.0107782 3.24931 -v 0.112362 0.0174173 3.249 -v 0.0637514 0.0217782 3.10241 -v 0.0715 0.0233891 3.102 -v 0.0447202 0.0217782 2.91805 -v 0.0593523 0.0217782 3.00094 -v 0.0902068 0.0107782 3.10102 -v 0.0858624 0.0174173 3.10125 -v 0.0292798 0.0217782 2.91995 -v 0.037 0.0233891 2.919 -v 0.0302492 0.0217782 2.79203 -v 0.0351024 0.0217782 2.84955 -v 0.0556382 0.0107782 2.91671 -v 0.0513098 0.0174173 2.91724 -v 0.0147508 0.0217782 2.79297 -v 0.0225 0.0233891 2.7925 -v 0.0283959 0.0217782 2.71676 -v 0.0412082 0.0107782 2.79136 -v 0.0368635 0.0174173 2.79162 -v 0.0277782 0.0217782 -3.551 -v -0.0961271 0.0106226 3.56534 -v -0.134707 0.003 3.5715 -v -0.0211428 0.0107782 3.54337 -v -0.058069 -0.00477817 3.55673 -v -0.0575602 0.003 3.55825 -v 0.0460925 0.0107782 3.50037 -v 0.0142223 -0.00477817 3.52444 -v 0.0150991 0.003 3.52577 -v 0.09303 0.0107782 3.43873 -v 0.0725345 -0.00477817 3.47156 -v 0.0737814 0.003 3.47255 -v 0.115507 0.0107782 3.36456 -v 0.107061 -0.00477817 3.4026 -v 0.108524 0.003 3.40325 -v 0.119308 0.0107782 3.28748 -v 0.119249 -0.00477817 3.32605 -v 0.120814 0.003 3.32639 -v 0.108116 0.0107782 3.19325 -v 0.116707 -0.00477817 3.24931 -v 0.118312 0.003 3.24942 -v 0.0702803 0.0107782 2.99979 -v 0.0902068 -0.00477817 3.10102 -v 0.0918115 0.003 3.10094 -v 0.0460307 0.0107782 2.84837 -v 0.0556382 -0.00477817 2.91671 -v 0.0572371 0.003 2.91652 -v 0.0393857 0.0107782 2.71659 -v 0.0412082 -0.00477817 2.79136 -v 0.0428131 0.003 2.79126 -v 0.0387782 0.0107782 -3.551 -v -0.0961271 -0.00462261 3.56534 -v -0.135378 -0.0102639 3.56608 -v -0.0211428 -0.00477817 3.54337 -v -0.0615432 -0.0157782 3.54634 -v -0.0594463 -0.0114173 3.55261 -v 0.0460925 -0.00477817 3.50037 -v 0.00823424 -0.0157782 3.5154 -v 0.0118484 -0.0114173 3.52086 -v 0.09303 -0.00477817 3.43873 -v 0.0640204 -0.0157782 3.46479 -v 0.0691592 -0.0114173 3.46888 -v 0.115507 -0.00477817 3.36456 -v 0.0970668 -0.0157782 3.39815 -v 0.103099 -0.0114173 3.40083 -v 0.119308 -0.00477817 3.28748 -v 0.108559 -0.0157782 3.32368 -v 0.115011 -0.0114173 3.32511 -v 0.108116 -0.00477817 3.19325 -v 0.105749 -0.0157782 3.24854 -v 0.112362 -0.0114173 3.249 -v 0.0702803 -0.00477817 2.99979 -v 0.0792486 -0.0157782 3.10159 -v 0.0858624 -0.0114173 3.10125 -v 0.0460307 -0.00477817 2.84837 -v 0.0447202 -0.0157782 2.91805 -v 0.0513098 -0.0114173 2.91724 -v 0.0393857 -0.00477817 2.71659 -v 0.0302492 -0.0157782 2.79203 -v 0.0368635 -0.0114173 2.79162 -v 0.0387782 -0.00477817 -3.551 -v -0.0985422 -0.0154026 3.55489 -v -0.137 -0.015758 3.553 -v -0.0257454 -0.0157782 3.53349 -v -0.0664567 -0.0157782 3.53166 -v -0.064 -0.0173891 3.539 -v 0.038716 -0.0157782 3.49239 -v -0.000234232 -0.0157782 3.5026 -v 0.00400001 -0.0173891 3.509 -v 0.0836399 -0.0157782 3.43318 -v 0.0519796 -0.0157782 3.45521 -v 0.058 -0.0173891 3.46 -v 0.105105 -0.0157782 3.36116 -v 0.0829332 -0.0157782 3.39185 -v 0.09 -0.0173891 3.395 -v 0.108437 -0.0157782 3.28603 -v 0.0934411 -0.0157782 3.32032 -v 0.101 -0.0173891 3.322 -v 0.0971378 -0.0157782 3.1931 -v 0.0902514 -0.0157782 3.24746 -v 0.098 -0.0173891 3.248 -v 0.0593523 -0.0157782 3.00094 -v 0.0637514 -0.0157782 3.10241 -v 0.0715 -0.0173891 3.102 -v 0.0351024 -0.0157782 2.84955 -v 0.0292798 -0.0157782 2.91995 -v 0.037 -0.0173891 2.919 -v 0.0283959 -0.0157782 2.71676 -v 0.0147508 -0.0157782 2.79297 -v 0.0225 -0.0173891 2.7925 -v 0.0277782 -0.0157782 -3.551 -v -0.101958 -0.0154026 3.54011 -v -0.138622 -0.0102639 3.53992 -v -0.0322546 -0.0157782 3.51951 -v -0.069931 -0.00477817 3.52127 -v -0.0685537 -0.0114173 3.52539 -v 0.028284 -0.0157782 3.48111 -v -0.00622225 -0.00477817 3.49356 -v -0.00384836 -0.0114173 3.49714 -v 0.0703601 -0.0157782 3.42532 -v 0.0434655 -0.00477817 3.44844 -v 0.0468408 -0.0114173 3.45112 -v 0.0903948 -0.0157782 3.35634 -v 0.0729393 -0.00477817 3.3874 -v 0.0769013 -0.0114173 3.38917 -v 0.093063 -0.0157782 3.28397 -v 0.0827513 -0.00477817 3.31795 -v 0.0869893 -0.0114173 3.31889 -v 0.0816122 -0.0157782 3.1929 -v 0.0792932 -0.00477817 3.24669 -v 0.0836376 -0.0114173 3.247 -v 0.0438977 -0.0157782 3.00256 -v 0.0527932 -0.00477817 3.10298 -v 0.0571376 -0.0114173 3.10275 -v 0.0196476 -0.0157782 2.8512 -v 0.0183618 -0.00477817 2.92129 -v 0.0226902 -0.0114173 2.92076 -v 0.0128541 -0.0157782 2.71699 -v 0.00379181 -0.00477817 2.79364 -v 0.00813647 -0.0114173 2.79338 -v 0.0122218 -0.0157782 -3.551 -v -0.104373 -0.00462261 3.52966 -v -0.139293 0.003 3.5345 -v -0.0368572 -0.00477817 3.50963 -v -0.069931 0.0107782 3.52127 -v -0.0704398 0.003 3.51975 -v 0.0209075 -0.00477817 3.47313 -v -0.00622225 0.0107782 3.49356 -v -0.00709914 0.003 3.49223 -v 0.06097 -0.00477817 3.41977 -v 0.0434655 0.0107782 3.44844 -v 0.0422186 0.003 3.44745 -v 0.0799931 -0.00477817 3.35294 -v 0.0729393 0.0107782 3.3874 -v 0.0714757 0.003 3.38675 -v 0.082192 -0.00477817 3.28252 -v 0.0827513 0.0107782 3.31795 -v 0.0811859 0.003 3.31761 -v 0.070634 -0.00477817 3.19275 -v 0.0792932 0.0107782 3.24669 -v 0.0776885 0.003 3.24658 -v 0.0329697 -0.00477817 3.00371 -v 0.0527932 0.0107782 3.10298 -v 0.0511885 0.003 3.10306 -v 0.0087193 -0.00477817 2.85238 -v 0.0183618 0.0107782 2.92129 -v 0.0167629 0.003 2.92148 -v 0.00186432 -0.00477817 2.71716 -v 0.00379181 0.0107782 2.79364 -v 0.0021869 0.003 2.79374 -v 0.00122183 -0.00477817 -3.551 -v -0.104373 0.0106226 3.52966 -v -0.138622 0.0162639 3.53992 -v -0.0368572 0.0107782 3.50963 -v -0.0685537 0.0174173 3.52539 -v 0.0209075 0.0107782 3.47313 -v -0.00384836 0.0174173 3.49714 -v 0.06097 0.0107782 3.41977 -v 0.0468408 0.0174173 3.45112 -v 0.0799931 0.0107782 3.35294 -v 0.0769013 0.0174173 3.38917 -v 0.082192 0.0107782 3.28252 -v 0.0869893 0.0174173 3.31889 -v 0.070634 0.0107782 3.19275 -v 0.0836376 0.0174173 3.247 -v 0.0329697 0.0107782 3.00371 -v 0.0571376 0.0174173 3.10275 -v 0.0087193 0.0107782 2.85238 -v 0.0226902 0.0174173 2.92076 -v 0.00186432 0.0107782 2.71716 -v 0.00813647 0.0174173 2.79338 -v 0.00122183 0.0107782 -3.551 -v -0.101958 0.0214026 3.54011 -v -0.0322546 0.0217782 3.51951 -v 0.028284 0.0217782 3.48111 -v 0.0703601 0.0217782 3.42532 -v 0.0903948 0.0217782 3.35634 -v 0.093063 0.0217782 3.28397 -v 0.0816122 0.0217782 3.1929 -v 0.0438977 0.0217782 3.00256 -v 0.0196476 0.0217782 2.8512 -v 0.0128541 0.0217782 2.71699 -v 0.0122218 0.0217782 -3.551 -f 108 89 114 -f 106 108 114 -f 81 108 106 -f 110 81 106 -f 110 106 112 -f 82 110 112 -f 106 114 90 -f 112 106 90 -f 111 90 120 -f 112 90 111 -f 116 112 111 -f 82 112 116 -f 111 118 83 -f 116 111 83 -f 118 120 91 -f 111 120 118 -f 118 126 117 -f 118 91 126 -f 83 117 122 -f 83 118 117 -f 122 124 84 -f 122 117 124 -f 117 92 124 -f 117 126 92 -f 92 132 123 -f 124 92 123 -f 124 123 128 -f 84 124 128 -f 123 130 85 -f 128 123 85 -f 132 93 130 -f 123 132 130 -f 138 129 130 -f 93 138 130 -f 129 134 85 -f 130 129 85 -f 136 86 134 -f 129 136 134 -f 94 136 129 -f 138 94 129 -f 94 135 136 -f 144 135 94 -f 135 140 136 -f 136 140 86 -f 142 87 135 -f 135 87 140 -f 144 142 135 -f 95 142 144 -f 149 142 95 -f 149 141 142 -f 141 146 87 -f 141 87 142 -f 147 146 141 -f 147 88 146 -f 96 141 149 -f 96 147 141 -f 107 147 96 -f 153 107 96 -f 151 88 147 -f 107 151 147 -f 81 151 107 -f 108 81 107 -f 108 107 153 -f 89 108 153 -f 155 154 97 -f 113 154 155 -f 113 89 154 -f 114 89 113 -f 114 113 155 -f 90 114 155 -f 156 155 97 -f 119 155 156 -f 120 155 119 -f 120 90 155 -f 91 119 156 -f 120 119 91 -f 156 97 157 -f 125 156 157 -f 91 125 126 -f 91 156 125 -f 126 157 92 -f 126 125 157 -f 97 158 131 -f 157 97 131 -f 157 131 132 -f 92 157 132 -f 131 158 93 -f 132 131 93 -f 97 159 137 -f 158 97 137 -f 137 138 93 -f 158 137 93 -f 159 94 138 -f 137 159 138 -f 160 143 159 -f 97 160 159 -f 159 144 94 -f 143 144 159 -f 143 95 144 -f 160 95 143 -f 161 160 97 -f 161 148 160 -f 148 95 160 -f 148 149 95 -f 161 149 148 -f 96 149 161 -f 154 161 97 -f 154 152 161 -f 153 96 161 -f 152 153 161 -f 89 152 154 -f 89 153 152 -f 162 81 110 -f 109 162 110 -f 73 162 109 -f 164 73 109 -f 164 109 165 -f 74 164 165 -f 109 110 82 -f 165 109 82 -f 167 73 164 -f 163 167 164 -f 65 167 163 -f 169 65 163 -f 169 163 171 -f 66 169 171 -f 171 163 74 -f 163 164 74 -f 173 65 169 -f 168 173 169 -f 57 173 168 -f 175 57 168 -f 175 168 177 -f 58 175 177 -f 177 168 66 -f 168 169 66 -f 174 57 175 -f 179 57 174 -f 181 179 174 -f 49 179 181 -f 50 174 183 -f 181 174 50 -f 183 175 58 -f 174 175 183 -f 180 49 181 -f 185 49 180 -f 187 185 180 -f 41 185 187 -f 42 180 189 -f 187 180 42 -f 189 181 50 -f 180 181 189 -f 186 41 187 -f 191 41 186 -f 193 191 186 -f 33 191 193 -f 34 186 195 -f 193 186 34 -f 195 187 42 -f 186 187 195 -f 192 33 193 -f 197 33 192 -f 199 197 192 -f 25 197 199 -f 26 192 201 -f 199 192 26 -f 201 193 34 -f 192 193 201 -f 198 25 199 -f 203 25 198 -f 205 203 198 -f 17 203 205 -f 18 198 207 -f 205 198 18 -f 207 199 26 -f 198 199 207 -f 204 17 205 -f 209 17 204 -f 211 209 204 -f 9 209 211 -f 10 204 213 -f 211 204 10 -f 213 205 18 -f 204 205 213 -f 210 9 211 -f 215 9 210 -f 1 215 210 -f 216 1 210 -f 216 210 218 -f 2 216 218 -f 218 211 10 -f 210 211 218 -f 165 82 116 -f 115 165 116 -f 74 165 115 -f 220 74 115 -f 75 220 221 -f 220 115 221 -f 221 115 83 -f 115 116 83 -f 171 74 220 -f 170 171 220 -f 66 171 170 -f 222 66 170 -f 67 222 224 -f 222 170 224 -f 224 170 75 -f 170 220 75 -f 177 66 222 -f 176 177 222 -f 58 177 176 -f 225 58 176 -f 225 176 227 -f 59 225 227 -f 227 176 67 -f 176 222 67 -f 182 58 225 -f 183 58 182 -f 228 183 182 -f 50 183 228 -f 228 182 51 -f 51 182 230 -f 230 225 59 -f 182 225 230 -f 188 50 228 -f 189 50 188 -f 231 189 188 -f 42 189 231 -f 231 188 43 -f 43 188 233 -f 188 228 233 -f 233 228 51 -f 194 42 231 -f 195 42 194 -f 234 195 194 -f 34 195 234 -f 234 194 35 -f 35 194 236 -f 194 231 236 -f 236 231 43 -f 200 34 234 -f 201 34 200 -f 237 201 200 -f 26 201 237 -f 27 200 239 -f 237 200 27 -f 200 234 239 -f 239 234 35 -f 207 26 237 -f 206 207 237 -f 18 207 206 -f 240 18 206 -f 240 206 242 -f 19 240 242 -f 206 237 27 -f 242 206 27 -f 213 18 240 -f 212 213 240 -f 243 10 212 -f 10 213 212 -f 243 212 245 -f 11 243 245 -f 212 240 19 -f 245 212 19 -f 218 10 243 -f 217 218 243 -f 2 218 217 -f 246 2 217 -f 246 217 248 -f 3 246 248 -f 217 243 11 -f 248 217 11 -f 83 122 121 -f 221 83 121 -f 221 121 250 -f 75 221 250 -f 121 251 76 -f 250 121 76 -f 122 84 251 -f 121 122 251 -f 75 250 223 -f 224 75 223 -f 252 224 223 -f 67 224 252 -f 68 223 254 -f 252 223 68 -f 250 76 254 -f 223 250 254 -f 226 67 252 -f 227 67 226 -f 59 227 255 -f 255 227 226 -f 60 226 257 -f 255 226 60 -f 252 68 257 -f 226 252 257 -f 230 59 255 -f 229 230 255 -f 51 230 229 -f 258 51 229 -f 52 258 260 -f 258 229 260 -f 229 255 60 -f 229 60 260 -f 233 51 258 -f 232 233 258 -f 43 233 232 -f 261 43 232 -f 44 261 263 -f 261 232 263 -f 232 258 52 -f 232 52 263 -f 236 43 261 -f 235 236 261 -f 35 236 235 -f 264 35 235 -f 36 264 266 -f 264 235 266 -f 235 261 44 -f 235 44 266 -f 239 35 264 -f 238 239 264 -f 27 239 238 -f 267 27 238 -f 28 267 269 -f 267 238 269 -f 238 264 36 -f 238 36 269 -f 241 27 267 -f 242 27 241 -f 270 242 241 -f 19 242 270 -f 20 241 272 -f 270 241 20 -f 267 28 272 -f 241 267 272 -f 244 19 270 -f 245 19 244 -f 273 245 244 -f 11 245 273 -f 12 244 275 -f 273 244 12 -f 270 20 275 -f 244 270 275 -f 247 11 273 -f 248 11 247 -f 276 248 247 -f 3 248 276 -f 276 247 4 -f 4 247 278 -f 273 12 278 -f 247 273 278 -f 84 128 127 -f 251 84 127 -f 251 127 280 -f 76 251 280 -f 127 281 77 -f 280 127 77 -f 128 85 281 -f 127 128 281 -f 76 280 253 -f 254 76 253 -f 282 254 253 -f 68 254 282 -f 69 253 284 -f 282 253 69 -f 280 77 284 -f 253 280 284 -f 256 68 282 -f 257 68 256 -f 285 257 256 -f 60 257 285 -f 61 256 287 -f 285 256 61 -f 287 282 69 -f 256 282 287 -f 260 60 285 -f 259 260 285 -f 52 260 259 -f 288 52 259 -f 53 288 290 -f 288 259 290 -f 259 285 61 -f 290 259 61 -f 263 52 288 -f 262 263 288 -f 44 263 262 -f 291 44 262 -f 45 291 293 -f 291 262 293 -f 262 288 53 -f 293 262 53 -f 266 44 291 -f 265 266 291 -f 36 266 265 -f 294 36 265 -f 37 294 296 -f 294 265 296 -f 265 291 45 -f 296 265 45 -f 269 36 294 -f 268 269 294 -f 28 269 268 -f 297 28 268 -f 29 297 299 -f 297 268 299 -f 268 294 37 -f 299 268 37 -f 272 28 297 -f 271 272 297 -f 20 272 271 -f 300 20 271 -f 21 300 302 -f 300 271 302 -f 271 297 29 -f 302 271 29 -f 275 20 300 -f 274 275 300 -f 12 275 274 -f 303 12 274 -f 13 303 305 -f 303 274 305 -f 274 300 21 -f 305 274 21 -f 278 12 303 -f 277 278 303 -f 306 278 277 -f 4 278 306 -f 5 277 308 -f 306 277 5 -f 277 303 13 -f 308 277 13 -f 134 133 281 -f 85 134 281 -f 281 310 77 -f 133 310 281 -f 133 78 310 -f 311 78 133 -f 86 311 133 -f 134 86 133 -f 77 283 284 -f 310 283 77 -f 312 69 284 -f 283 312 284 -f 70 312 283 -f 314 70 283 -f 310 314 283 -f 78 314 310 -f 286 287 69 -f 312 286 69 -f 315 61 287 -f 286 315 287 -f 62 315 286 -f 317 62 286 -f 317 286 312 -f 70 317 312 -f 315 290 61 -f 315 289 290 -f 289 318 53 -f 289 53 290 -f 320 318 289 -f 320 54 318 -f 62 289 315 -f 62 320 289 -f 318 293 53 -f 318 292 293 -f 292 321 45 -f 292 45 293 -f 323 321 292 -f 323 46 321 -f 54 292 318 -f 54 323 292 -f 321 296 45 -f 321 295 296 -f 295 324 37 -f 295 37 296 -f 326 324 295 -f 326 38 324 -f 46 295 321 -f 46 326 295 -f 324 299 37 -f 324 298 299 -f 298 327 29 -f 298 29 299 -f 329 327 298 -f 329 30 327 -f 38 298 324 -f 38 329 298 -f 327 302 29 -f 327 301 302 -f 301 330 21 -f 301 21 302 -f 332 330 301 -f 332 22 330 -f 30 301 327 -f 30 332 301 -f 330 305 21 -f 330 304 305 -f 304 333 13 -f 304 13 305 -f 335 333 304 -f 335 14 333 -f 22 304 330 -f 22 335 304 -f 333 308 13 -f 333 307 308 -f 336 5 308 -f 307 336 308 -f 6 336 307 -f 338 6 307 -f 14 307 333 -f 14 338 307 -f 86 139 311 -f 140 139 86 -f 311 340 78 -f 139 340 311 -f 341 79 139 -f 139 79 340 -f 87 341 140 -f 140 341 139 -f 78 313 314 -f 340 313 78 -f 342 70 314 -f 313 342 314 -f 344 71 313 -f 71 342 313 -f 79 344 340 -f 340 344 313 -f 70 316 317 -f 342 316 70 -f 345 62 317 -f 316 345 317 -f 63 345 316 -f 347 63 316 -f 347 316 342 -f 71 347 342 -f 62 345 320 -f 345 319 320 -f 319 348 54 -f 319 54 320 -f 350 348 319 -f 350 55 348 -f 63 319 345 -f 63 350 319 -f 54 348 323 -f 348 322 323 -f 322 351 46 -f 322 46 323 -f 353 351 322 -f 353 47 351 -f 55 322 348 -f 55 353 322 -f 46 351 326 -f 351 325 326 -f 325 354 38 -f 325 38 326 -f 356 354 325 -f 356 39 354 -f 47 325 351 -f 47 356 325 -f 38 354 329 -f 354 328 329 -f 328 357 30 -f 328 30 329 -f 359 357 328 -f 359 31 357 -f 39 328 354 -f 39 359 328 -f 30 331 332 -f 357 331 30 -f 360 22 332 -f 331 360 332 -f 23 360 331 -f 362 23 331 -f 362 331 357 -f 31 362 357 -f 22 334 335 -f 360 334 22 -f 363 14 335 -f 334 363 335 -f 15 363 334 -f 365 15 334 -f 365 334 360 -f 23 365 360 -f 14 337 338 -f 363 337 14 -f 366 6 338 -f 337 366 338 -f 7 366 337 -f 368 7 337 -f 368 337 363 -f 15 368 363 -f 146 145 341 -f 146 341 87 -f 145 370 79 -f 145 79 341 -f 371 370 145 -f 371 80 370 -f 88 145 146 -f 88 371 145 -f 370 343 344 -f 370 344 79 -f 343 372 71 -f 343 71 344 -f 373 372 343 -f 373 72 372 -f 80 343 370 -f 80 373 343 -f 372 347 71 -f 372 346 347 -f 346 63 347 -f 346 374 63 -f 375 374 346 -f 375 64 374 -f 72 346 372 -f 72 375 346 -f 349 350 63 -f 374 349 63 -f 376 55 350 -f 349 376 350 -f 56 376 349 -f 377 56 349 -f 377 349 374 -f 64 377 374 -f 352 353 55 -f 376 352 55 -f 378 47 353 -f 352 378 353 -f 48 378 352 -f 379 48 352 -f 379 352 376 -f 56 379 376 -f 355 356 47 -f 378 355 47 -f 380 39 356 -f 355 380 356 -f 40 380 355 -f 381 40 355 -f 381 355 378 -f 48 381 378 -f 358 359 39 -f 380 358 39 -f 382 31 359 -f 358 382 359 -f 32 382 358 -f 383 32 358 -f 383 358 380 -f 40 383 380 -f 382 362 31 -f 382 361 362 -f 361 23 362 -f 361 384 23 -f 385 384 361 -f 385 24 384 -f 32 361 382 -f 32 385 361 -f 384 365 23 -f 384 364 365 -f 364 15 365 -f 364 386 15 -f 387 16 386 -f 387 386 364 -f 24 364 384 -f 24 387 364 -f 386 368 15 -f 386 367 368 -f 367 7 368 -f 367 388 7 -f 389 388 367 -f 389 8 388 -f 16 367 386 -f 16 389 367 -f 150 371 88 -f 151 150 88 -f 150 80 371 -f 150 391 80 -f 162 391 150 -f 162 73 391 -f 162 150 151 -f 81 162 151 -f 391 166 373 -f 391 373 80 -f 166 72 373 -f 166 392 72 -f 167 392 166 -f 167 65 392 -f 73 166 391 -f 73 167 166 -f 392 172 375 -f 392 375 72 -f 172 64 375 -f 172 393 64 -f 173 393 172 -f 173 57 393 -f 65 172 392 -f 65 173 172 -f 178 377 64 -f 393 178 64 -f 394 56 377 -f 178 394 377 -f 49 394 178 -f 179 49 178 -f 179 178 393 -f 57 179 393 -f 184 379 56 -f 394 184 56 -f 395 48 379 -f 184 395 379 -f 41 395 184 -f 185 41 184 -f 185 184 394 -f 49 185 394 -f 190 381 48 -f 395 190 48 -f 396 40 381 -f 190 396 381 -f 33 396 190 -f 191 33 190 -f 191 190 395 -f 41 191 395 -f 196 383 40 -f 396 196 40 -f 397 32 383 -f 196 397 383 -f 25 397 196 -f 197 25 196 -f 197 196 396 -f 33 197 396 -f 202 385 32 -f 397 202 32 -f 398 24 385 -f 202 398 385 -f 17 398 202 -f 203 17 202 -f 203 202 397 -f 25 203 397 -f 208 387 24 -f 398 208 24 -f 399 16 387 -f 208 399 387 -f 9 399 208 -f 209 9 208 -f 209 208 398 -f 17 209 398 -f 214 389 16 -f 399 214 16 -f 214 8 389 -f 214 400 8 -f 215 400 214 -f 215 1 400 -f 215 214 399 -f 9 215 399 -f 105 2 246 -f 249 105 246 -f 249 246 3 -f 104 249 3 -f 104 3 279 -f 279 3 276 -f 279 276 103 -f 276 4 103 -f 103 4 309 -f 309 4 306 -f 309 306 102 -f 102 306 5 -f 339 102 5 -f 336 339 5 -f 101 339 336 -f 6 101 336 -f 6 369 101 -f 366 369 6 -f 7 100 366 -f 100 369 366 -f 388 390 100 -f 388 100 7 -f 8 99 390 -f 8 390 388 -f 400 401 99 -f 400 99 8 -f 1 401 400 -f 1 98 401 -f 219 98 216 -f 98 1 216 -f 105 219 2 -f 219 216 2 diff --git a/applications/plugins/SensableEmulation/examples/testOmniDriverEmu.scn b/applications/plugins/SensableEmulation/examples/testOmniDriverEmu.scn deleted file mode 100644 index e27e25b8c6f..00000000000 --- a/applications/plugins/SensableEmulation/examples/testOmniDriverEmu.scn +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/SensableEmulation/pthread/pthread.h b/applications/plugins/SensableEmulation/pthread/pthread.h deleted file mode 100644 index b4072f72c6f..00000000000 --- a/applications/plugins/SensableEmulation/pthread/pthread.h +++ /dev/null @@ -1,1368 +0,0 @@ -/* This is an implementation of the threads API of POSIX 1003.1-2001. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#if !defined( PTHREAD_H ) -#define PTHREAD_H - -/* - * See the README file for an explanation of the pthreads-win32 version - * numbering scheme and how the DLL is named etc. - */ -#define PTW32_VERSION 2,9,1,0 -#define PTW32_VERSION_STRING "2, 9, 1, 0\0" - -/* There are three implementations of cancel cleanup. - * Note that pthread.h is included in both application - * compilation units and also internally for the library. - * The code here and within the library aims to work - * for all reasonable combinations of environments. - * - * The three implementations are: - * - * WIN32 SEH - * C - * C++ - * - * Please note that exiting a push/pop block via - * "return", "exit", "break", or "continue" will - * lead to different behaviour amongst applications - * depending upon whether the library was built - * using SEH, C++, or C. For example, a library built - * with SEH will call the cleanup routine, while both - * C++ and C built versions will not. - */ - -/* - * Define defaults for cleanup code. - * Note: Unless the build explicitly defines one of the following, then - * we default to standard C style cleanup. This style uses setjmp/longjmp - * in the cancelation and thread exit implementations and therefore won't - * do stack unwinding if linked to applications that have it (e.g. - * C++ apps). This is currently consistent with most/all commercial Unix - * POSIX threads implementations. - */ -#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) -# define __CLEANUP_C -#endif - -#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) -#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. -#endif - -/* - * Stop here if we are being included by the resource compiler. - */ -#if !defined(RC_INVOKED) - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#if defined(_UWIN) -# define HAVE_STRUCT_TIMESPEC 1 -# define HAVE_SIGNAL_H 1 -# undef HAVE_PTW32_CONFIG_H -# pragma comment(lib, "pthread") -#endif - -/* - * ------------------------------------------------------------- - * - * - * Module: pthread.h - * - * Purpose: - * Provides an implementation of PThreads based upon the - * standard: - * - * POSIX 1003.1-2001 - * and - * The Single Unix Specification version 3 - * - * (these two are equivalent) - * - * in order to enhance code portability between Windows, - * various commercial Unix implementations, and Linux. - * - * See the ANNOUNCE file for a full list of conforming - * routines and defined constants, and a list of missing - * routines and constants not defined in this implementation. - * - * Authors: - * There have been many contributors to this library. - * The initial implementation was contributed by - * John Bossom, and several others have provided major - * sections or revisions of parts of the implementation. - * Often significant effort has been contributed to - * find and fix important bugs and other problems to - * improve the reliability of the library, which sometimes - * is not reflected in the amount of code which changed as - * result. - * As much as possible, the contributors are acknowledged - * in the ChangeLog file in the source code distribution - * where their changes are noted in detail. - * - * Contributors are listed in the CONTRIBUTORS file. - * - * As usual, all bouquets go to the contributors, and all - * brickbats go to the project maintainer. - * - * Maintainer: - * The code base for this project is coordinated and - * eventually pre-tested, packaged, and made available by - * - * Ross Johnson - * - * QA Testers: - * Ultimately, the library is tested in the real world by - * a host of competent and demanding scientists and - * engineers who report bugs and/or provide solutions - * which are then fixed or incorporated into subsequent - * versions of the library. Each time a bug is fixed, a - * test case is written to prove the fix and ensure - * that later changes to the code don't reintroduce the - * same error. The number of test cases is slowly growing - * and therefore so is the code reliability. - * - * Compliance: - * See the file ANNOUNCE for the list of implemented - * and not-implemented routines and defined options. - * Of course, these are all defined is this file as well. - * - * Web site: - * The source code and other information about this library - * are available from - * - * http://sources.redhat.com/pthreads-win32/ - * - * ------------------------------------------------------------- - */ - -/* Try to avoid including windows.h */ -#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus) -#define PTW32_INCLUDE_WINDOWS_H -#endif - -#if defined(PTW32_INCLUDE_WINDOWS_H) -#include -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) -/* - * VC++6.0 or early compiler's header has no DWORD_PTR type. - */ -typedef unsigned long DWORD_PTR; -typedef unsigned long ULONG_PTR; -#endif -/* - * ----------------- - * autoconf switches - * ----------------- - */ - -#if defined(HAVE_PTW32_CONFIG_H) -#include "config.h" -#endif /* HAVE_PTW32_CONFIG_H */ - -#if !defined(NEED_FTIME) -#include -#else /* NEED_FTIME */ -/* use native WIN32 time API */ -#endif /* NEED_FTIME */ - -#if defined(HAVE_SIGNAL_H) -#include -#endif /* HAVE_SIGNAL_H */ - -#include - -/* - * Boolean values to make us independent of system includes. - */ -enum { - PTW32_FALSE = 0, - PTW32_TRUE = (! PTW32_FALSE) -}; - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#if !defined(PTW32_CONFIG_H) -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(__MINGW64__) -# define HAVE_STRUCT_TIMESPEC -# define HAVE_MODE_T -# elif defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#if defined(NEED_ERRNO) -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Several systems don't define some error numbers. - */ -#if !defined(ENOTSUP) -# define ENOTSUP 48 /* This is the value in Solaris. */ -#endif - -#if !defined(ETIMEDOUT) -# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ -#endif - -#if !defined(ENOSYS) -# define ENOSYS 140 /* Semi-arbitrary value */ -#endif - -#if !defined(EDEADLK) -# if defined(EDEADLOCK) -# define EDEADLK EDEADLOCK -# else -# define EDEADLK 36 /* This is the value in MSVC. */ -# endif -#endif - -/* POSIX 2008 - related to robust mutexes */ -#if !defined(EOWNERDEAD) -# define EOWNERDEAD 43 -#endif -#if !defined(ENOTRECOVERABLE) -# define ENOTRECOVERABLE 44 -#endif - -#include - -/* - * To avoid including windows.h we define only those things that we - * actually need from it. - */ -#if !defined(PTW32_INCLUDE_WINDOWS_H) -#if !defined(HANDLE) -# define PTW32__HANDLE_DEF -# define HANDLE void * -#endif -#if !defined(DWORD) -# define PTW32__DWORD_DEF -# define DWORD unsigned long -#endif -#endif - -#if !defined(HAVE_STRUCT_TIMESPEC) -#define HAVE_STRUCT_TIMESPEC -#if !defined(_TIMESPEC_DEFINED) -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif /* _TIMESPEC_DEFINED */ -#endif /* HAVE_STRUCT_TIMESPEC */ - -#if !defined(SIG_BLOCK) -#define SIG_BLOCK 0 -#endif /* SIG_BLOCK */ - -#if !defined(SIG_UNBLOCK) -#define SIG_UNBLOCK 1 -#endif /* SIG_UNBLOCK */ - -#if !defined(SIG_SETMASK) -#define SIG_SETMASK 2 -#endif /* SIG_SETMASK */ - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -/* - * ------------------------------------------------------------- - * - * POSIX 1003.1-2001 Options - * ========================= - * - * Options are normally set in , which is not provided - * with pthreads-win32. - * - * For conformance with the Single Unix Specification (version 3), all of the - * options below are defined, and have a value of either -1 (not supported) - * or 200112L (supported). - * - * These options can neither be left undefined nor have a value of 0, because - * either indicates that sysconf(), which is not implemented, may be used at - * runtime to check the status of the option. - * - * _POSIX_THREADS (== 200112L) - * If == 200112L, you can use threads - * - * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) - * If == 200112L, you can control the size of a thread's - * stack - * pthread_attr_getstacksize - * pthread_attr_setstacksize - * - * _POSIX_THREAD_ATTR_STACKADDR (== -1) - * If == 200112L, you can allocate and control a thread's - * stack. If not supported, the following functions - * will return ENOSYS, indicating they are not - * supported: - * pthread_attr_getstackaddr - * pthread_attr_setstackaddr - * - * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) - * If == 200112L, you can use realtime scheduling. - * This option indicates that the behaviour of some - * implemented functions conforms to the additional TPS - * requirements in the standard. E.g. rwlocks favour - * writers over readers when threads have equal priority. - * - * _POSIX_THREAD_PRIO_INHERIT (== -1) - * If == 200112L, you can create priority inheritance - * mutexes. - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PRIO_PROTECT (== -1) - * If == 200112L, you can create priority ceiling mutexes - * Indicates the availability of: - * pthread_mutex_getprioceiling - * pthread_mutex_setprioceiling - * pthread_mutexattr_getprioceiling - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprioceiling - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PROCESS_SHARED (== -1) - * If set, you can create mutexes and condition - * variables that can be shared with another - * process.If set, indicates the availability - * of: - * pthread_mutexattr_getpshared - * pthread_mutexattr_setpshared - * pthread_condattr_getpshared - * pthread_condattr_setpshared - * - * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) - * If == 200112L you can use the special *_r library - * functions that provide thread-safe behaviour - * - * _POSIX_READER_WRITER_LOCKS (== 200112L) - * If == 200112L, you can use read/write locks - * - * _POSIX_SPIN_LOCKS (== 200112L) - * If == 200112L, you can use spin locks - * - * _POSIX_BARRIERS (== 200112L) - * If == 200112L, you can use barriers - * - * + These functions provide both 'inherit' and/or - * 'protect' protocol, based upon these macro - * settings. - * - * ------------------------------------------------------------- - */ - -/* - * POSIX Options - */ -#undef _POSIX_THREADS -#define _POSIX_THREADS 200809L - -#undef _POSIX_READER_WRITER_LOCKS -#define _POSIX_READER_WRITER_LOCKS 200809L - -#undef _POSIX_SPIN_LOCKS -#define _POSIX_SPIN_LOCKS 200809L - -#undef _POSIX_BARRIERS -#define _POSIX_BARRIERS 200809L - -#undef _POSIX_THREAD_SAFE_FUNCTIONS -#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L - -#undef _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_ATTR_STACKSIZE 200809L - -/* - * The following options are not supported - */ -#undef _POSIX_THREAD_ATTR_STACKADDR -#define _POSIX_THREAD_ATTR_STACKADDR -1 - -#undef _POSIX_THREAD_PRIO_INHERIT -#define _POSIX_THREAD_PRIO_INHERIT -1 - -#undef _POSIX_THREAD_PRIO_PROTECT -#define _POSIX_THREAD_PRIO_PROTECT -1 - -/* TPS is not fully supported. */ -#undef _POSIX_THREAD_PRIORITY_SCHEDULING -#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 - -#undef _POSIX_THREAD_PROCESS_SHARED -#define _POSIX_THREAD_PROCESS_SHARED -1 - - -/* - * POSIX 1003.1-2001 Limits - * =========================== - * - * These limits are normally set in , which is not provided with - * pthreads-win32. - * - * PTHREAD_DESTRUCTOR_ITERATIONS - * Maximum number of attempts to destroy - * a thread's thread-specific data on - * termination (must be at least 4) - * - * PTHREAD_KEYS_MAX - * Maximum number of thread-specific data keys - * available per process (must be at least 128) - * - * PTHREAD_STACK_MIN - * Minimum supported stack size for a thread - * - * PTHREAD_THREADS_MAX - * Maximum number of threads supported per - * process (must be at least 64). - * - * SEM_NSEMS_MAX - * The maximum number of semaphores a process can have. - * (must be at least 256) - * - * SEM_VALUE_MAX - * The maximum value a semaphore can have. - * (must be at least 32767) - * - */ -#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 - -#undef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS - -#undef _POSIX_THREAD_KEYS_MAX -#define _POSIX_THREAD_KEYS_MAX 128 - -#undef PTHREAD_KEYS_MAX -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX - -#undef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 0 - -#undef _POSIX_THREAD_THREADS_MAX -#define _POSIX_THREAD_THREADS_MAX 64 - - /* Arbitrary value */ -#undef PTHREAD_THREADS_MAX -#define PTHREAD_THREADS_MAX 2019 - -#undef _POSIX_SEM_NSEMS_MAX -#define _POSIX_SEM_NSEMS_MAX 256 - - /* Arbitrary value */ -#undef SEM_NSEMS_MAX -#define SEM_NSEMS_MAX 1024 - -#undef _POSIX_SEM_VALUE_MAX -#define _POSIX_SEM_VALUE_MAX 32767 - -#undef SEM_VALUE_MAX -#define SEM_VALUE_MAX INT_MAX - - -#if defined(__GNUC__) && !defined(__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the library, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the library, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#if !defined(PTW32_STATIC_LIB) -# if defined(PTW32_BUILD) -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * The Open Watcom C/C++ compiler uses a non-standard calling convention - * that passes function args in registers unless __cdecl is explicitly specified - * in exposed function prototypes. - * - * We force all calls to cdecl even though this could slow Watcom code down - * slightly. If you know that the Watcom compiler will be used to build both - * the DLL and application, then you can probably define this as a null string. - * Remember that pthread.h (this file) is used for both the DLL and application builds. - */ -#define PTW32_CDECL __cdecl - -#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX -# include -#else -/* - * Generic handle type - intended to extend uniqueness beyond - * that available with a simple pointer. It should scale for either - * IA-32 or IA-64. - */ -typedef struct { - void * p; /* Pointer to actual object */ - unsigned int x; /* Extra information - reuse count etc */ -} ptw32_handle_t; - -typedef ptw32_handle_t pthread_t; -typedef struct pthread_attr_t_ * pthread_attr_t; -typedef struct pthread_once_t_ pthread_once_t; -typedef struct pthread_key_t_ * pthread_key_t; -typedef struct pthread_mutex_t_ * pthread_mutex_t; -typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; -typedef struct pthread_cond_t_ * pthread_cond_t; -typedef struct pthread_condattr_t_ * pthread_condattr_t; -#endif -typedef struct pthread_rwlock_t_ * pthread_rwlock_t; -typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; -typedef struct pthread_spinlock_t_ * pthread_spinlock_t; -typedef struct pthread_barrier_t_ * pthread_barrier_t; -typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; - -/* - * ==================== - * ==================== - * POSIX Threads - * ==================== - * ==================== - */ - -enum { -/* - * pthread_attr_{get,set}detachstate - */ - PTHREAD_CREATE_JOINABLE = 0, /* Default */ - PTHREAD_CREATE_DETACHED = 1, - -/* - * pthread_attr_{get,set}inheritsched - */ - PTHREAD_INHERIT_SCHED = 0, - PTHREAD_EXPLICIT_SCHED = 1, /* Default */ - -/* - * pthread_{get,set}scope - */ - PTHREAD_SCOPE_PROCESS = 0, - PTHREAD_SCOPE_SYSTEM = 1, /* Default */ - -/* - * pthread_setcancelstate paramters - */ - PTHREAD_CANCEL_ENABLE = 0, /* Default */ - PTHREAD_CANCEL_DISABLE = 1, - -/* - * pthread_setcanceltype parameters - */ - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_DEFERRED = 1, /* Default */ - -/* - * pthread_mutexattr_{get,set}pshared - * pthread_condattr_{get,set}pshared - */ - PTHREAD_PROCESS_PRIVATE = 0, - PTHREAD_PROCESS_SHARED = 1, - -/* - * pthread_mutexattr_{get,set}robust - */ - PTHREAD_MUTEX_STALLED = 0, /* Default */ - PTHREAD_MUTEX_ROBUST = 1, - -/* - * pthread_barrier_wait - */ - PTHREAD_BARRIER_SERIAL_THREAD = -1 -}; - -/* - * ==================== - * ==================== - * Cancelation - * ==================== - * ==================== - */ -#define PTHREAD_CANCELED ((void *)(size_t) -1) - - -/* - * ==================== - * ==================== - * Once Key - * ==================== - * ==================== - */ -#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} - -struct pthread_once_t_ -{ - int done; /* indicates if user function has been executed */ - void * lock; - int reserved1; - int reserved2; -}; - - -/* - * ==================== - * ==================== - * Object initialisers - * ==================== - * ==================== - */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) - -/* - * Compatibility with LinuxThreads - */ -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER - -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) - -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) - -#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) - - -/* - * Mutex types. - */ -enum -{ - /* Compatibility with LinuxThreads */ - PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, - /* For compatibility with POSIX */ - PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -}; - - -typedef struct ptw32_cleanup_t ptw32_cleanup_t; - -#if defined(_MSC_VER) -/* Disable MSVC 'anachronism used' warning */ -#pragma warning( disable : 4229 ) -#endif - -typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); - -#if defined(_MSC_VER) -#pragma warning( default : 4229 ) -#endif - -struct ptw32_cleanup_t -{ - ptw32_cleanup_callback_t routine; - void *arg; - struct ptw32_cleanup_t *prev; -}; - -#if defined(__CLEANUP_SEH) - /* - * WIN32 SEH version of cancel cleanup. - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ - _cleanup.arg = (_arg); \ - __try \ - { \ - -#define pthread_cleanup_pop( _execute ) \ - } \ - __finally \ - { \ - if( _execute || AbnormalTermination()) \ - { \ - (*(_cleanup.routine))( _cleanup.arg ); \ - } \ - } \ - } - -#else /* __CLEANUP_SEH */ - -#if defined(__CLEANUP_C) - - /* - * C implementation of PThreads cancel cleanup - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ - -#define pthread_cleanup_pop( _execute ) \ - (void) ptw32_pop_cleanup( _execute ); \ - } - -#else /* __CLEANUP_C */ - -#if defined(__CLEANUP_CXX) - - /* - * C++ version of cancel cleanup. - * - John E. Bossom. - */ - - class PThreadCleanup { - /* - * PThreadCleanup - * - * Purpose - * This class is a C++ helper class that is - * used to implement pthread_cleanup_push/ - * pthread_cleanup_pop. - * The destructor of this class automatically - * pops the pushed cleanup routine regardless - * of how the code exits the scope - * (i.e. such as by an exception) - */ - ptw32_cleanup_callback_t cleanUpRout; - void * obj; - int executeIt; - - public: - PThreadCleanup() : - cleanUpRout( 0 ), - obj( 0 ), - executeIt( 0 ) - /* - * No cleanup performed - */ - { - } - - PThreadCleanup( - ptw32_cleanup_callback_t routine, - void * arg ) : - cleanUpRout( routine ), - obj( arg ), - executeIt( 1 ) - /* - * Registers a cleanup routine for 'arg' - */ - { - } - - ~PThreadCleanup() - { - if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) - { - (void) (*cleanUpRout)( obj ); - } - } - - void execute( int exec ) - { - executeIt = exec; - } - }; - - /* - * C++ implementation of PThreads cancel cleanup; - * This implementation takes advantage of a helper - * class who's destructor automatically calls the - * cleanup routine if we exit our scope weirdly - */ -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ - (void *) (_arg) ); - -#define pthread_cleanup_pop( _execute ) \ - cleanup.execute( _execute ); \ - } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - -/* - * =============== - * =============== - * Methods - * =============== - * =============== - */ - -/* - * PThread Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, - int *detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, - void **stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, - size_t * stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, - int detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, - void *stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, - size_t stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, - int *); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, - int inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, - int * inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, - int *); - -/* - * PThread Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, - const pthread_attr_t * attr, - void *(PTW32_CDECL *start) (void *), - void *arg); - -PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); - -PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, - pthread_t t2); - -PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); - -PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, - void **value_ptr); - -PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, - int *oldstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, - int *oldtype); - -PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, - void (PTW32_CDECL *init_routine) (void)); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); - -PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, - ptw32_cleanup_callback_t routine, - void *arg); -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread Specific Data Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, - void (PTW32_CDECL *destructor) (void *)); - -PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); - -PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, - const void *value); - -PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); - - -/* - * Mutex Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, - int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( - pthread_mutexattr_t *attr, - int robust); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( - const pthread_mutexattr_t * attr, - int * robust); - -/* - * Barrier Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, - int pshared); - -/* - * Mutex Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, - const pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); - -/* - * Spinlock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); - -/* - * Barrier Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, - const pthread_barrierattr_t * attr, - unsigned int count); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); - -/* - * Condition Variable Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, - int pshared); - -/* - * Condition Variable Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, - const pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, - pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); - -/* - * Scheduling - */ -PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, - int policy, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, - int *policy, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); - -PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); - -/* - * Read-Write Lock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, - const pthread_rwlockattr_t *attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, - int pshared); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 - -/* - * Signal Functions. Should be defined in but MSVC and MinGW32 - * already have signal.h that don't define these. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); - -/* - * Non-portable functions - */ - -/* - * Compatibility with Linux. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, - int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, - int *kind); - -/* - * Possibly supported by other POSIX threads implementations - */ -PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); -PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); -PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); - -/* - * Useful if an application wants to statically link - * the lib rather than load the DLL at run-time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); - -/* - * Features that are auto-detected at load/run time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); -enum ptw32_features { - PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ - PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ -}; - -/* - * Register a system time change with the library. - * Causes the library to perform various functions - * in response to the change. Should be called whenever - * the application's top level window receives a - * WM_TIMECHANGE message. It can be passed directly to - * pthread_create() as a new thread if desired. - */ -PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); - -#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* - * Returns the Win32 HANDLE for the POSIX thread. - */ -PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); -/* - * Returns the win32 thread ID for POSIX thread. - */ -PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); - - -/* - * Protected Methods - * - * This function blocks until the given WIN32 handle - * is signaled or pthread_cancel had been called. - * This function allows the caller to hook into the - * PThreads cancel mechanism. It is implemented using - * - * WaitForMultipleObjects - * - * on 'waitHandle' and a manually reset WIN32 Event - * used to implement pthread_cancel. The 'timeout' - * argument to TimedWait is simply passed to - * WaitForMultipleObjects. - */ -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, - DWORD timeout); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread-Safe C Runtime Library Mappings. - */ -#if !defined(_UWIN) -# if defined(NEED_ERRNO) - PTW32_DLLPORT int * PTW32_CDECL _errno( void ); -# else -# if !defined(errno) -# if (defined(_MT) || defined(_DLL)) - __declspec(dllimport) extern int * __cdecl _errno(void); -# define errno (*_errno()) -# endif -# endif -# endif -#endif - -/* - * Some compiler environments don't define some things. - */ -#if defined(__BORLANDC__) -# define _ftime ftime -# define _timeb timeb -#endif - -#if defined(__cplusplus) - -/* - * Internal exceptions - */ -class ptw32_exception {}; -class ptw32_exception_cancel : public ptw32_exception {}; -class ptw32_exception_exit : public ptw32_exception {}; - -#endif - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* FIXME: This is only required if the library was built using SEH */ -/* - * Get internal SEH tag - */ -PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#if !defined(PTW32_BUILD) - -#if defined(__CLEANUP_SEH) - -/* - * Redefine the SEH __except keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#define __except( E ) \ - __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ - ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) - -#endif /* __CLEANUP_SEH */ - -#if defined(__CLEANUP_CXX) - -/* - * Redefine the C++ catch keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#if defined(_MSC_VER) - /* - * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' - * if you want Pthread-Win32 cancelation and pthread_exit to work. - */ - -#if !defined(PtW32NoCatchWarn) - -#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") -#pragma message("------------------------------------------------------------------") -#pragma message("When compiling applications with MSVC++ and C++ exception handling:") -#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") -#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") -#pragma message(" cancelation and pthread_exit to work. For example:") -#pragma message("") -#pragma message(" #if defined(PtW32CatchAll)") -#pragma message(" PtW32CatchAll") -#pragma message(" #else") -#pragma message(" catch(...)") -#pragma message(" #endif") -#pragma message(" {") -#pragma message(" /* Catchall block processing */") -#pragma message(" }") -#pragma message("------------------------------------------------------------------") - -#endif - -#define PtW32CatchAll \ - catch( ptw32_exception & ) { throw; } \ - catch( ... ) - -#else /* _MSC_VER */ - -#define catch( E ) \ - catch( ptw32_exception & ) { throw; } \ - catch( E ) - -#endif /* _MSC_VER */ - -#endif /* __CLEANUP_CXX */ - -#endif /* ! PTW32_BUILD */ - -#if defined(__cplusplus) -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#if defined(PTW32__HANDLE_DEF) -# undef HANDLE -#endif -#if defined(PTW32__DWORD_DEF) -# undef DWORD -#endif - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* ! RC_INVOKED */ - -#endif /* PTHREAD_H */ diff --git a/applications/plugins/SensableEmulation/pthread/pthreadVC2.dll b/applications/plugins/SensableEmulation/pthread/pthreadVC2.dll deleted file mode 100644 index fcb5d9dcc1c18b0be18845a34c3aaf0ae37be200..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55808 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 199309 -#undef PTW32_SCHED_LEVEL -#define PTW32_SCHED_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_SCHED_LEVEL -#define PTW32_SCHED_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_SCHED_LEVEL_MAX 3 - -#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) -#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX -/* Include everything */ -#endif - - -#if defined(__GNUC__) && !defined(__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the library, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the library, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#if !defined(PTW32_STATIC_LIB) -# if defined(PTW32_BUILD) -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#if !defined(PTW32_CONFIG_H) -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(__MINGW64__) -# define HAVE_STRUCT_TIMESPEC -# define HAVE_MODE_T -# elif defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX -#if defined(NEED_ERRNO) -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ - -#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) -# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX -/* For pid_t */ -# include -/* Required by Unix 98 */ -# include -# else - typedef int pid_t; -# endif -#else - typedef int pid_t; -#endif - -/* Thread scheduling policies */ - -enum { - SCHED_OTHER = 0, - SCHED_FIFO, - SCHED_RR, - SCHED_MIN = SCHED_OTHER, - SCHED_MAX = SCHED_RR -}; - -struct sched_param { - int sched_priority; -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -PTW32_DLLPORT int __cdecl sched_yield (void); - -PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); - -PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); - -PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); - -PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); - -/* - * Note that this macro returns ENOTSUP rather than - * ENOSYS as might be expected. However, returning ENOSYS - * should mean that sched_get_priority_{min,max} are - * not implemented as well as sched_rr_get_interval. - * This is not the case, since we just don't support - * round-robin scheduling. Therefore I have chosen to - * return the same value as sched_setscheduler when - * SCHED_RR is passed to it. - */ -#define sched_rr_get_interval(_pid, _interval) \ - ( errno = ENOTSUP, (int) -1 ) - - -#if defined(__cplusplus) -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_SCHED_LEVEL -#undef PTW32_SCHED_LEVEL_MAX - -#endif /* !_SCHED_H */ - diff --git a/applications/plugins/SensableEmulation/pthread/semaphore.h b/applications/plugins/SensableEmulation/pthread/semaphore.h deleted file mode 100644 index c6e9407e25b..00000000000 --- a/applications/plugins/SensableEmulation/pthread/semaphore.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Module: semaphore.h - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#if !defined( SEMAPHORE_H ) -#define SEMAPHORE_H - -#undef PTW32_SEMAPHORE_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_SEMAPHORE_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_SEMAPHORE_LEVEL -#define PTW32_SEMAPHORE_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_SEMAPHORE_LEVEL -#define PTW32_SEMAPHORE_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_SEMAPHORE_LEVEL_MAX 3 - -#if !defined(PTW32_SEMAPHORE_LEVEL) -#define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX -/* Include everything */ -#endif - -#if defined(__GNUC__) && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the library, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the library, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#if !defined(PTW32_STATIC_LIB) -# if defined(PTW32_BUILD) -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#if !defined(PTW32_CONFIG_H) -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(__MINGW64__) -# define HAVE_STRUCT_TIMESPEC -# define HAVE_MODE_T -# elif defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX -#if defined(NEED_ERRNO) -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */ - -#define _POSIX_SEMAPHORES - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -#if !defined(HAVE_MODE_T) -typedef unsigned int mode_t; -#endif - - -typedef struct sem_t_ * sem_t; - -PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, - int pshared, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, - const struct timespec * abstime); - -PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, - int count); - -PTW32_DLLPORT int __cdecl sem_open (const char * name, - int oflag, - mode_t mode, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_unlink (const char * name); - -PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, - int * sval); - -#if defined(__cplusplus) -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_SEMAPHORE_LEVEL -#undef PTW32_SEMAPHORE_LEVEL_MAX - -#endif /* !SEMAPHORE_H */ diff --git a/applications/plugins/SofaCUDA/CMakeLists.txt b/applications/plugins/SofaCUDA/CMakeLists.txt index 9ec20b48eda..ed1cb7f93d0 100644 --- a/applications/plugins/SofaCUDA/CMakeLists.txt +++ b/applications/plugins/SofaCUDA/CMakeLists.txt @@ -396,7 +396,7 @@ target_link_libraries(${PROJECT_NAME} Sofa.Component.MechanicalLoad ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17 cuda_std_17) if(Sofa.GL_FOUND) target_link_libraries(${PROJECT_NAME} Sofa.GL) diff --git a/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu b/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu index 89bd6e5d672..0617c7ee550 100644 --- a/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu +++ b/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu @@ -28,9 +28,6 @@ #include #include - -//#define NO_CUDA - cudaDeviceProp mycudaDeviceProp; @@ -43,139 +40,6 @@ namespace cuda { #endif -#ifdef NO_CUDA - -bool cudaCheck(cudaError_t, const char*) -{ - return true; -} - -bool cudaInitCalled = false; - -int mycudaInit(int) -{ - cudaInitCalled = true; - return 0; -} - -void mycudaMalloc(void **devPtr, size_t,int ) -{ - *devPtr = NULL; -} - -void mycudaMallocPitch(void **devPtr, size_t*, size_t, size_t) -{ - *devPtr = NULL; -} - -void mycudaFree(void *, int) -{ -} - -void mycudaMallocHost(void **hostPtr, size_t size) -{ - *hostPtr = malloc(size); -} - -void mycudaFreeHost(void *hostPtr) -{ - free(hostPtr); -} - -void mycudaMemcpyHostToDevice(void *, const void *, size_t, int) -{ -} - -void mycudaMemcpyDeviceToDevice(void *, const void *, size_t,int ) -{ -} - -void mycudaMemcpyDeviceToHost(void *, const void *, size_t,int ) -{ -} - -void mycudaMemcpyHostToDevice2D(void *, size_t, const void *, size_t, size_t, size_t) -{ -} - -void mycudaMemcpyDeviceToDevice2D(void *, size_t, const void *, size_t, size_t, size_t ) -{ -} - -void mycudaMemcpyDeviceToHost2D(void *, size_t, const void *, size_t, size_t, size_t) -{ -} - -void mycudaGLRegisterBufferObject(int) -{ -} - -void mycudaGLUnregisterBufferObject(int) -{ -} - -void mycudaGLMapBufferObject(void** ptr, int) -{ - *ptr = NULL; -} - -void mycudaGLUnmapBufferObject(int) -{ -} - -int mycudaGetnumDevices() -{ - return 0; -} - -int mycudaGetBufferDevice() -{ - return 0; -} - -void mycudaMemset(void *devPtr, int val, size_t size,int ) -{ -} - -void cuda_void_kernel() -{ -} - -#ifdef SOFA_GPU_CUBLAS -cusparseHandle_t getCusparseCtx() -{ - return NULL; -} - -cublasHandle_t getCublasCtx() -{ - return NULL; -} - -cusparseMatDescr_t getCusparseMatGeneralDescr() -{ - return NULL; -} - -cusparseMatDescr_t getCusparseMatTriangularLowerDescr() -{ - return NULL; -} - -cusparseMatDescr_t getCusparseMatTriangularUpperDescr() -{ - return NULL; -} - - -void SOFA_GPU_CUDA_API mycudaMemGetInfo(size_t * free,size_t * total) { - -} - -#endif //SOFA_GPU_CUBLAS - -#else - extern "C" { int SOFA_GPU_CUDA_API mycudaGetMultiProcessorCount(); @@ -513,8 +377,6 @@ void SOFA_GPU_CUDA_API mycudaMemGetInfo(size_t * free,size_t * total) { #endif //SOFA_GPU_CUBLAS -#endif - #if defined(__cplusplus) } // namespace cuda } // namespace gpu diff --git a/applications/plugins/SofaCarving/SofaCarving_test/SofaCarving_test.cpp b/applications/plugins/SofaCarving/SofaCarving_test/SofaCarving_test.cpp index 1424f4cca7f..5e8eef63918 100644 --- a/applications/plugins/SofaCarving/SofaCarving_test/SofaCarving_test.cpp +++ b/applications/plugins/SofaCarving/SofaCarving_test/SofaCarving_test.cpp @@ -61,9 +61,10 @@ class SofaCarving_test : public BaseSimulationTest void doCarvingWithPenetration(); /// Unload the scene - void TearDown() override + void doTearDown() override { - if (m_simu != nullptr && m_root != nullptr) { + if (m_root != nullptr) + { sofa::simulation::node::unload(m_root); } } diff --git a/applications/plugins/SofaDistanceGrid/src/SofaDistanceGrid/RegisterModelToCollisionFactory.cpp b/applications/plugins/SofaDistanceGrid/src/SofaDistanceGrid/RegisterModelToCollisionFactory.cpp index c6bf75f0684..6a0f20f31d5 100644 --- a/applications/plugins/SofaDistanceGrid/src/SofaDistanceGrid/RegisterModelToCollisionFactory.cpp +++ b/applications/plugins/SofaDistanceGrid/src/SofaDistanceGrid/RegisterModelToCollisionFactory.cpp @@ -35,6 +35,7 @@ using sofa::core::collision::Contact ; #include #include +#include #include "components/collision/DistanceGridCollisionModel.h" #include "components/collision/FFDDistanceGridDiscreteIntersection.h" diff --git a/applications/plugins/SofaSimpleGUI/CMakeLists.txt b/applications/plugins/SofaSimpleGUI/CMakeLists.txt deleted file mode 100644 index 6f8153328c4..00000000000 --- a/applications/plugins/SofaSimpleGUI/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 3.22) -project(SofaSimpleGUI) - -set(SOFASIMPLEGUI_VERSION 0.1) - -set(HEADER_FILES - Camera.h - Interactor.h - PickedPoint.h - SofaGL.h - SofaScene.h - SpringInteractor.h - VisualPickVisitor.h - config.h.in -) - -set(SOURCE_FILES - Camera.cpp - Interactor.cpp - SofaGL.cpp - SofaScene.cpp - SpringInteractor.cpp - VisualPickVisitor.cpp - initSimpleGUI.cpp -) - -sofa_find_package(Sofa.Component REQUIRED) -sofa_find_package(Eigen3 REQUIRED) -sofa_find_package(Sofa.GL REQUIRED) -sofa_find_package(Sofa.Simulation.Graph REQUIRED) - -add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Component Sofa.GL Sofa.Simulation.Graph) -target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen) - -set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${SOFASIMPLEGUI_VERSION}) - -## Install rules for the library and headers; CMake package configurations files -sofa_create_package_with_targets( - PACKAGE_NAME ${PROJECT_NAME} - PACKAGE_VERSION ${SOFASIMPLEGUI_VERSION} - TARGETS ${PROJECT_NAME} AUTO_SET_TARGET_PROPERTIES - INCLUDE_INSTALL_DIR ${PROJECT_NAME} - ) diff --git a/applications/plugins/SofaSimpleGUI/Camera.cpp b/applications/plugins/SofaSimpleGUI/Camera.cpp deleted file mode 100644 index 498cb77f94d..00000000000 --- a/applications/plugins/SofaSimpleGUI/Camera.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "Camera.h" -#include -#include -using std::cout; -using std::endl; - - -namespace sofa::simplegui -{ - -Camera::Camera() -{ - transform.matrix() = Eigen::Matrix4f::Identity(); - tb_tournerXY=0, tb_translaterXY=0, tb_bougerZ=0; -} - -void Camera::lookAt() -{ - - glMultMatrixf( transform.data() ); -} - -template inline T sqr(const T& t){ return t*t; } - -void Camera::viewAll( float xmin, float ymin, float zmin, float xmax, float ymax, float zmax ) -{ - Vec3 pmin(xmin,ymin,zmin), pmax(xmax,ymax,zmax); - Vec3 pcen = (pmin+pmax)*0.5; - Vec3 diag = pmax-pmin; - float radius = diag.norm(); - // cout<<"Camera, diag = " << diag.transpose() << endl; - // cout<<"Camera, scene radius = " << radius << endl; - - // Desired distance: distance * tan(a) = radius - float distance = 1.5 * radius / tan(fovy * M_PI/180); - // cout<<"Camera::viewAll, angle = " << fovy << ", tan = " << tan(fovy) << ", distance = " << distance << endl; - // cout<<"Camera::viewAll, xmin xmax ymin ymax zmin zmax = " << xmin << " " << xmax <<" "<fabs(dy) ) -// { // rotation z -// float angle = dx; -// Eigen::AngleAxisf rot( angle, Vec3(0,0,-1) ); -// transform.linear() = rot*transform.linear(); -// } -// else if( fabs(dy)>fabs(dx) ) -// { - transform.translation() += Vec3( 0,0, -dy/100); -// } - } - tb_ancienX = x; - tb_ancienY = y; - return true; - } - return false; -} - -Camera::Vec3 Camera::eye() const { - return - transform.linear().inverse() * transform.translation(); -} - - -} - diff --git a/applications/plugins/SofaSimpleGUI/Camera.h b/applications/plugins/SofaSimpleGUI/Camera.h deleted file mode 100644 index 1ef48542626..00000000000 --- a/applications/plugins/SofaSimpleGUI/Camera.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef SOFA_SIMPLEGUI_CAMERA_H -#define SOFA_SIMPLEGUI_CAMERA_H - -#include -#include - - -namespace sofa::simplegui -{ - -/** - * @brief The Camera class implements a simple viewpoint transformation, and its update using the mouse. - * Currently only one displacement mode is implemented, and it is not extensively tested. - * - * @author Francois Faure, 2014 - */ -class SOFA_SOFASIMPLEGUI_API Camera -{ -public: - typedef Eigen::Transform Transform; - typedef Eigen::Vector3f Vec3; - - enum {ButtonLeft, ButtonMiddle, ButtonRight}; - enum {ButtonDown,ButtonUp}; - - - Camera(); - - - /// Set the view point. Parameters correspond to gluLookAt. - /// Note that this just sets the parameters. The actual viewing transform is applied in void lookAt() . - void setlookAt( - float eyeX, float eyeY, float eyeZ, - float targetX, float targetY, float targetZ, - float upX, float upY, float upZ - ); - - /// Apply the viewing transform, typically just after glLoadIdentity() in the draw function. - void lookAt(); - - void viewAll( float xmin, float ymin, float zmin, float xmax, float ymax, float zmax ); - - /// Equivalent of gluPerspective. - /// Alternatively, the definition and the application of the projection matrix can be done separately using other functions. - /// @sa void setPerspective( float fovy, float ratio, float znear, float zfar ) @sa void perspective() - void perspective( float fovy, float ratio, float znear, float zfar ); - - /// Set the projection matrix, without applying it. Parameters correspond to gluPerspective. - /// Note that this just sets the parameters. The actual projection transform is applied in void perspective() . - void setPerspective( float fovy, float ratio, float znear, float zfar ); - - /// Apply the projection matrix defined in setPerspective, typically in the reshape function - void perspective(); - - - - - /// Set the camera displacement modes and return true. - bool handleMouseButton(int button, int state, int x, int y); - /// Displace the camera based on the mouse motion and return true. - bool handleMouseMotion(int x, int y); - - /// Center of the camera in world coordinates - Vec3 eye() const; - - /// Viewing matrix - const Transform& getTransform() const { return transform; } - -protected: - - Transform transform; ///< Viewing transform: world wrt camera, i.e. inverse of the camera pose - - // camera projection - float fovy, ratio, znear, zfar; // parameters of perspective - - - int tb_ancienX, tb_ancienY, tb_tournerXY, tb_translaterXY, tb_bougerZ; - -}; - - - -} - - -#endif // CAMERA_H diff --git a/applications/plugins/SofaSimpleGUI/Interactor.cpp b/applications/plugins/SofaSimpleGUI/Interactor.cpp deleted file mode 100644 index dd5eeceab22..00000000000 --- a/applications/plugins/SofaSimpleGUI/Interactor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "Interactor.h" -#include "PickedPoint.h" -#include "SofaScene.h" -#include -#include - -using namespace sofa; - - -namespace sofa::simplegui -{ - -Interactor::Interactor(const PickedPoint& picked) - : _pickedPoint( picked ) -{ - _interactionNode = sofa::simulation::getSimulation()->createNewNode("picked point interaction node"); -} - -Interactor::~Interactor() -{ - _interactionNode->execute(sofa::core::execparams::defaultInstance()); -} - -void Interactor::attach(SofaScene *scene) -{ - scene->insertInteractor(this); -} - -void Interactor::detach() -{ - _interactionNode->detachFromGraph(); -} - -} - diff --git a/applications/plugins/SofaSimpleGUI/Interactor.h b/applications/plugins/SofaSimpleGUI/Interactor.h deleted file mode 100644 index f7dd353a718..00000000000 --- a/applications/plugins/SofaSimpleGUI/Interactor.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef SOFA_Interactor_H -#define SOFA_Interactor_H - -#include -#include -#include "PickedPoint.h" - - -namespace sofa::simplegui -{ - -class SofaScene; - -using simulation::Node; - - -/** @brief Base class for all interactors. - * Interactors are sofa subgraphs used to apply actions to the scene, typically through user interaction. - * - * Note that they are not necessarily moved using the mouse, since there is no mouse or window coordinates in the API. - * @author Francois Faure, 2014 -*/ -class SOFA_SOFASIMPLEGUI_API Interactor -{ -protected: - Node::SPtr _interactionNode; ///< Scene node used to implement this - PickedPoint _pickedPoint; ///< The point attached to this - -public: - - typedef type::Vec3 Vec3; - - Interactor( const PickedPoint& picked ); - virtual ~Interactor(); - - /// Insert this in the scene as a child of the given node. If overloaded, this function should be called at the beginning of the overloaded function. - virtual void attach( SofaScene* ); - - /// Remove this from the scene, without destroying it. If overloaded, this function should be called at the end of the overloaded function. - virtual void detach(); - - /// Current interaction point - virtual Vec3 getPoint()=0; - - /// Displace the interaction to the given point - virtual void setPoint( const Vec3& p ) = 0; - - /// Root of the interactor graph - Node::SPtr getNode() { return _interactionNode; } - - /// Simulated point attached to this - const PickedPoint& getPickedPoint() const { return _pickedPoint; } -}; - -} - - -#endif // SOFA_Interactor_H diff --git a/applications/plugins/SofaSimpleGUI/PickedPoint.h b/applications/plugins/SofaSimpleGUI/PickedPoint.h deleted file mode 100644 index 640bb9079b9..00000000000 --- a/applications/plugins/SofaSimpleGUI/PickedPoint.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef GLPICKEDPOINT_H -#define GLPICKEDPOINT_H - -#include -#include -#include - -using sofa::core::behavior::BaseMechanicalState; -typedef std::size_t nat; -typedef sofa::type::Vec3 Vec3; - - -namespace sofa::simplegui -{ - -/** - * @brief The PickedPoint struct represents a vertex of a State, typically picked using the mouse. - * It is returned by the Sofa interface to the user application to set up an interaction. - * We call it valid if it corresponds to a valid index of an existing mechanical state, and invalid if not so (the pointer to the mechanical state is null) - * @author Francois Faure, 2014 - */ -struct SOFA_SOFASIMPLEGUI_API PickedPoint -{ - BaseMechanicalState::SPtr state; ///< the DOF of the picked object - nat index; ///< index of the particle picked - Vec3 point; ///< location of the picked particle in world space - - /// Conversion to boolean for easier test writing. True iff the PickedPoint is valid. Default value is converted to false. - operator bool() const { return state != NULL; } - - PickedPoint(BaseMechanicalState::SPtr state=0, nat index=0) - : state(state) - , index(index) - { } - - inline friend std::ostream& operator << ( std::ostream& out, const PickedPoint p){ - out << "state: " << p.state->getName() << ", index: " << p.index << ", point: " << p.point; - return out; - } - - /// Comparison operator used in maps - bool operator < (const PickedPoint& p ) const { - return state < p.state || index < p.index; - } - - /// Comparison operator used in maps - bool operator != (const PickedPoint& p ) const { - return *this

Examples - -- `glutOnePick`: A Sofa simulation within a basic Glut interface. The user can - click and drag one point at a time to interact with the simulaton. -- `qtSofa`: A Sofa simulation within a basic Qt interface. The user can click and - drag multiple points. -- `qtSofa/qtSofa.pro`: Project file for the same application, built as an - application which is not a sub-project of Sofa. See comments inside. -- `qtQuickSofa`: A Sofa simulation within a QtQuick interface. Not yet mature, may - be temporarily disabled. - - -

Dependencies

- -- Qt > 5.0 is necessary for qtQuickSofa - - -

Issues

- -- Currently there is no way to create interactors in plugins. They are created - by the user application. -- The application built using qtSofa/qtSofa.pro crashes at scene creation time, - while the same code running as a Sofa sub-project works fine. - -*/ diff --git a/applications/plugins/SofaSimpleGUI/SofaGL.cpp b/applications/plugins/SofaSimpleGUI/SofaGL.cpp deleted file mode 100644 index 24903830b67..00000000000 --- a/applications/plugins/SofaSimpleGUI/SofaGL.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include -#include "SofaGL.h" -#include "VisualPickVisitor.h" -#include -#include -#include -#include - -#include -using sofa::simulation::mechanicalvisitor::MechanicalPickParticlesVisitor; - -using std::cout; -using std::cerr; -using std::endl; - -namespace sofa { -using core::objectmodel::Tag; - -namespace simplegui { - -template inline T sqr(const T& t){ return t*t; } - - -SofaGL::SofaGL(SofaScene *s) : - _sofaScene(s) -{ - if(!_sofaScene) - { - std::cerr << "Error: you are trying to create a SofaGL object with a null SofaScene" << std::endl; - return; - } - - glewInit(); - - _vparams = sofa::core::visual::VisualParams::defaultInstance(); - _vparams->drawTool() = &_drawToolGL; - _vparams->setSupported(sofa::core::visual::API_OpenGL); - - _isPicking = false; - - - _sofaScene->initVisual(); -} - -void SofaGL::draw() -{ - glGetIntegerv (GL_VIEWPORT, _viewport); - glGetDoublev (GL_MODELVIEW_MATRIX, _mvmatrix); - glGetDoublev (GL_PROJECTION_MATRIX, _projmatrix); - - if(_vparams) - { - _vparams->viewport() = sofa::type::fixed_array(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); - SReal xmin,xmax,ymin,ymax,zmin,zmax; - _sofaScene->getBoundingBox(&xmin,&xmax,&ymin,&ymax,&zmin,&zmax); - _vparams->sceneBBox() = sofa::type::BoundingBox(xmin,xmax,ymin,ymax,zmin,zmax); - _vparams->setProjectionMatrix(_projmatrix); - _vparams->setModelViewMatrix(_mvmatrix); - } - - //_sofaScene->getSimulation()->updateVisual(_sofaScene->getSimulation()->GetRoot().get()); // needed to update normals and VBOs ! (i think it should be better if updateVisual() was called from draw(), why it is not already the case ?) - _sofaScene->updateVisual(); // needed to update normals and VBOs ! (i think it should be better if updateVisual() was called from draw(), why it is not already the case ?) - - if( _isPicking ){ - - // start picking - glSelectBuffer(BUFSIZE,selectBuf); - glRenderMode(GL_SELECT); - - glInitNames(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - gluPickMatrix(pickX,_viewport[3]-pickY,5,5,_viewport); - glMultMatrixd(_projmatrix); - glMatrixMode(GL_MODELVIEW); - - // draw - _vparams->pass() = sofa::core::visual::VisualParams::Std; - VisualPickVisitor pick ( _vparams ); - pick.setTags(_sofaScene->groot()->getTags()); - cerr<<"SofaGL::draw root used " << endl; - _sofaScene->groot()->execute ( &pick ); - - // stop picking - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glFlush(); - hits = glRenderMode(GL_RENDER); - if (hits != 0) - { - GLuint* buffer = selectBuf; - // process the hits - GLint i, j, numberOfNames=0; - GLuint names, *ptr, minZ,*ptrNames=nullptr; - - ptr = (GLuint *) buffer; - minZ = 0xffffffff; - for (i = 0; i < hits; i++) { - names = *ptr; - ptr++; - if (*ptr < minZ) { - numberOfNames = names; - minZ = *ptr; - ptrNames = ptr+2; - } - - ptr += names+2; - } - if (numberOfNames > 0) { - cerr << "You picked object "; - ptr = ptrNames; - for (j = 0; j < numberOfNames; j++,ptr++) { - cerr<< pick.names[*ptr] << " "; - } - } - else - cerr<<"You didn't click a snowman!"; - cerr<getSimulation()->draw(_vparams, _sofaScene->getSimulation()->GetRoot().get()); - draw(_vparams); -} - -void SofaGL::draw(sofa::core::visual::VisualParams* vparams) -{ - core::visual::VisualLoop* vloop = _sofaScene->groot()->getVisualLoop(); - assert(vloop); - if (!vparams) vparams = sofa::core::visual::VisualParams::defaultInstance(); - vparams->update(); - vloop->drawStep(vparams); -} - -void SofaGL::getPickDirection( GLdouble* dx, GLdouble* dy, GLdouble* dz, int x, int y ) -{ - // Intersection of the ray with the near and far planes - GLint realy = _viewport[3] - (GLint) y - 1; // convert coordinates from image space (y downward) to window space (y upward) - GLdouble wx, wy, wz; /* returned world x, y, z coords */ - gluUnProject ((GLdouble) x, (GLdouble) realy, 0.0, _mvmatrix, _projmatrix, _viewport, &wx, &wy, &wz); // z=0: near plane - //cout<<"World coords at z=0.0 are ("<groot()->getContext() ); - - PickedPoint pickedPoint; - if (!picker.particles.empty()) - { - sofa::core::behavior::BaseMechanicalState *mstate = picker.particles.begin()->second.first; - unsigned index = picker.particles.begin()->second.second; - - pickedPoint.state = mstate; - pickedPoint.index = index; - pickedPoint.point = Vec3(mstate->getPX(index), mstate->getPY(index), mstate->getPZ(index)); - } - - return pickedPoint; -} - - -Interactor* SofaGL::getInteractor( const PickedPoint& glpicked ) -{ - cout << "SofaGL::getInteractor, looking for " << glpicked << endl; - for( Picked_to_Interactor::iterator i=_picked_to_interactor.begin(); i!=_picked_to_interactor.end(); i++ ) - { - cout << "SofaGL::getInteractor, map contains " << (*i).first << endl; - } - if( _picked_to_interactor.find(glpicked)!=_picked_to_interactor.end() ) // there is already an interactor on this particle - { - return _picked_to_interactor[glpicked]; - } - else { // new interactor - return NULL; - } -} - - - -Interactor* SofaGL::pickInteractor( GLdouble ox, GLdouble oy, GLdouble oz, int x, int y ) -{ - - type::Vec3d origin(ox,oy,oz), direction; - getPickDirection(&direction[0],&direction[1],&direction[2],x,y); - double distance = 10.5, distanceGrowth = 0.1; // cone around the ray ???? - // cout<< "SofaScene::rayPick from origin " << origin << ", in direction " << direction << endl; - MechanicalPickParticlesVisitor picker(sofa::core::ExecParams::defaultInstance(), origin, direction, distance, distanceGrowth, sofa::core::objectmodel::Tag("!NoPicking") ); - picker.execute(_sofaScene->groot()->getContext()); - - if (!picker.particles.empty()) - { - PickedPoint pickedPoint(picker.particles.begin()->second.first, picker.particles.begin()->second.second); - if( _picked_to_interactor.find(pickedPoint)!=_picked_to_interactor.end() ) - return _picked_to_interactor[pickedPoint]; - } - - return NULL; -} - - -void SofaGL::attach( Interactor* interactor ) -{ - interactor->attach( _sofaScene ); - _picked_to_interactor[interactor->getPickedPoint()] = interactor; - // cout<<"SofaGL::attach "<< endl; _sofaScene->printGraph(); -} - -void SofaGL::move( Interactor* interactor, int x, int y) -{ - if( !interactor ) - return; - - // get the distance to the current point - Vec3 current = interactor->getPoint(); - GLdouble wcur[3]; // window coordinates of the current point - gluProject(current[0],current[1],current[2],_mvmatrix,_projmatrix,_viewport,wcur,wcur+1,wcur+2); - // cout << "current point = " << current << endl; - // cout<<"move anchor, distance = " << wcur[2] << endl; - - // compute and set the position of the new point - GLdouble p[3]; - gluUnProject ( x, _viewport[3]-y-1, wcur[2], _mvmatrix, _projmatrix, _viewport, &p[0], &p[1], &p[2]); // new position of the picked point - // cout<<"x="<< x <<", y="<< y <<", X="<detach(); - // cout<<"SofaGL::detach "<< endl; _sofaScene->printGraph(); -} - -void SofaGL::getSceneBBox( float* xmin, float* ymin, float* zmin, float* xmax, float* ymax, float* zmax ) -{ - SReal xm, xM, ym, yM, zm, zM; - _sofaScene->getBoundingBox(&xm,&xM,&ym,&yM,&zm,&zM); - - *xmin = helper::narrow_cast(xm); - *xmax = helper::narrow_cast(xM); - *ymin = helper::narrow_cast(ym); - *ymax = helper::narrow_cast(yM); - *zmin = helper::narrow_cast(zm); - *zmax = helper::narrow_cast(zM); -} - - -void SofaGL::viewAll( SReal* xcam, SReal* ycam, SReal* zcam, SReal* xcen, SReal* ycen, SReal* zcen, SReal a, SReal* nearPlane, SReal* farPlane) -{ - // scene center and radius - SReal xmin, xmax, ymin, ymax, zmin, zmax; - _sofaScene->getBoundingBox(&xmin,&xmax,&ymin,&ymax,&zmin,&zmax); - cout<<"SofaGL::viewAll, bounding box = ("<< xmin <<" "< -#include "SofaScene.h" -#include -#include - -#include "PickedPoint.h" -#include "SpringInteractor.h" - - -namespace sofa::simplegui -{ - -/** OpenGL interface to a SofaScene. - * This is not a viewer, this is an object used by a viewer to display a Sofa scene and to pick objects in it. - * It contains a pointer to the Sofa scene. Several viewers can be connected to a single scene through such interfaces. - * - * Picking returns a PickedPoint which describes a particle. - * It is up to the application to create the appropriate Interactor, which can then be inserted in the Sofa scene. - * This class provides the functions to attach/detach an interactor and move it. - * - * @author Francois Faure, 2014 - - */ -class SOFA_SOFASIMPLEGUI_API SofaGL -{ -public: - /** - * @param s The Sofa scene to interact with, the scene MUST already be opened ! - */ - SofaGL( SofaScene* s ); - /** - * @brief Draw the scene and stores the transformation matrices, for picking. - * This requires an OpenGL context. It is supposed to be used by the drawing method of a viewer, after setting the modelview matrix. - */ - void draw(); - /** - * @brief Compute the parameters to pass to gluPerspective to make the whole scene visible. - * The new camera center is set on the line from the current camera center to the scene center, at the appropriate distance. - * @param xcam Camera center (input-output) - * @param ycam Camera center (input-output) - * @param zcam Camera center (input-output) - * @param xcen Center of the scene (output) - * @param ycen Center of the scene (output) - * @param zcen Center of the scene (output) - * @param a Camera vertical angle (input) - * @param near Smaller than the nearest distance from the new camera center to the scene (output) - * @param far Larger than the nearest distance from the new camera center to the scene (output) - */ - void viewAll( SReal* xcam, SReal* ycam, SReal* zcam, SReal* xcen, SReal* ycen, SReal* zcen, SReal a, SReal* nearPlane, SReal* farPlane); - - /// Compute the bounding box of the scene - void getSceneBBox( float* xmin, float* ymin, float* zmin, float* xmax, float* ymax, float* zmax ); - - /// @name Interaction - /// @{ - /** @brief Try to pick a particle along a ray. - * The ray starts at the camera center and passes through point with coordinates x,y - * ox, oy, oz are the camera center in world coordinates. - * x,y in image coordinates (origin on top left). - * If a point is picked, the application may create an Interactor based on it. - * @return a valid PickedPoint if succeeded, an invalid PickedPoint if not. - */ - PickedPoint pick(GLdouble ox, GLdouble oy, GLdouble oz, int x, int y); - - - /** @brief Insert an interactor in the scene - * Does not check if it is already there, so be careful not to insert the same twice - */ - void attach( Interactor* ); - - /** - * @brief getInteractor - * @param picked - * @return Interactor acting on the given picked point, or NULL if none - */ - Interactor* getInteractor( const PickedPoint& picked ); - - - /** @brief Try to pick an Interactor along a ray. - * The ray starts at the camera center and passes through point with coordinates x,y - * ox, oy, oz are the camera center in world coordinates. - * x,y in image coordinates (origin on top left). - * @return Pointer if an Interactor is found, NULL if not. - */ - Interactor* pickInteractor(GLdouble ox, GLdouble oy, GLdouble oz, int x, int y); - - /** - * @brief move the interactor according to the mouse pointer. - * x,y in image coordinates (origin on top left). - */ - void move( Interactor*, int x, int y); - - /// Remove the interactor from the scene, without deleting it. - void detach(Interactor*); - - /// @} - - /** @brief Try to pick a displayed thing along a ray, using OpenGL picking. - * The ray starts at the camera center and passes through point with coordinates x,y in image coordinates (origin on top left). - * In this experimental implementation, this function just prints something on the standard output. - */ - void glPick(int x, int y); - - /** - * @brief getPickDirection Compute the direction of a button click, returned as a unit vector - * @param dx normalized direction - * @param dy normalized direction - * @param dz normalized direction - * @param x x-coordinate of the click - * @param y y-coordinate of the click (origin on top) - */ - void getPickDirection( GLdouble* dx, GLdouble* dy, GLdouble* dz, int x, int y ); - - -protected: - SofaScene* _sofaScene; - - // matrices used for picking - GLint _viewport[4]; - GLdouble _mvmatrix[16], _projmatrix[16]; - - // rendering tools - sofa::gl::DrawToolGL _drawToolGL; - sofa::core::visual::VisualParams* _vparams; - void draw(sofa::core::visual::VisualParams*); - - // Interaction tools - typedef std::map< PickedPoint, Interactor*> Picked_to_Interactor; - /** Currently available interactors, associated with picked points. - * The interactors are not necessarily being manipulated. Only one is typically manipulated at a given time. - */ - Picked_to_Interactor _picked_to_interactor; - Interactor* _drag; ///< The currently active interactor - - - - // OpenGL picking data - bool _isPicking; ///< if we are doing OpenGL picking - GLint pickX, pickY; // window coordinates of the pick point - enum {BUFSIZE=1024}; - GLuint selectBuf[BUFSIZE]; - GLint hits; - - -}; - -} - - -#endif // SOFA_NEWGUI_SofaGL_H diff --git a/applications/plugins/SofaSimpleGUI/SofaGlutAnt.zip b/applications/plugins/SofaSimpleGUI/SofaGlutAnt.zip deleted file mode 100644 index 02195aba1f63a340e5c706633438048aded8985f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5452 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 IxPQI<7o{uFi2wiq diff --git a/applications/plugins/SofaSimpleGUI/SofaScene.cpp b/applications/plugins/SofaSimpleGUI/SofaScene.cpp deleted file mode 100644 index 8cbf2a7abdc..00000000000 --- a/applications/plugins/SofaSimpleGUI/SofaScene.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "SofaScene.h" -#include "Interactor.h" -#include -using std::cerr; -using std::cout; -using std::endl; - -#include -#include -#include -#include -#include - -// sofa types should not be exposed -//typedef sofa::type::Vec3 Vec3; -//typedef sofa::component::container::MechanicalObject< defaulttype::Vec3Types > Vec3DOF; -typedef sofa::simulation::graph::DAGSimulation SofaSimulation; - - -namespace sofa::simplegui -{ - - -typedef sofa::type::Vec3 Vec3; -typedef sofa::component::statecontainer::MechanicalObject< defaulttype::Vec3Types > Vec3DOF; - - -SofaScene::SofaScene() -{ - _groot = _iroot = nullptr; - std::shared_ptr classVisualModel;// = NULL; - sofa::core::ObjectFactory::AddAlias("VisualModel", "OglModel", true, &classVisualModel); - - sofa::component::init(); -} - -void SofaScene::step( SReal dt) -{ - sofa::simulation::node::animate(_groot.get(),dt); -} - -void SofaScene::printGraph() -{ - sofa::simulation::node::print(_groot.get()); -} - -void SofaScene::loadPlugins( const std::vector& plugins ) -{ - for (const auto& plugin : plugins) - { - cout <<"SofaScene::init, loading plugin " << plugin << '\n'; - sofa::helper::system::PluginManager::getInstance().loadPlugin(plugin); - } - - sofa::helper::system::PluginManager::getInstance().init(); -} - -void SofaScene::open(const std::string& fileName ) -{ - // --- Create simulation graph --- - assert( !fileName.empty()); - - if(_groot) sofa::simulation::node::unload (_groot); - _groot = sofa::simulation::node::load( fileName.c_str() ).get(); - if(!_groot) - { - cerr << "loading failed" << endl; - return; - } - - _iroot = _groot->createChild("iroot").get(); - -// _currentFileName = fileName; - - sofa::simulation::node::init(_groot.get()); - - printGraph(); - SReal xm,xM,ym,yM,zm,zM; - getBoundingBox(&xm,&xM,&ym,&yM,&zm,&zM); - cout<<"SofaScene::setScene, xm="<addChild(node); - _iroot = _groot->createChild("iroot").get(); - sofa::simulation::node::init(_groot.get()); -} - -void SofaScene::reset() -{ - sofa::simulation::node::reset(_groot.get()); -} - -//void SofaScene::open(const char *filename) -//{ -// unload(_groot); - -// _groot = load( filename ); -// if(!_groot) -// { -// cerr << "loading failed" << endl; -// return; -// } - -// _iroot = _groot->createChild("iroot"); - -// _currentFileName = filename; - -// sofa::simulation::node::::init(_groot); -//// cout<<"SofaScene::init, scene loaded" << endl; -//// printGraph(); -//} - -void SofaScene::getBoundingBox( SReal* xmin, SReal* xmax, SReal* ymin, SReal* ymax, SReal* zmin, SReal* zmax ) -{ - SReal pmin[3], pmax[3]; - sofa::simulation::node::computeBBox( _groot.get(), pmin, pmax ); - *xmin = pmin[0]; *xmax = pmax[0]; - *ymin = pmin[1]; *ymax = pmax[1]; - *zmin = pmin[2]; *zmax = pmax[2]; -} - -void SofaScene::insertInteractor( Interactor * interactor ) -{ - if(_iroot) - _iroot->addChild(interactor->getNode()); -} - -simulation::Node* SofaScene::groot() { return _groot.get(); } - -void SofaScene::initVisual(){ - sofa::simulation::node::initTextures(_groot.get()); -} - -void SofaScene::updateVisual() -{ - sofa::simulation::node::updateVisual(_groot.get()); // needed to update normals and VBOs ! (i think it should be better if updateVisual() was called from draw(), why it is not already the case ?) -} - -//void SofaScene::draw( sofa::core::visual::VisualParams* v) -//{ -// if( v==NULL ) -// { -// -// } -// sofa::simulation::node::draw(_vparams, groot() ); -//} - - -} diff --git a/applications/plugins/SofaSimpleGUI/SofaScene.h b/applications/plugins/SofaSimpleGUI/SofaScene.h deleted file mode 100644 index 83de56ad63b..00000000000 --- a/applications/plugins/SofaSimpleGUI/SofaScene.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef SOFA_NEWGUI_SofaScene_H -#define SOFA_NEWGUI_SofaScene_H - -#include -#include -#include -#include - -namespace sofa { -namespace simulation { - class Simulation; -} - -namespace simplegui { - -class Interactor; - - -/** @brief A sofa scene graph with simulation functions. - * - * There are methods to initialize and update the visual models, but rendering must be performed externally, see e.g. class SofaGL. - * - * The typical life cycle is: - * - loadPlugins( list of plugin names ); - setScene( scenegraph ); or open(filename) - initVisual() - [ your main loop: ] - step(dt); - updateVisual(); - [ use a SofaGL object to display the simulated objects ] - - - * @author Francois Faure, 2014 - */ -class SOFA_SOFASIMPLEGUI_API SofaScene -{ -public: - /** - * @brief Initialize Sofa - */ - SofaScene(); - virtual ~SofaScene(){} - - /** - * @brief load the given plugin - * @param plugins names of the plugins - */ - void loadPlugins( const std::vector& plugins ); - /** - * @brief Load a scene file. The previous scene graph, if any, is deleted. - * @param fileName Scene file to load - */ - void open( const std::string& fileName ); - /** - * @brief Set the scene graph. The previous scene graph, if any, is deleted. - * @param graph the scene to simulate - */ - void setScene( simulation::Node* graph ); - /** - * @brief Print the scene graph on the standard output, for debugging. - */ - void printGraph(); - /** - * @brief Integrate time by one step and update the Sofa scene. - */ - void step( SReal dt ); - /** - * @brief restart from the beginning - */ - void reset(); - /** - * @brief Compute the bounding box of the simulated objects - * @param xmin min coordinate in the X direction - * @param xmax max coordinate in the X direction - * @param ymin etc. - * @param ymax - * @param zmin - * @param zmax - */ - void getBoundingBox( SReal* xmin, SReal* xmax, SReal* ymin, SReal* ymax, SReal* zmin, SReal* zmax ); - - /// To do once before rendering a scene, typically at initialization time - void initVisual(); - - /// Update the visual models. To do after animating and before rendering. - void updateVisual(); - - - - /** @name Developer API - * To be used to create new functionalities. - */ - ///@{ - - /// Root of the simulated scene. - simulation::Node* groot(); - - /// Root of the interactors, set as child of groot - simulation::Node* iroot(){ return _iroot; } - - /// Do not use this directly. Use Interactor::attach, which calls this. - void insertInteractor( Interactor* ); - - ///@} - - - - -protected: - simulation::Node::SPtr _groot; ///< root of the scene - simulation::Node* _iroot; ///< root of the interactors, child of _groot - -}; - -} -} - - -#endif // SOFA_NEWGUI_SofaScene_H diff --git a/applications/plugins/SofaSimpleGUI/SofaSimpleGUIConfig.cmake.in b/applications/plugins/SofaSimpleGUI/SofaSimpleGUIConfig.cmake.in deleted file mode 100644 index 25e069ed35b..00000000000 --- a/applications/plugins/SofaSimpleGUI/SofaSimpleGUIConfig.cmake.in +++ /dev/null @@ -1,15 +0,0 @@ -# CMake package configuration file for the SofaSimpleGUI plugin - -@PACKAGE_GUARD@ -@PACKAGE_INIT@ - -find_package(Sofa.Component REQUIRED) -find_package(Eigen3 QUIET REQUIRED) -find_package(Sofa.GL QUIET REQUIRED) -find_package(Sofa.Simulation.Graph QUIET REQUIRED) - -if(NOT TARGET SofaSimpleGUI) - include("${CMAKE_CURRENT_LIST_DIR}/SofaSimpleGUITargets.cmake") -endif() - -check_required_components(SofaSimpleGUI) diff --git a/applications/plugins/SofaSimpleGUI/SpringInteractor.cpp b/applications/plugins/SofaSimpleGUI/SpringInteractor.cpp deleted file mode 100644 index 0e6948d9743..00000000000 --- a/applications/plugins/SofaSimpleGUI/SpringInteractor.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "SpringInteractor.h" -#include "PickedPoint.h" -#include -#include -#include - - -namespace sofa::simplegui -{ -typedef sofa::component::constraint::projective::FixedConstraint FixedConstraint3; - -SpringInteractor::SpringInteractor(const PickedPoint &picked, SReal stiffness) - : Interactor(picked) -{ - // get the DOF of the picked object - MechanicalObject3* pickedDof=dynamic_cast(picked.state.get()); assert(pickedDof); - - // create DOF to represent the actuator - _interactorDof = sofa::core::objectmodel::New(); - _interactionNode->addObject(_interactorDof); - _interactorDof->setName("interactorDOF"); - _interactorDof->addTag(std::string("Interactor")); - MechanicalObject3::WriteVecCoord xanchor = _interactorDof->writePositions(); - xanchor[0] = picked.point; - FixedConstraint3::SPtr fixed= sofa::core::objectmodel::New(); // Makes it unmovable through forces - _interactionNode->addObject(fixed); - fixed->init(); - - // create spring to drag the picked object - _spring = sofa::core::objectmodel::New(_interactorDof.get(),pickedDof); - _interactionNode->addObject(_spring); - _spring->addSpring(0,picked.index,stiffness,0.1,0.); - - - -// cout << "SpringInteractor set spring to " << pickedDof->getName() << ", " << picked.index << endl; -} - -Vec3 SpringInteractor::getPoint() -{ - MechanicalObject3::ReadVecCoord xanchor = _interactorDof->readPositions(); - return xanchor[0]; -} - -void SpringInteractor::setPoint( const Vec3& p ) -{ - MechanicalObject3::WriteVecCoord xanchor = _interactorDof->writePositions(); - xanchor[0] = p; -} - -void SpringInteractor::attach(SofaScene *scene) -{ - Inherited::attach(scene); - _interactionNode->removeObject(_spring); - Node* targetParent = dynamic_cast(_spring->getMState2()->getContext()); - targetParent->addObject(_spring); -} - -void SpringInteractor::detach() -{ - Inherited::detach(); - Node* parent = dynamic_cast(_spring->getMState2()->getContext()); - parent->removeObject(_spring); - _interactionNode->addObject(_spring); -} - -} diff --git a/applications/plugins/SofaSimpleGUI/SpringInteractor.h b/applications/plugins/SofaSimpleGUI/SpringInteractor.h deleted file mode 100644 index ec3c187ccd8..00000000000 --- a/applications/plugins/SofaSimpleGUI/SpringInteractor.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef SOFA_SpringInteractor_H -#define SOFA_SpringInteractor_H - -#include -#include "Interactor.h" - -#include -#include -#include - - -namespace sofa::simplegui -{ - using sofa::defaulttype::Vec3Types ; - using MechanicalObject3 = sofa::component::statecontainer::MechanicalObject ; - using SpringForceField3 = sofa::component::solidmechanics::spring::SpringForceField ; - -/** - * @brief Interaction using a spring. - * An interactor, typically attached to the mouse pointer, pulls a control point using a spring. - * @author Francois Faure, 2014 - */ -class SOFA_SOFASIMPLEGUI_API SpringInteractor: public Interactor -{ - typedef Interactor Inherited; -protected: - MechanicalObject3::SPtr _interactorDof; - SpringForceField3::SPtr _spring; -public: - /** - * @brief SpringInteractor - * @param picked The picked point. - * @param stiffness The stiffness of the spring attached to the picked point. - */ - SpringInteractor(const PickedPoint& picked, SReal stiffness=(SReal) 100.); - - /// Insert this in the scene as a child of the given node - void attach( SofaScene* scene ) override; - - /// Remove this from the scene, without destroying it. - void detach() override; - - /// current interaction point - Vec3 getPoint() override; - - /// Displace the interaction to the given point - void setPoint( const Vec3& p ) override; - -}; - -} - - -#endif // SOFA_SpringInteractor_H diff --git a/applications/plugins/SofaSimpleGUI/VisualPickVisitor.cpp b/applications/plugins/SofaSimpleGUI/VisualPickVisitor.cpp deleted file mode 100644 index c7b3203a8d7..00000000000 --- a/applications/plugins/SofaSimpleGUI/VisualPickVisitor.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "VisualPickVisitor.h" -#include -using std::cout; -using std::cerr; -using std::endl; - -#include -#include -#include -#include - - -namespace sofa::simplegui -{ - -VisualPickVisitor::VisualPickVisitor(core::visual::VisualParams* params) - : VisualVisitor(params) -{ - pickedId = 0; -} - - -simulation::Visitor::Result VisualPickVisitor::processNodeTopDown(simulation::Node* node) -{ -// cerr <<"VisualPickVisitor::processNodeTopDown" << endl; - hasShader = (node->getShader()!=NULL); - - for_each(this, node, node->visualModel, &VisualPickVisitor::fwdVisualModel); - this->VisualVisitor::processNodeTopDown(node); - - return RESULT_CONTINUE; -} - -void VisualPickVisitor::processNodeBottomUp(simulation::Node* node) -{ -// cerr <<"VisualPickVisitor::processNodeBottomUp" << endl; - for_each(this, node, node->visualModel, &VisualPickVisitor::bwdVisualModel); -} - -void VisualPickVisitor::processObject(simulation::Node* /*node*/, core::objectmodel::BaseObject* o) -{ -#ifdef DEBUG_DRAW - std::cerr << ">" << o->getClassName() << "::draw() of " << o->getName() << std::endl; -#endif -// cout<<"VisualPickVisitor::processObject push name of "<< o->getName() << " = " << pickedId << endl; - names.push_back(o->getName()); - glPushName(pickedId++); - o->draw(vparams); - glPopName(); -// cout<<"VisualPickVisitor::processObject end " << endl; - -#ifdef DEBUG_DRAW - std::cerr << "<" << o->getClassName() << "::draw() of " << o->getName() << std::endl; -#endif -} - -void VisualPickVisitor::fwdVisualModel(simulation::Node* /*node*/, core::visual::VisualModel* vm) -{ -#ifdef DEBUG_DRAW - std::cerr << ">" << vm->getClassName() << "::fwdDraw() of " << vm->getName() << std::endl; -#endif - vm->fwdDraw(vparams); -#ifdef DEBUG_DRAW - std::cerr << "<" << vm->getClassName() << "::fwdDraw() of " << vm->getName() << std::endl; -#endif -} - -void VisualPickVisitor::bwdVisualModel(simulation::Node* /*node*/,core::visual::VisualModel* vm) -{ -#ifdef DEBUG_DRAW - std::cerr << ">" << vm->getClassName() << "::bwdDraw() of " << vm->getName() << std::endl; -#endif - vm->bwdDraw(vparams); -#ifdef DEBUG_DRAW - std::cerr << "<" << vm->getClassName() << "::bwdDraw() of " << vm->getName() << std::endl; -#endif -} - -void VisualPickVisitor::processVisualModel(simulation::Node* node, core::visual::VisualModel* vm) -{ - //cerr<<"VisualPickVisitor::processVisualModel "<getName()<(node->getShader(subsetsToManage)); - - - switch(vparams->pass()) - { - case core::visual::VisualParams::Std: - { - if (shader && shader->isActive()) - shader->start(); -#ifdef DEBUG_DRAW - std::cerr << ">" << vm->getClassName() << "::drawVisual() of " << vm->getName() << std::endl; -#endif - names.push_back(vm->getName()); - glPushName(pickedId++); - vm->drawVisual(vparams); - glPopName(); -#ifdef DEBUG_DRAW - std::cerr << "<" << vm->getClassName() << "::drawVisual() of " << vm->getName() << std::endl; -#endif - if (shader && shader->isActive()) - shader->stop(); - break; - } - case core::visual::VisualParams::Transparent: - { - if (shader && shader->isActive()) - shader->start(); -#ifdef DEBUG_DRAW - std::cerr << ">" << vm->getClassName() << "::drawTransparent() of " << vm->getName() << std::endl; -#endif - vm->drawTransparent(vparams); -#ifdef DEBUG_DRAW - std::cerr << "<" << vm->getClassName() << "::drawTransparent() of " << vm->getName() << std::endl; -#endif - if (shader && shader->isActive()) - shader->stop(); - break; - } - case core::visual::VisualParams::Shadow: -#ifdef DEBUG_DRAW - std::cerr << ">" << vm->getClassName() << "::drawShadow() of " << vm->getName() << std::endl; -#endif - vm->drawShadow(vparams); -#ifdef DEBUG_DRAW - std::cerr << "<" << vm->getClassName() << "::drawShadow() of " << vm->getName() << std::endl; -#endif - break; - } - -} - - -} - - diff --git a/applications/plugins/SofaSimpleGUI/VisualPickVisitor.h b/applications/plugins/SofaSimpleGUI/VisualPickVisitor.h deleted file mode 100644 index fe72aa97004..00000000000 --- a/applications/plugins/SofaSimpleGUI/VisualPickVisitor.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SOFA_SIMPLEGUI_VisualPickVisitor_H -#define SOFA_SIMPLEGUI_VisualPickVisitor_H -#include -#include - - -namespace sofa::simplegui -{ - -/** - * @brief The VisualPickVisitor class displays the scene for OpenGL picking. - * It uses the glPushName instruction, and it must be called within a specific OpenGL context, see http://www.lighthouse3d.com/opengl/picking/ - * The names vector member contains the names of all the objects rendered, in the traversal order. - * This allows to associate a hit number to an object during the pre-processing. - * @sa SofaGL - * @author Francois Faure, 2014 - * - * @warning The code is directly adapted from VisualDrawVisitor, without much insight - */ -class VisualPickVisitor : public ::sofa::simulation::VisualVisitor -{ -public: - bool hasShader; - VisualPickVisitor(core::visual::VisualParams* params); - Result processNodeTopDown(simulation::Node* node) override; - void processNodeBottomUp(simulation::Node* node) override; - virtual void fwdVisualModel(simulation::Node* node, core::visual::VisualModel* vm); - void processVisualModel(simulation::Node* node, core::visual::VisualModel* vm) override; - void processObject(simulation::Node* node, core::objectmodel::BaseObject* o) override; - virtual void bwdVisualModel(simulation::Node* node, core::visual::VisualModel* vm); - const char* getClassName() const override { return "VisualPickVisitor"; } - - sofa::type::vector names; // names of the object displayed - -private: - int pickedId; - - -}; - -} - -#endif // SOFA_SIMPLEGUI_VisualPickVisitor_H diff --git a/applications/plugins/SofaSimpleGUI/doc/Doxyfile b/applications/plugins/SofaSimpleGUI/doc/Doxyfile deleted file mode 100644 index 1ff35ada7e4..00000000000 --- a/applications/plugins/SofaSimpleGUI/doc/Doxyfile +++ /dev/null @@ -1,1918 +0,0 @@ -# Doxyfile 1.8.4 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = SimpleGUI - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = code - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, -# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, -# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. Note that you specify absolute paths here, but also -# relative paths, which will be relative from the directory where doxygen is -# started. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, -# and language is one of the parsers supported by doxygen: IDL, Java, -# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, -# C++. For instance to make doxygen treat .inc files as Fortran files (default -# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note -# that for custom extensions you also need to set FILE_PATTERNS otherwise the -# files are not read by doxygen. - -EXTENSION_MAPPING = - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES (the -# default) will make doxygen replace the get and set methods by a property in -# the documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields or simple typedef fields will be shown -# inline in the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO (the default), structs, classes, and unions are shown on a separate -# page (for HTML and Man pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can -# be an expensive process and often the same symbol appear multiple times in -# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too -# small doxygen will become slower. If the cache is too large, memory is wasted. -# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid -# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 -# symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = YES - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if section-label ... \endif -# and \cond section-label ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. Do not use -# file names with spaces, bibtex cannot handle them. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = .. - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.d \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.idl \ - *.odl \ - *.cs \ - *.php \ - *.php3 \ - *.inc \ - *.m \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.vhd \ - *.vhdl - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = ../glutOnePick - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be ignored. -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If left blank doxygen will -# generate a default style sheet. Note that it is recommended to use -# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this -# tag will in the future become obsolete. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional -# user-defined cascading style sheet that is included after the standard -# style sheets created by doxygen. Using this option one can overrule -# certain style aspects. This is preferred over using HTML_STYLESHEET -# since it does not replace the standard style sheet and is therefor more -# robust against future updates. Doxygen will copy the style sheet file to -# the output directory. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely -# identify the documentation publisher. This should be a reverse domain-name -# style string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -#
-# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and -# SVG. The default value is HTML-CSS, which is slower, but has the best -# compatibility. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript -# pieces of code that will be used on startup of the MathJax code. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. -# There are two flavours of web server based search depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. -# See the manual for details. - -SERVER_BASED_SEARCH = NO - -# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP -# script for searching. Instead the search results are written to an XML file -# which needs to be processed by an external indexer. Doxygen will invoke an -# external search engine pointed to by the SEARCHENGINE_URL option to obtain -# the search results. Doxygen ships with an example indexer (doxyindexer) and -# search engine (doxysearch.cgi) which are based on the open source search -# engine library Xapian. See the manual for configuration details. - -EXTERNAL_SEARCH = NO - -# The SEARCHENGINE_URL should point to a search engine hosted by a web server -# which will returned the search results when EXTERNAL_SEARCH is enabled. -# Doxygen ships with an example search engine (doxysearch) which is based on -# the open source search engine library Xapian. See the manual for configuration -# details. - -SEARCHENGINE_URL = - -# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed -# search data is written to a file for indexing by an external tool. With the -# SEARCHDATA_FILE tag the name of this file can be specified. - -SEARCHDATA_FILE = searchdata.xml - -# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the -# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is -# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple -# projects and redirect the results back to the right project. - -EXTERNAL_SEARCH_ID = - -# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen -# projects other than the one defined by this configuration file, but that are -# all added to the same external search index. Each project needs to have a -# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id -# of to a relative location where the documentation can be found. -# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... - -EXTRA_SEARCH_MAPPINGS = - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4 will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images -# or other source files which should be copied to the LaTeX output directory. -# Note that the files will be copied as-is; there are no commands or markers -# available. - -LATEX_EXTRA_FILES = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options related to the DOCBOOK output -#--------------------------------------------------------------------------- - -# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files -# that can be used to generate PDF. - -GENERATE_DOCBOOK = NO - -# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in -# front of it. If left blank docbook will be used as the default path. - -DOCBOOK_OUTPUT = docbook - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed -# in the related pages index. If set to NO, only the current project's -# pages will be listed. - -EXTERNAL_PAGES = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# manageable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/applications/plugins/SofaSimpleGUI/doc/DoxygenLayout.xml b/applications/plugins/SofaSimpleGUI/doc/DoxygenLayout.xml deleted file mode 100644 index 4be599bd1a7..00000000000 --- a/applications/plugins/SofaSimpleGUI/doc/DoxygenLayout.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/SofaSimpleGUI/doc/SimpleGUI.png b/applications/plugins/SofaSimpleGUI/doc/SimpleGUI.png deleted file mode 100644 index 25881a4e2bd974f3229c06699ea1fdde20d25d95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18862 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 R2%4<~I~+p5*9FJs{RNgh$rAto diff --git a/applications/plugins/SofaSimpleGUI/doc/index.html b/applications/plugins/SofaSimpleGUI/doc/index.html deleted file mode 100644 index f612f48076b..00000000000 --- a/applications/plugins/SofaSimpleGUI/doc/index.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - SimpleGUI - - - - - - - - -

SimpleGUI

- - - - - - - - - - - -
SimpleGUI helps inserting a Sofa simulation in graphics applications, such as this simple Glut program.
-
representative image of the plugin
- -
- - - -
- -

Introduction

-This is a simpler alternative to the standard Sofa GUI. See the code documentation (*) for more detail.
-
-

Compilation

-One subproject uses qtquick. On Ubuntu 14.04, it requires package qtdeclarative5-dev. - - -

Examples

- - -
    - -
  • glutOnePick: a glut application with a Sofa simulation. The user can interact by clicking and dragging particles. -
  • -
  • qtSofa: a qt application with a Sofa simulation. The user can interact by shift-clicking and dragging particles. -
  • -
- - - -

Intellectual -property and rights

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Authors
-
Francois Faure
Contact
-
Francois.Faure@inria.fr
-
License
-
This plugin is distributed under -the same license as the core of SOFA. -
Patents
-

-
APP registration
-

-
Sponsors
-
-
-
- -
- -
- -

HowTo

- -

Code documentation

- -can be generated using doxygen. In Unix -systems, simply type doxygen -Doxyfile in the doc directory.
- -
- -

LaTeX formulas

- -can be directly copy-pasted from .tex to this html document thanks to the mathjax config and -script included in the header. Equation numbering and cross-referencing works, as well a newcommand.
- -
- -
- -
- -
- - diff --git a/applications/plugins/SofaSimpleGUI/examples/liver.scn b/applications/plugins/SofaSimpleGUI/examples/liver.scn deleted file mode 100644 index 2ea0cb8954c..00000000000 --- a/applications/plugins/SofaSimpleGUI/examples/liver.scn +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/SofaSimpleGUI/examples/oneTet.scn b/applications/plugins/SofaSimpleGUI/examples/oneTet.scn deleted file mode 100644 index d888792de76..00000000000 --- a/applications/plugins/SofaSimpleGUI/examples/oneTet.scn +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/plugins/image/image_test/DataImage_test.cpp b/applications/plugins/image/image_test/DataImage_test.cpp index 76ef76c395a..ce749b58a7d 100644 --- a/applications/plugins/image/image_test/DataImage_test.cpp +++ b/applications/plugins/image/image_test/DataImage_test.cpp @@ -45,7 +45,7 @@ struct DataImageLink_test : public sofa::testing::BaseTest core::objectmodel::Data< defaulttype::Image > data2; /// Create a link between the two images - void SetUp() + void doSetUp() { } diff --git a/applications/plugins/image/image_test/ImageEngine_test.cpp b/applications/plugins/image/image_test/ImageEngine_test.cpp index 7890e89d929..dcae5fee3d9 100644 --- a/applications/plugins/image/image_test/ImageEngine_test.cpp +++ b/applications/plugins/image/image_test/ImageEngine_test.cpp @@ -51,7 +51,7 @@ struct ImageEngine_test : public sofa::testing::BaseTest simulation::Node::SPtr root; // Unload scene - void TearDown() + void doTearDown() { if (root!=NULL) sofa::simulation::node::unload(root); diff --git a/applications/projects/SceneChecking/tests/SceneChecker_test.cpp b/applications/projects/SceneChecking/tests/SceneChecker_test.cpp index 9de8d0bbcf4..1324a6773c1 100644 --- a/applications/projects/SceneChecking/tests/SceneChecker_test.cpp +++ b/applications/projects/SceneChecking/tests/SceneChecker_test.cpp @@ -76,13 +76,13 @@ int ComponentDeprecatedClassId = sofa::core::RegisterObject("") //////////////////////////////////////////////////////////////////////////////////////////////////// struct SceneChecker_test : public BaseSimulationTest { - void SetUp() override + void doSetUp() override { } void checkRequiredPlugin(bool missing) { - sofa::simpleapi::importPlugin("Sofa.Component.ODESolver.Forward"); + sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Forward); const std::string missStr = missing ? "" : " \n"; std::stringstream scene; @@ -173,11 +173,12 @@ struct SceneChecker_test : public BaseSimulationTest EXPECT_MSG_NOEMIT(Warning); const std::string lvl = (shouldWarn)?"17.06":"17.12"; - + + sofa::simpleapi::importPlugin("Sofa.Component.SceneUtility"); + std::stringstream scene; scene << " \n" << " \n" - << " \n" << " \n" << " \n" << " \n"; diff --git a/applications/projects/SofaPhysicsAPI/src/SofaPhysicsAPI/SofaPhysicsSimulation.cpp b/applications/projects/SofaPhysicsAPI/src/SofaPhysicsAPI/SofaPhysicsSimulation.cpp index f0e53e0ac62..56e4c217bec 100644 --- a/applications/projects/SofaPhysicsAPI/src/SofaPhysicsAPI/SofaPhysicsSimulation.cpp +++ b/applications/projects/SofaPhysicsAPI/src/SofaPhysicsAPI/SofaPhysicsSimulation.cpp @@ -1123,13 +1123,12 @@ void SofaPhysicsSimulation::calcProjection() xFactor *= 0.01; yFactor *= 0.01; - //std::cout << xNear << " " << yNear << std::endl; - - double zForeground = -vparams->zNear() - offset; - double zBackground = -vparams->zFar() + offset; - if (currentCamera->getCameraType() == sofa::core::visual::VisualParams::PERSPECTIVE_TYPE) - gluPerspective(currentCamera->getFieldOfView(), (double) width / (double) height, vparams->zNear(), vparams->zFar()); + { + gluPerspective(currentCamera->getFieldOfView(), + (double) width / (double) height, + vparams->zNear(),vparams->zFar()); + } else { double ratio = vparams->zFar() / (vparams->zNear() * 20); @@ -1138,8 +1137,8 @@ void SofaPhysicsSimulation::calcProjection() { ratio = -300 * (tcenter.norm2()) / tcenter[2]; } - glOrtho((-xNear * xFactor) * ratio, (xNear * xFactor) * ratio, (-yNear - * yFactor) * ratio, (yNear * yFactor) * ratio, + glOrtho((-xNear * xFactor) * ratio, (xNear * xFactor) * ratio, + (-yNear * yFactor) * ratio, (yNear * yFactor) * ratio, vparams->zNear(), vparams->zFar()); } diff --git a/applications/projects/runSofa/runSofa_test/runSofa_test.cpp b/applications/projects/runSofa/runSofa_test/runSofa_test.cpp index 70fb826b39e..7d0607e198e 100644 --- a/applications/projects/runSofa/runSofa_test/runSofa_test.cpp +++ b/applications/projects/runSofa/runSofa_test/runSofa_test.cpp @@ -44,7 +44,7 @@ class runSofa_test : public sofa::testing::BaseTest } - void SetUp() override + void doSetUp() override { const std::string& pluginDir = PluginRepository.getFirstPath(); @@ -58,7 +58,7 @@ class runSofa_test : public sofa::testing::BaseTest testPluginList << m_testPluginName << std::endl; testPluginList.close(); } - void TearDown() override + void doTearDown() override { } diff --git a/examples/Component/Constraint/Projective/LinearVelocityProjectiveConstraint.scn b/examples/Component/Constraint/Projective/LinearVelocityProjectiveConstraint.scn new file mode 100644 index 00000000000..9f1617fb152 --- /dev/null +++ b/examples/Component/Constraint/Projective/LinearVelocityProjectiveConstraint.scn @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/Component/ODESolver/Forward/EulerSymplecticSolver.scn b/examples/Component/ODESolver/Forward/EulerSymplecticSolver.scn index a82b531ff07..47e9608e636 100644 --- a/examples/Component/ODESolver/Forward/EulerSymplecticSolver.scn +++ b/examples/Component/ODESolver/Forward/EulerSymplecticSolver.scn @@ -21,7 +21,7 @@ trivially, it requires a linear solver, here SparseLDLSolver. - + diff --git a/examples/Component/ODESolver/Forward/EulerSymplecticSolver_diagonal.scn b/examples/Component/ODESolver/Forward/EulerSymplecticSolver_diagonal.scn index f8a7a002d4a..73bbc5ebfc3 100644 --- a/examples/Component/ODESolver/Forward/EulerSymplecticSolver_diagonal.scn +++ b/examples/Component/ODESolver/Forward/EulerSymplecticSolver_diagonal.scn @@ -22,7 +22,7 @@ trivially, it does not require a linear solver. - + diff --git a/examples/Component/Visual/CylinderVisualModel.scn b/examples/Component/Visual/CylinderVisualModel.scn new file mode 100644 index 00000000000..65191fc0e44 --- /dev/null +++ b/examples/Component/Visual/CylinderVisualModel.scn @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/examples/Component/Visual/OglCylinderModel.scn b/examples/Component/Visual/OglCylinderModel.scn deleted file mode 100644 index 0db4bc72a6c..00000000000 --- a/examples/Component/Visual/OglCylinderModel.scn +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/examples/Demos/SofaWasher.scn b/examples/Demos/SofaWasher.scn new file mode 100644 index 00000000000..bddd71116e9 --- /dev/null +++ b/examples/Demos/SofaWasher.scn @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/Demos/fallingBeamAugmentedLagrangianCollision.scn b/examples/Demos/fallingBeamAugmentedLagrangianCollision.scn new file mode 100644 index 00000000000..18f52f4a548 --- /dev/null +++ b/examples/Demos/fallingBeamAugmentedLagrangianCollision.scn @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Container,TriangleSetTopologyModifier] --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/RegressionStateScenes.regression-tests b/examples/RegressionStateScenes.regression-tests index 9c28cd6161b..2f0c0ef182e 100644 --- a/examples/RegressionStateScenes.regression-tests +++ b/examples/RegressionStateScenes.regression-tests @@ -31,6 +31,7 @@ Component/Constraint/Lagrangian/BilateralLagrangianConstraint_UGS.scn 100 1e-4 0 Component/Constraint/Lagrangian/FrictionContact_LCP_with_friction.scn 500 1e-4 0 1 Component/Constraint/Lagrangian/FrictionContact_LCP_without_friction.scn 500 1e-4 0 1 Component/Constraint/Projective/FixedProjectiveConstraint.scn 100 1e-4 0 1 +Component/Constraint/Projective/LinearVelocityProjectiveConstraint.scn 100 1e-4 0 1 Component/LinearSolver/Direct/FEMBAR_EigenSimplicialLDLT.scn 100 1e-8 0 1 Component/LinearSolver/Direct/FEMBAR_EigenSimplicialLLT.scn 100 1e-8 0 1 Component/LinearSolver/Direct/FEMBAR_EigenSparseLU.scn 100 1e-8 0 1 diff --git a/share/mesh/SOFA_collision_center.obj b/share/mesh/SOFA_collision_center.obj new file mode 100644 index 00000000000..c071bf0c129 --- /dev/null +++ b/share/mesh/SOFA_collision_center.obj @@ -0,0 +1,331 @@ +v -192.234 60.457 0.000 +v -189.317 52.829 0.000 +v -183.414 47.615 0.000 +v -173.613 45.920 0.000 +v -165.855 48.929 0.000 +v -160.167 56.092 0.000 +v -159.376 66.516 0.000 +v -156.116 74.076 0.000 +v -152.857 81.636 0.000 +v -145.511 90.817 0.000 +v -134.622 100.230 0.000 +v -125.799 97.927 0.000 +v -115.953 97.236 0.000 +v -106.068 96.982 0.000 +v -100.334 87.901 0.000 +v -96.236 80.052 0.000 +v -91.153 68.625 0.000 +v -87.038 57.346 0.000 +v -83.743 44.803 0.000 +v -87.666 37.097 0.000 +v -89.744 26.562 0.000 +v -86.884 14.815 0.000 +v -79.864 6.052 0.000 +v -66.864 0.540 0.000 +v -59.681 0.157 0.000 +v -48.396 4.304 0.000 +v -40.186 12.733 0.000 +v -38.370 20.114 0.000 +v -36.553 27.495 0.000 +v -40.379 38.100 0.000 +v -43.974 45.348 0.000 +v -49.977 50.135 0.000 +v -57.590 52.968 0.000 +v -66.192 54.088 0.000 +v -71.055 60.605 0.000 +v -75.918 67.122 0.000 +v -82.815 79.950 0.000 +v -86.197 87.816 0.000 +v -89.579 95.682 0.000 +v -92.541 106.558 0.000 +v -86.900 113.639 0.000 +v -83.049 121.064 0.000 +v -78.827 131.435 0.000 +v -70.977 133.787 0.000 +v -63.127 136.138 0.000 +v -52.440 137.705 0.000 +v -38.773 137.039 0.000 +v -28.245 128.966 0.000 +v -20.523 127.103 0.000 +v -12.125 128.879 0.000 +v -5.314 133.780 0.000 +v -0.968 141.173 0.000 +v -0.366 149.833 0.000 +v -5.899 161.931 0.000 +v -13.518 167.123 0.000 +v -20.675 168.349 0.000 +v -27.648 167.107 0.000 +v -36.038 160.817 0.000 +v -43.298 150.255 0.000 +v -50.895 148.359 0.000 +v -58.491 146.464 0.000 +v -70.331 144.893 0.000 +v -81.939 146.078 0.000 +v -87.792 156.517 0.000 +v -93.706 163.818 0.000 +v -92.080 171.240 0.000 +v -90.454 178.663 0.000 +v -85.634 190.998 0.000 +v -81.758 197.794 0.000 +v -77.881 204.591 0.000 +v -72.676 211.814 0.000 +v -73.665 219.375 0.000 +v -81.676 224.300 0.000 +v -90.935 219.789 0.000 +v -92.652 209.204 0.000 +v -94.458 196.914 0.000 +v -97.278 185.909 0.000 +v -100.159 178.624 0.000 +v -103.041 171.340 0.000 +v -112.111 171.350 0.000 +v -123.510 171.135 0.000 +v -128.272 160.279 0.000 +v -133.109 152.563 0.000 +v -138.716 147.545 0.000 +v -145.255 144.460 0.000 +v -153.680 142.985 0.000 +v -155.439 133.793 0.000 +v -154.376 125.587 0.000 +v -150.570 116.142 0.000 +v -145.562 108.566 0.000 +v -150.057 100.036 0.000 +v -156.761 92.282 0.000 +v -163.721 85.325 0.000 +v -172.760 79.516 0.000 +v -183.268 77.238 0.000 +v -188.655 72.565 0.000 +v -192.138 63.034 0.000 +v -90.795 120.277 0.000 +v -130.272 145.871 0.000 +v -120.301 105.784 0.000 +v -62.800 46.549 0.000 +v -63.135 5.437 0.000 +v -96.507 155.697 0.000 +v -13.675 157.951 0.000 +v -185.764 65.444 0.000 +v -141.503 116.374 0.000 +v -80.470 30.205 0.000 +v -45.671 17.996 0.000 +v -23.522 135.760 0.000 +v -47.179 37.207 0.000 +v -148.552 130.362 0.000 +v -167.233 61.709 0.000 +v -33.229 150.407 0.000 +v -9.474 141.199 0.000 +v -107.547 163.366 0.000 +v -124.912 151.937 0.000 +v -122.780 144.132 0.000 +v -127.723 138.297 0.000 +v -120.290 136.758 0.000 +v -125.332 130.728 0.000 +v -117.518 129.306 0.000 +v -112.406 135.570 0.000 +v -117.124 149.722 0.000 +v -109.427 127.981 0.000 +v -104.036 134.449 0.000 +v -122.815 123.018 0.000 +v -133.461 132.959 0.000 +v -177.256 53.433 0.000 +v -107.224 141.761 0.000 +v -98.587 141.232 0.000 +v -75.922 15.439 0.000 +v -70.669 48.053 0.000 +v -67.603 39.843 0.000 +v -119.648 157.364 0.000 +v -96.300 132.718 0.000 +v -80.476 215.243 0.000 +v -176.303 70.947 0.000 +v -59.590 38.697 0.000 +v -64.262 31.912 0.000 +v -56.123 30.793 0.000 +v -60.818 24.042 0.000 +v -21.816 161.521 0.000 +v -20.204 152.975 0.000 +v -139.601 139.090 0.000 +v -186.968 59.497 0.000 +v -43.956 30.900 0.000 +v -110.569 154.657 0.000 +v -71.732 24.802 0.000 +v -66.562 16.822 0.000 +v -57.474 16.376 0.000 +v -52.401 22.470 0.000 +v -166.964 70.386 0.000 +v -179.232 61.803 0.000 +v -88.694 129.669 0.000 +v -136.215 108.170 0.000 +v -133.205 116.870 0.000 +v -137.458 124.346 0.000 +v -75.926 41.599 0.000 +v -69.054 9.458 0.000 +v -12.567 149.561 0.000 +v -19.315 143.842 0.000 +v -114.797 121.441 0.000 +v -106.597 120.038 0.000 +v -112.461 113.194 0.000 +v -103.795 112.578 0.000 +v -78.551 52.368 0.000 +v -101.658 126.642 0.000 +v -97.365 97.626 0.000 +v -110.077 105.141 0.000 +v -120.631 114.536 0.000 +v -127.595 111.085 0.000 +v -84.929 138.868 0.000 +v -73.533 34.167 0.000 +v -91.945 146.612 0.000 +v -102.784 149.063 0.000 +v -147.215 137.146 0.000 +v -86.808 202.831 0.000 +v -98.580 119.870 0.000 +v -141.115 131.911 0.000 +v -55.575 44.877 0.000 +v -145.596 124.120 0.000 +v -115.244 142.559 0.000 +v -84.787 72.337 0.000 +v -77.401 139.012 0.000 +v -163.303 77.412 0.000 +v -129.740 124.259 0.000 +v -15.414 136.172 0.000 +v -29.817 142.309 0.000 +v -100.362 163.051 0.000 +v -44.688 143.607 0.000 +v -115.100 164.442 0.000 +v -56.927 8.503 0.000 +v -50.711 12.663 0.000 +v -44.251 24.437 0.000 +v -142.393 101.564 0.000 +v -7.768 153.257 0.000 +v -78.377 59.970 0.000 +v -93.256 89.441 0.000 +v -81.804 22.091 0.000 +v -182.803 70.875 0.000 +v -27.532 155.822 0.000 +v -173.475 59.055 0.000 +v -95.749 112.999 0.000 +v -89.074 79.703 0.000 +v -97.094 168.914 0.000 +v -121.633 163.305 0.000 +v -169.600 54.190 0.000 +v -30.089 136.018 0.000 +v -103.554 157.167 0.000 +v -100.933 105.314 0.000 +v -92.355 190.512 0.000 +v -172.687 65.092 0.000 +v -62.630 11.319 0.000 +v -110.589 147.553 0.000 +v -6.335 147.008 0.000 +v -26.019 149.071 0.000 +v -94.895 126.094 0.000 +v -50.100 42.830 0.000 +v -85.750 210.332 0.000 +v -92.091 137.820 0.000 +v -183.237 55.035 0.000 +v -133.955 140.752 0.000 +v -49.618 30.398 0.000 +v -95.295 175.834 0.000 +v -37.961 144.723 0.000 +v -88.202 195.810 0.000 +v -72.555 54.413 0.000 +v -126.797 117.954 0.000 +v -28.258 161.317 0.000 +v -83.454 65.080 0.000 +v -80.537 37.306 0.000 +v -53.249 37.215 0.000 +v -128.948 104.318 0.000 +l 9 10 +l 10 11 +l 11 12 +l 12 13 +l 13 14 +l 14 15 +l 15 16 +l 16 17 +l 17 18 +l 18 19 +l 19 20 +l 20 21 +l 21 22 +l 22 23 +l 23 24 +l 24 25 +l 25 26 +l 26 27 +l 27 28 +l 28 29 +l 29 30 +l 30 31 +l 31 32 +l 32 33 +l 33 34 +l 34 35 +l 35 36 +l 36 37 +l 37 38 +l 38 39 +l 39 40 +l 40 41 +l 41 42 +l 42 43 +l 43 44 +l 44 45 +l 45 46 +l 46 47 +l 47 48 +l 48 49 +l 49 50 +l 50 51 +l 51 52 +l 52 53 +l 53 54 +l 54 55 +l 55 56 +l 56 57 +l 57 58 +l 58 59 +l 59 60 +l 60 61 +l 61 62 +l 62 63 +l 63 64 +l 64 65 +l 65 66 +l 66 67 +l 67 68 +l 68 69 +l 69 70 +l 70 71 +l 71 72 +l 72 73 +l 73 74 +l 74 75 +l 75 76 +l 76 77 +l 77 78 +l 78 79 +l 79 80 +l 80 81 +l 81 82 +l 82 83 +l 83 84 +l 84 85 +l 85 86 +l 86 87 +l 87 88 +l 88 89 +l 89 90 +l 90 91 +l 91 92 +l 92 93 +l 93 94 +l 94 95 +l 95 96 +l 96 97 +l 97 1 +l 1 2 +l 2 3 +l 3 4 +l 4 5 +l 5 6 +l 6 7 +l 7 8 +l 8 9 +l 9 10 diff --git a/share/mesh/SOFA_collision_no_face.obj b/share/mesh/SOFA_collision_no_face.obj new file mode 100644 index 00000000000..e57e58f326e --- /dev/null +++ b/share/mesh/SOFA_collision_no_face.obj @@ -0,0 +1,663 @@ +# Created by meshio v5.3.5, 2024-09-25T18:14:02.430293 +v -192.2342 60.457245 10.0 +v -189.31730740740738 52.82884722222222 10.0 +v -183.41376592592582 47.61546277777778 10.0 +v -173.6132583333333 45.920255000000004 10.0 +v -165.85462666666666 48.92924000000001 10.0 +v -160.16704666666664 56.09198166666665 10.0 +v -159.37593763888887 66.51596805555556 10.0 +v -156.11633567129627 74.07602837962963 10.0 +v -152.8567337037037 81.63608870370372 10.0 +v -145.51108629629633 90.81706796296298 10.0 +v -134.6217261111111 100.22958703703705 10.0 +v -125.79946277777776 97.92726842592593 10.0 +v -115.953295 97.23594333333337 10.0 +v -106.06834694444444 96.98207342592596 10.0 +v -100.3339277777778 87.90088314814818 10.0 +v -96.23609499999999 80.05152500000003 10.0 +v -91.15257314814814 68.62492833333336 10.0 +v -87.03835351851848 57.34572500000003 10.0 +v -83.74313000000001 44.80251500000002 10.0 +v -87.66622499999998 37.096515000000025 10.0 +v -89.74371333333333 26.562383333333358 10.0 +v -86.88399333333336 14.815341600000025 10.0 +v -79.86389111111112 6.052006637592616 10.0 +v -66.86430944444444 0.540367772870393 10.0 +v -59.681045 0.15701463000002247 10.0 +v -48.39609007407407 4.303864712592599 10.0 +v -40.186471592592554 12.732514897407409 10.0 +v -38.36987618518516 20.11385351351852 10.0 +v -36.55328077777778 27.49519212962963 10.0 +v -40.37934666666666 38.099591249999996 10.0 +v -43.973831777777775 45.34838324074073 10.0 +v -49.97722092592592 50.13503537037036 10.0 +v -57.59017840740741 52.96834796296295 10.0 +v -66.19233837962963 54.088347361111104 10.0 +v -71.05505891203704 60.605059884259255 10.0 +v -75.91777944444445 67.1217724074074 10.0 +v -82.81507722222221 79.95018425925926 10.0 +v -86.19711277777778 87.81599125 10.0 +v -89.57914833333334 95.68179824074073 10.0 +v -92.54104875 106.55805377314815 10.0 +v -86.89993870370371 113.6386588888889 10.0 +v -83.04949462962965 121.06399111111115 10.0 +v -78.82741104166666 131.43537312499998 10.0 +v -70.97719724305556 133.7867217476852 10.0 +v -63.12698344444444 136.13807037037037 10.0 +v -52.43966322222221 137.70537962962962 10.0 +v -38.77308843518518 137.0387159259259 10.0 +v -28.24538698148148 128.96565074074073 10.0 +v -20.5235 127.10275999999999 10.0 +v -12.125082784074074 128.8794311111111 10.0 +v -5.313775472592594 133.78004888888893 10.0 +v -0.9682875699999975 141.17252 10.0 +v -0.3660809085479142 149.83270736111112 10.0 +v -5.899070161666663 161.93091666666663 10.0 +v -13.517511999999996 167.12332999999995 10.0 +v -20.675108999999992 168.34940888888886 10.0 +v -27.64777533333333 167.10740777777775 10.0 +v -36.03802499999999 160.8171541666666 10.0 +v -43.298451629629625 150.25509138888884 10.0 +v -50.89456226851851 148.35949513888883 10.0 +v -58.4906729074074 146.46389888888882 10.0 +v -70.33091166666667 144.89254499999998 10.0 +v -81.93915148148147 146.0783130555555 10.0 +v -87.7921037037037 156.5167438888888 10.0 +v -93.70557393518519 163.81800837962953 10.0 +v -92.07963502314814 171.2402660416666 10.0 +v -90.4536961111111 178.66252370370367 10.0 +v -85.63357388888889 190.99786962962963 10.0 +v -81.75751805555555 197.79434719907402 10.0 +v -77.88146222222221 204.59082476851844 10.0 +v -72.67621055555556 211.81439907407403 10.0 +v -73.66474944444445 219.37477092592593 10.0 +v -81.6759438888889 224.2998306481481 10.0 +v -90.9351136111111 219.78926435185178 10.0 +v -92.65223499999999 209.20385499999992 10.0 +v -94.4578737037037 196.914474074074 10.0 +v -97.2777946296296 185.9085259259259 10.0 +v -100.1594729398148 178.62421442129624 10.0 +v -103.04115125 171.3399029166666 10.0 +v -112.11144648148147 171.35005407407402 10.0 +v -123.51036842592592 171.13475379629622 10.0 +v -128.27178666666663 160.27901666666656 10.0 +v -133.10878 152.5625499999999 10.0 +v -138.7159614814815 147.54539999999992 10.0 +v -145.25479851851856 144.45964333333328 10.0 +v -153.68033000000003 142.9850049999999 10.0 +v -155.4393640740741 133.79316740740734 10.0 +v -154.37636592592597 125.58727259259257 10.0 +v -150.5701890740741 116.14194944444435 10.0 +v -145.56223212962965 108.56584944444434 10.0 +v -150.0574383333333 100.03593583333323 10.0 +v -156.7614892592593 92.2815485185184 10.0 +v -163.72093740740743 85.32462814814801 10.0 +v -172.7604129166667 79.51592083333321 10.0 +v -183.26769 77.23760666666655 10.0 +v -188.65461888888893 72.56539074074061 10.0 +v -192.1384777777778 63.03370259259246 10.0 +v -90.79469223931024 120.2765345697156 10.0 +v -130.27206178203218 145.8707036079303 10.0 +v -120.3005012223003 105.783518677909 10.0 +v -62.79996643270988 46.54901183909538 10.0 +v -63.13452677356536 5.437126051548473 10.0 +v -96.50657002421443 155.69681879997668 10.0 +v -13.674701802772079 157.95127051897657 10.0 +v -185.7644801212342 65.44386782625185 10.0 +v -141.50342607075757 116.37374434367861 10.0 +v -80.4699907926312 30.205388253184243 10.0 +v -45.67060064437615 17.996401976675905 10.0 +v -23.521931285775775 135.75980957560998 10.0 +v -47.17948981920532 37.20687091978861 10.0 +v -148.5521073725251 130.36183817460127 10.0 +v -167.23284357891862 61.70889978311311 10.0 +v -33.2292240615551 150.40729488607099 10.0 +v -9.474409401453354 141.19920964051374 10.0 +v -107.54701855215194 163.3662169261165 10.0 +v -124.91199637725182 151.9369300685621 10.0 +v -122.78034056892332 144.1321534749725 10.0 +v -127.72296417457406 138.2969416718167 10.0 +v -120.28968738633553 136.75832228825092 10.0 +v -125.33180300765987 130.72837635807107 10.0 +v -117.51777454488052 129.30632680970731 10.0 +v -112.40616428744056 135.5700944536723 10.0 +v -117.12440687367832 149.72215371523376 10.0 +v -109.42670339762846 127.98068658856891 10.0 +v -104.03640048232853 134.44857377633608 10.0 +v -122.81523559906748 123.01827677799912 10.0 +v -133.46063411910313 132.95893672936003 10.0 +v -177.25566492113205 53.4328323624113 10.0 +v -107.22358255156996 141.76124776350443 10.0 +v -98.58714198065006 141.23188017805398 10.0 +v -75.92246618500151 15.438510193798813 10.0 +v -70.66940315406168 48.05318695890437 10.0 +v -67.60265428612371 39.843463356753325 10.0 +v -119.64816976632478 157.36389944240634 10.0 +v -96.30049213195124 132.71820653113966 10.0 +v -80.47583145551187 215.242994152514 10.0 +v -176.30287519797622 70.94732087614447 10.0 +v -59.589602523612896 38.69714312606434 10.0 +v -64.26165108917482 31.912413856518423 10.0 +v -56.1228785275038 30.79318385967851 10.0 +v -60.817899793284056 24.0422240894983 10.0 +v -21.81614250571405 161.52104661054761 10.0 +v -20.20361652546872 152.97476595251652 10.0 +v -139.6012067195076 139.08978868869883 10.0 +v -186.96764720778108 59.49704198867249 10.0 +v -43.95649136671274 30.90012061856282 10.0 +v -110.56873433140078 154.65727911147232 10.0 +v -71.73195670069174 24.80246156696747 10.0 +v -66.56191299351336 16.822146889176754 10.0 +v -57.47399949333125 16.375773056706407 10.0 +v -52.40112634816329 22.469668797807255 10.0 +v -166.96426211048424 70.385973194771 10.0 +v -179.23192725936863 61.80318698035899 10.0 +v -88.69422404576852 129.6694305325907 10.0 +v -136.21485140975886 108.17019137977269 10.0 +v -133.2054296001303 116.87019483999154 10.0 +v -137.45796418074139 124.34647456323945 10.0 +v -75.92586906245883 41.59926399575145 10.0 +v -69.05399628925638 9.458216470913737 10.0 +v -12.566572203762508 149.56075146378697 10.0 +v -19.31546983634809 143.84219703854268 10.0 +v -114.7968604000771 121.44090235560448 10.0 +v -106.59683511965208 120.03837444788589 10.0 +v -112.46058398821174 113.19383432910763 10.0 +v -103.79512254140776 112.5775905962738 10.0 +v -78.55117919390311 52.36757171218854 10.0 +v -101.65789746937159 126.64235334361702 10.0 +v -97.36520334842065 97.62616152063724 10.0 +v -110.07664451058537 105.14110934238123 10.0 +v -120.63070665700958 114.53618048163405 10.0 +v -127.59545086979477 111.08457023353913 10.0 +v -84.92890185938371 138.86761580983347 10.0 +v -73.5334343737174 34.166696207816926 10.0 +v -91.94460973105883 146.61200255335748 10.0 +v -102.7837008134617 149.0632233620782 10.0 +v -147.21501196993654 137.14609675533566 10.0 +v -86.80773501061078 202.83109437700378 10.0 +v -98.58018726698994 119.87032050328325 10.0 +v -141.11543834219395 131.9107245740923 10.0 +v -55.57453807726806 44.87722893206972 10.0 +v -145.59591516103634 124.12033394877476 10.0 +v -115.24428130213164 142.5589140592931 10.0 +v -84.78659718782622 72.3373679748638 10.0 +v -77.40071465845081 139.0121137476148 10.0 +v -163.30283152017378 77.41244750040703 10.0 +v -129.7399151522091 124.25909662143171 10.0 +v -15.414403146806585 136.17184595580434 10.0 +v -29.816751282996158 142.30887133715973 10.0 +v -100.36243383841085 163.05064047579359 10.0 +v -44.68796992696312 143.60667606514036 10.0 +v -115.10036498536482 164.44151577735752 10.0 +v -56.9270288371536 8.503313084216492 10.0 +v -50.71124127425364 12.662660906820408 10.0 +v -44.25081263248774 24.437135524813453 10.0 +v -142.3934668560258 101.56372633151004 10.0 +v -7.768196597964453 153.25674051409266 10.0 +v -78.37668440984068 59.97022527437368 10.0 +v -93.25601766220184 89.44088171196435 10.0 +v -81.80397686948136 22.09083461396302 10.0 +v -182.8028881521716 70.87542394540759 10.0 +v -27.53181776661814 155.82180672084945 10.0 +v -173.47475178294061 59.055267843154056 10.0 +v -95.74883447809327 112.99914233717453 10.0 +v -89.07391216636267 79.70347975490343 10.0 +v -97.09353709184268 168.91385892921875 10.0 +v -121.63267246107056 163.30479642068167 10.0 +v -169.59969865827628 54.18974610922418 10.0 +v -30.089289496359648 136.01826189485905 10.0 +v -103.55369151192792 157.16683573508746 10.0 +v -100.93253342882522 105.31402183259011 10.0 +v -92.3553207784182 190.51153119469672 10.0 +v -172.68685153415072 65.09196268593557 10.0 +v -62.630292877363985 11.319315110512372 10.0 +v -110.58894117444848 147.55256360231635 10.0 +v -6.334557913073101 147.0080565599221 10.0 +v -26.01937589459724 149.07098718702784 10.0 +v -94.89477521804297 126.09444472552833 10.0 +v -50.09998557118215 42.830181832596594 10.0 +v -85.75047545989118 210.33160652997756 10.0 +v -92.09107394976247 137.81982712099506 10.0 +v -183.237262544323 55.03547426628854 10.0 +v -133.95456565533968 140.75235413956113 10.0 +v -49.617607658301104 30.398395070110706 10.0 +v -95.29549562271511 175.8339607785908 10.0 +v -37.96109706726583 144.72332992063713 10.0 +v -88.20240428743541 195.8098632948956 10.0 +v -72.5550344666457 54.413171209256355 10.0 +v -126.79734757564225 117.95366379091912 10.0 +v -28.258440151416373 161.3168538189603 10.0 +v -83.4543975417556 65.08000379799563 10.0 +v -80.53651683589368 37.30639298460086 10.0 +v -53.24901614176597 37.21465969289774 10.0 +v -128.9482251766824 104.31788098259726 10.0 +v -192.2342 60.457245 -10.0 +v -189.31730740740738 52.82884722222222 -10.0 +v -183.41376592592582 47.61546277777778 -10.0 +v -173.6132583333333 45.920255000000004 -10.0 +v -165.85462666666666 48.92924000000001 -10.0 +v -160.16704666666664 56.09198166666665 -10.0 +v -159.37593763888887 66.51596805555556 -10.0 +v -156.11633567129627 74.07602837962963 -10.0 +v -152.8567337037037 81.63608870370372 -10.0 +v -145.51108629629633 90.81706796296298 -10.0 +v -134.6217261111111 100.22958703703705 -10.0 +v -125.79946277777776 97.92726842592593 -10.0 +v -115.953295 97.23594333333337 -10.0 +v -106.06834694444444 96.98207342592596 -10.0 +v -100.3339277777778 87.90088314814818 -10.0 +v -96.23609499999999 80.05152500000003 -10.0 +v -91.15257314814814 68.62492833333336 -10.0 +v -87.03835351851848 57.34572500000003 -10.0 +v -83.74313000000001 44.80251500000002 -10.0 +v -87.66622499999998 37.096515000000025 -10.0 +v -89.74371333333333 26.562383333333358 -10.0 +v -86.88399333333336 14.815341600000025 -10.0 +v -79.86389111111112 6.052006637592616 -10.0 +v -66.86430944444444 0.540367772870393 -10.0 +v -59.681045 0.15701463000002247 -10.0 +v -48.39609007407407 4.303864712592599 -10.0 +v -40.186471592592554 12.732514897407409 -10.0 +v -38.36987618518516 20.11385351351852 -10.0 +v -36.55328077777778 27.49519212962963 -10.0 +v -40.37934666666666 38.099591249999996 -10.0 +v -43.973831777777775 45.34838324074073 -10.0 +v -49.97722092592592 50.13503537037036 -10.0 +v -57.59017840740741 52.96834796296295 -10.0 +v -66.19233837962963 54.088347361111104 -10.0 +v -71.05505891203704 60.605059884259255 -10.0 +v -75.91777944444445 67.1217724074074 -10.0 +v -82.81507722222221 79.95018425925926 -10.0 +v -86.19711277777778 87.81599125 -10.0 +v -89.57914833333334 95.68179824074073 -10.0 +v -92.54104875 106.55805377314815 -10.0 +v -86.89993870370371 113.6386588888889 -10.0 +v -83.04949462962965 121.06399111111115 -10.0 +v -78.82741104166666 131.43537312499998 -10.0 +v -70.97719724305556 133.7867217476852 -10.0 +v -63.12698344444444 136.13807037037037 -10.0 +v -52.43966322222221 137.70537962962962 -10.0 +v -38.77308843518518 137.0387159259259 -10.0 +v -28.24538698148148 128.96565074074073 -10.0 +v -20.5235 127.10275999999999 -10.0 +v -12.125082784074074 128.8794311111111 -10.0 +v -5.313775472592594 133.78004888888893 -10.0 +v -0.9682875699999975 141.17252 -10.0 +v -0.3660809085479142 149.83270736111112 -10.0 +v -5.899070161666663 161.93091666666663 -10.0 +v -13.517511999999996 167.12332999999995 -10.0 +v -20.675108999999992 168.34940888888886 -10.0 +v -27.64777533333333 167.10740777777775 -10.0 +v -36.03802499999999 160.8171541666666 -10.0 +v -43.298451629629625 150.25509138888884 -10.0 +v -50.89456226851851 148.35949513888883 -10.0 +v -58.4906729074074 146.46389888888882 -10.0 +v -70.33091166666667 144.89254499999998 -10.0 +v -81.93915148148147 146.0783130555555 -10.0 +v -87.7921037037037 156.5167438888888 -10.0 +v -93.70557393518519 163.81800837962953 -10.0 +v -92.07963502314814 171.2402660416666 -10.0 +v -90.4536961111111 178.66252370370367 -10.0 +v -85.63357388888889 190.99786962962963 -10.0 +v -81.75751805555555 197.79434719907402 -10.0 +v -77.88146222222221 204.59082476851844 -10.0 +v -72.67621055555556 211.81439907407403 -10.0 +v -73.66474944444445 219.37477092592593 -10.0 +v -81.6759438888889 224.2998306481481 -10.0 +v -90.9351136111111 219.78926435185178 -10.0 +v -92.65223499999999 209.20385499999992 -10.0 +v -94.4578737037037 196.914474074074 -10.0 +v -97.2777946296296 185.9085259259259 -10.0 +v -100.1594729398148 178.62421442129624 -10.0 +v -103.04115125 171.3399029166666 -10.0 +v -112.11144648148147 171.35005407407402 -10.0 +v -123.51036842592592 171.13475379629622 -10.0 +v -128.27178666666663 160.27901666666656 -10.0 +v -133.10878 152.5625499999999 -10.0 +v -138.7159614814815 147.54539999999992 -10.0 +v -145.25479851851856 144.45964333333328 -10.0 +v -153.68033000000003 142.9850049999999 -10.0 +v -155.4393640740741 133.79316740740734 -10.0 +v -154.37636592592597 125.58727259259257 -10.0 +v -150.5701890740741 116.14194944444435 -10.0 +v -145.56223212962965 108.56584944444434 -10.0 +v -150.0574383333333 100.03593583333323 -10.0 +v -156.7614892592593 92.2815485185184 -10.0 +v -163.72093740740743 85.32462814814801 -10.0 +v -172.7604129166667 79.51592083333321 -10.0 +v -183.26769 77.23760666666655 -10.0 +v -188.65461888888893 72.56539074074061 -10.0 +v -192.1384777777778 63.03370259259246 -10.0 +v -90.79469223931024 120.2765345697156 -10.0 +v -130.27206178203218 145.8707036079303 -10.0 +v -120.3005012223003 105.783518677909 -10.0 +v -62.79996643270988 46.54901183909538 -10.0 +v -63.13452677356536 5.437126051548473 -10.0 +v -96.50657002421443 155.69681879997668 -10.0 +v -13.674701802772079 157.95127051897657 -10.0 +v -185.7644801212342 65.44386782625185 -10.0 +v -141.50342607075757 116.37374434367861 -10.0 +v -80.4699907926312 30.205388253184243 -10.0 +v -45.67060064437615 17.996401976675905 -10.0 +v -23.521931285775775 135.75980957560998 -10.0 +v -47.17948981920532 37.20687091978861 -10.0 +v -148.5521073725251 130.36183817460127 -10.0 +v -167.23284357891862 61.70889978311311 -10.0 +v -33.2292240615551 150.40729488607099 -10.0 +v -9.474409401453354 141.19920964051374 -10.0 +v -107.54701855215194 163.3662169261165 -10.0 +v -124.91199637725182 151.9369300685621 -10.0 +v -122.78034056892332 144.1321534749725 -10.0 +v -127.72296417457406 138.2969416718167 -10.0 +v -120.28968738633553 136.75832228825092 -10.0 +v -125.33180300765987 130.72837635807107 -10.0 +v -117.51777454488052 129.30632680970731 -10.0 +v -112.40616428744056 135.5700944536723 -10.0 +v -117.12440687367832 149.72215371523376 -10.0 +v -109.42670339762846 127.98068658856891 -10.0 +v -104.03640048232853 134.44857377633608 -10.0 +v -122.81523559906748 123.01827677799912 -10.0 +v -133.46063411910313 132.95893672936003 -10.0 +v -177.25566492113205 53.4328323624113 -10.0 +v -107.22358255156996 141.76124776350443 -10.0 +v -98.58714198065006 141.23188017805398 -10.0 +v -75.92246618500151 15.438510193798813 -10.0 +v -70.66940315406168 48.05318695890437 -10.0 +v -67.60265428612371 39.843463356753325 -10.0 +v -119.64816976632478 157.36389944240634 -10.0 +v -96.30049213195124 132.71820653113966 -10.0 +v -80.47583145551187 215.242994152514 -10.0 +v -176.30287519797622 70.94732087614447 -10.0 +v -59.589602523612896 38.69714312606434 -10.0 +v -64.26165108917482 31.912413856518423 -10.0 +v -56.1228785275038 30.79318385967851 -10.0 +v -60.817899793284056 24.0422240894983 -10.0 +v -21.81614250571405 161.52104661054761 -10.0 +v -20.20361652546872 152.97476595251652 -10.0 +v -139.6012067195076 139.08978868869883 -10.0 +v -186.96764720778108 59.49704198867249 -10.0 +v -43.95649136671274 30.90012061856282 -10.0 +v -110.56873433140078 154.65727911147232 -10.0 +v -71.73195670069174 24.80246156696747 -10.0 +v -66.56191299351336 16.822146889176754 -10.0 +v -57.47399949333125 16.375773056706407 -10.0 +v -52.40112634816329 22.469668797807255 -10.0 +v -166.96426211048424 70.385973194771 -10.0 +v -179.23192725936863 61.80318698035899 -10.0 +v -88.69422404576852 129.6694305325907 -10.0 +v -136.21485140975886 108.17019137977269 -10.0 +v -133.2054296001303 116.87019483999154 -10.0 +v -137.45796418074139 124.34647456323945 -10.0 +v -75.92586906245883 41.59926399575145 -10.0 +v -69.05399628925638 9.458216470913737 -10.0 +v -12.566572203762508 149.56075146378697 -10.0 +v -19.31546983634809 143.84219703854268 -10.0 +v -114.7968604000771 121.44090235560448 -10.0 +v -106.59683511965208 120.03837444788589 -10.0 +v -112.46058398821174 113.19383432910763 -10.0 +v -103.79512254140776 112.5775905962738 -10.0 +v -78.55117919390311 52.36757171218854 -10.0 +v -101.65789746937159 126.64235334361702 -10.0 +v -97.36520334842065 97.62616152063724 -10.0 +v -110.07664451058537 105.14110934238123 -10.0 +v -120.63070665700958 114.53618048163405 -10.0 +v -127.59545086979477 111.08457023353913 -10.0 +v -84.92890185938371 138.86761580983347 -10.0 +v -73.5334343737174 34.166696207816926 -10.0 +v -91.94460973105883 146.61200255335748 -10.0 +v -102.7837008134617 149.0632233620782 -10.0 +v -147.21501196993654 137.14609675533566 -10.0 +v -86.80773501061078 202.83109437700378 -10.0 +v -98.58018726698994 119.87032050328325 -10.0 +v -141.11543834219395 131.9107245740923 -10.0 +v -55.57453807726806 44.87722893206972 -10.0 +v -145.59591516103634 124.12033394877476 -10.0 +v -115.24428130213164 142.5589140592931 -10.0 +v -84.78659718782622 72.3373679748638 -10.0 +v -77.40071465845081 139.0121137476148 -10.0 +v -163.30283152017378 77.41244750040703 -10.0 +v -129.7399151522091 124.25909662143171 -10.0 +v -15.414403146806585 136.17184595580434 -10.0 +v -29.816751282996158 142.30887133715973 -10.0 +v -100.36243383841085 163.05064047579359 -10.0 +v -44.68796992696312 143.60667606514036 -10.0 +v -115.10036498536482 164.44151577735752 -10.0 +v -56.9270288371536 8.503313084216492 -10.0 +v -50.71124127425364 12.662660906820408 -10.0 +v -44.25081263248774 24.437135524813453 -10.0 +v -142.3934668560258 101.56372633151004 -10.0 +v -7.768196597964453 153.25674051409266 -10.0 +v -78.37668440984068 59.97022527437368 -10.0 +v -93.25601766220184 89.44088171196435 -10.0 +v -81.80397686948136 22.09083461396302 -10.0 +v -182.8028881521716 70.87542394540759 -10.0 +v -27.53181776661814 155.82180672084945 -10.0 +v -173.47475178294061 59.055267843154056 -10.0 +v -95.74883447809327 112.99914233717453 -10.0 +v -89.07391216636267 79.70347975490343 -10.0 +v -97.09353709184268 168.91385892921875 -10.0 +v -121.63267246107056 163.30479642068167 -10.0 +v -169.59969865827628 54.18974610922418 -10.0 +v -30.089289496359648 136.01826189485905 -10.0 +v -103.55369151192792 157.16683573508746 -10.0 +v -100.93253342882522 105.31402183259011 -10.0 +v -92.3553207784182 190.51153119469672 -10.0 +v -172.68685153415072 65.09196268593557 -10.0 +v -62.630292877363985 11.319315110512372 -10.0 +v -110.58894117444848 147.55256360231635 -10.0 +v -6.334557913073101 147.0080565599221 -10.0 +v -26.01937589459724 149.07098718702784 -10.0 +v -94.89477521804297 126.09444472552833 -10.0 +v -50.09998557118215 42.830181832596594 -10.0 +v -85.75047545989118 210.33160652997756 -10.0 +v -92.09107394976247 137.81982712099506 -10.0 +v -183.237262544323 55.03547426628854 -10.0 +v -133.95456565533968 140.75235413956113 -10.0 +v -49.617607658301104 30.398395070110706 -10.0 +v -95.29549562271511 175.8339607785908 -10.0 +v -37.96109706726583 144.72332992063713 -10.0 +v -88.20240428743541 195.8098632948956 -10.0 +v -72.5550344666457 54.413171209256355 -10.0 +v -126.79734757564225 117.95366379091912 -10.0 +v -28.258440151416373 161.3168538189603 -10.0 +v -83.4543975417556 65.08000379799563 -10.0 +v -80.53651683589368 37.30639298460086 -10.0 +v -53.24901614176597 37.21465969289774 -10.0 +v -128.9482251766824 104.31788098259726 -10.0 +f 9 10 243 +f 243 242 9 +f 10 11 244 +f 244 243 10 +f 11 12 245 +f 245 244 11 +f 12 13 246 +f 246 245 12 +f 13 14 247 +f 247 246 13 +f 14 15 248 +f 248 247 14 +f 15 16 249 +f 249 248 15 +f 16 17 250 +f 250 249 16 +f 17 18 251 +f 251 250 17 +f 18 19 252 +f 252 251 18 +f 19 20 253 +f 253 252 19 +f 20 21 254 +f 254 253 20 +f 21 22 255 +f 255 254 21 +f 22 23 256 +f 256 255 22 +f 23 24 257 +f 257 256 23 +f 24 25 258 +f 258 257 24 +f 25 26 259 +f 259 258 25 +f 26 27 260 +f 260 259 26 +f 27 28 261 +f 261 260 27 +f 28 29 262 +f 262 261 28 +f 29 30 263 +f 263 262 29 +f 30 31 264 +f 264 263 30 +f 31 32 265 +f 265 264 31 +f 32 33 266 +f 266 265 32 +f 33 34 267 +f 267 266 33 +f 34 35 268 +f 268 267 34 +f 35 36 269 +f 269 268 35 +f 36 37 270 +f 270 269 36 +f 37 38 271 +f 271 270 37 +f 38 39 272 +f 272 271 38 +f 39 40 273 +f 273 272 39 +f 40 41 274 +f 274 273 40 +f 41 42 275 +f 275 274 41 +f 42 43 276 +f 276 275 42 +f 43 44 277 +f 277 276 43 +f 44 45 278 +f 278 277 44 +f 45 46 279 +f 279 278 45 +f 46 47 280 +f 280 279 46 +f 47 48 281 +f 281 280 47 +f 48 49 282 +f 282 281 48 +f 49 50 283 +f 283 282 49 +f 50 51 284 +f 284 283 50 +f 51 52 285 +f 285 284 51 +f 52 53 286 +f 286 285 52 +f 53 54 287 +f 287 286 53 +f 54 55 288 +f 288 287 54 +f 55 56 289 +f 289 288 55 +f 56 57 290 +f 290 289 56 +f 57 58 291 +f 291 290 57 +f 58 59 292 +f 292 291 58 +f 59 60 293 +f 293 292 59 +f 60 61 294 +f 294 293 60 +f 61 62 295 +f 295 294 61 +f 62 63 296 +f 296 295 62 +f 63 64 297 +f 297 296 63 +f 64 65 298 +f 298 297 64 +f 65 66 299 +f 299 298 65 +f 66 67 300 +f 300 299 66 +f 67 68 301 +f 301 300 67 +f 68 69 302 +f 302 301 68 +f 69 70 303 +f 303 302 69 +f 70 71 304 +f 304 303 70 +f 71 72 305 +f 305 304 71 +f 72 73 306 +f 306 305 72 +f 73 74 307 +f 307 306 73 +f 74 75 308 +f 308 307 74 +f 75 76 309 +f 309 308 75 +f 76 77 310 +f 310 309 76 +f 77 78 311 +f 311 310 77 +f 78 79 312 +f 312 311 78 +f 79 80 313 +f 313 312 79 +f 80 81 314 +f 314 313 80 +f 81 82 315 +f 315 314 81 +f 82 83 316 +f 316 315 82 +f 83 84 317 +f 317 316 83 +f 84 85 318 +f 318 317 84 +f 85 86 319 +f 319 318 85 +f 86 87 320 +f 320 319 86 +f 87 88 321 +f 321 320 87 +f 88 89 322 +f 322 321 88 +f 89 90 323 +f 323 322 89 +f 90 91 324 +f 324 323 90 +f 91 92 325 +f 325 324 91 +f 92 93 326 +f 326 325 92 +f 93 94 327 +f 327 326 93 +f 94 95 328 +f 328 327 94 +f 95 96 329 +f 329 328 95 +f 96 97 330 +f 330 329 96 +f 97 1 234 +f 234 330 97 +f 1 2 235 +f 235 234 1 +f 2 3 236 +f 236 235 2 +f 3 4 237 +f 237 236 3 +f 4 5 238 +f 238 237 4 +f 5 6 239 +f 239 238 5 +f 6 7 240 +f 240 239 6 +f 7 8 241 +f 241 240 7 +f 8 9 242 +f 242 241 8 +f 9 10 243 +f 243 242 9 diff --git a/share/mesh/SOFA_surface.obj b/share/mesh/SOFA_surface.obj new file mode 100644 index 00000000000..0bb37757fac --- /dev/null +++ b/share/mesh/SOFA_surface.obj @@ -0,0 +1,2409 @@ +# Created by meshio v5.3.5, 2024-09-24T17:57:39.586615 +v -192.2342 60.457245 10.0 +v -189.31730740740738 52.82884722222222 10.0 +v -183.41376592592582 47.61546277777778 10.0 +v -173.6132583333333 45.920255000000004 10.0 +v -165.85462666666666 48.92924000000001 10.0 +v -160.16704666666664 56.09198166666665 10.0 +v -158.8940022222222 63.55143388888888 10.0 +v -159.85787305555553 69.48050222222223 10.0 +v -156.35730337962963 75.55829546296297 10.0 +v -152.8567337037037 81.63608870370372 10.0 +v -145.51108629629633 90.81706796296298 10.0 +v -140.0664062037037 95.52332750000002 10.0 +v -134.6217261111111 100.22958703703705 10.0 +v -125.79946277777776 97.92726842592593 10.0 +v -115.953295 97.23594333333337 10.0 +v -106.06834694444444 96.98207342592596 10.0 +v -100.3339277777778 87.90088314814818 10.0 +v -96.23609499999999 80.05152500000003 10.0 +v -91.15257314814814 68.62492833333336 10.0 +v -87.03835351851848 57.34572500000003 10.0 +v -83.74313000000001 44.80251500000002 10.0 +v -87.66622499999998 37.096515000000025 10.0 +v -89.74371333333333 26.562383333333358 10.0 +v -86.88399333333336 14.815341600000025 10.0 +v -79.86389111111112 6.052006637592616 10.0 +v -70.11096555555555 1.0513059157407634 10.0 +v -61.64934916666667 0.09322213000002247 10.0 +v -55.02271962037037 2.1985434212963106 10.0 +v -48.39609007407407 4.303864712592599 10.0 +v -40.186471592592554 12.732514897407409 10.0 +v -38.24271392129628 19.346265782037037 10.0 +v -36.29895625 25.960016666666668 10.0 +v -37.29351061111111 33.92115018518518 10.0 +v -40.633671194444446 39.63476671296296 10.0 +v -43.973831777777775 45.34838324074073 10.0 +v -49.97722092592592 50.13503537037036 10.0 +v -57.59017840740741 52.96834796296295 10.0 +v -66.19233837962963 54.088347361111104 10.0 +v -71.86131314814816 60.90463675925926 10.0 +v -75.91777944444445 67.1217724074074 10.0 +v -79.36642833333333 73.53597833333333 10.0 +v -82.81507722222221 79.95018425925926 10.0 +v -86.19711277777778 87.81599125 10.0 +v -89.57914833333334 95.68179824074073 10.0 +v -92.66648541666666 105.96417962962963 10.0 +v -86.89993870370371 113.6386588888889 10.0 +v -83.04949462962965 121.06399111111115 10.0 +v -76.95362795138888 132.31780457175927 10.0 +v -70.04030569791666 134.22793747106482 10.0 +v -63.12698344444444 136.13807037037037 10.0 +v -52.43966322222221 137.70537962962962 10.0 +v -45.60637582870369 137.37204777777777 10.0 +v -38.77308843518518 137.0387159259259 10.0 +v -31.333042462962958 130.26321814814813 10.0 +v -22.84061575 127.38542166666666 10.0 +v -12.125082784074074 128.8794311111111 10.0 +v -5.313775472592594 133.78004888888893 10.0 +v -0.5900747368970809 142.69963833333333 10.0 +v -0.32077573758249756 151.01752499999998 10.0 +v -3.7391141985185157 159.69738037037033 10.0 +v -8.05902612481481 164.16445296296294 10.0 +v -13.517511999999996 167.12332999999995 10.0 +v -20.675108999999992 168.34940888888886 10.0 +v -27.64777533333333 167.10740777777775 10.0 +v -33.877182999999995 163.49677999999994 10.0 +v -38.19886699999999 158.13752833333325 10.0 +v -41.82407624999999 150.65757249999996 10.0 +v -48.64911351851851 148.5135555555555 10.0 +v -55.12316081481481 147.0686377777777 10.0 +v -64.58940907407407 145.502692037037 10.0 +v -73.34119018518518 144.6388659259259 10.0 +v -81.93915148148147 146.0783130555555 10.0 +v -87.7921037037037 156.5167438888888 10.0 +v -93.14944 162.89553333333328 10.0 +v -92.39023888888889 171.5462068518518 10.0 +v -90.4536961111111 178.66252370370367 10.0 +v -88.043635 184.83019666666667 10.0 +v -85.63357388888889 190.99786962962963 10.0 +v -82.41569722222222 197.0997860185185 10.0 +v -77.88146222222221 204.59082476851844 10.0 +v -72.67621055555556 211.81439907407403 10.0 +v -73.66474944444445 219.37477092592593 10.0 +v -78.65621666666667 223.9302066666666 10.0 +v -86.87440833333335 223.70262166666657 10.0 +v -92.81708166666664 216.84273999999994 10.0 +v -92.65223499999999 209.20385499999992 10.0 +v -94.4578737037037 196.914474074074 10.0 +v -97.2777946296296 185.9085259259259 10.0 +v -100.1594729398148 178.62421442129624 10.0 +v -103.04115125 171.3399029166666 10.0 +v -112.11144648148147 171.35005407407402 10.0 +v -123.51036842592592 171.13475379629622 10.0 +v -126.86862296296295 163.15518481481473 10.0 +v -131.39186518518517 154.98269925925916 10.0 +v -138.7159614814815 147.54539999999992 10.0 +v -145.25479851851856 144.45964333333328 10.0 +v -153.68033000000003 142.9850049999999 10.0 +v -155.4393640740741 133.79316740740734 10.0 +v -154.37636592592597 125.58727259259257 10.0 +v -150.5701890740741 116.14194944444435 10.0 +v -145.56223212962965 108.56584944444434 10.0 +v -150.0574383333333 100.03593583333323 10.0 +v -156.7614892592593 92.2815485185184 10.0 +v -163.72093740740743 85.32462814814801 10.0 +v -170.3772353240741 80.06991004629617 10.0 +v -180.58388435185188 78.10908324074062 10.0 +v -188.65461888888893 72.56539074074061 10.0 +v -192.1384777777778 63.03370259259246 10.0 +v -149.18391000001193 86.22657833331846 10.0 +v -103.20113736112101 92.44147828705273 10.0 +v -93.69433407408025 74.3382266666806 10.0 +v -89.09546333333697 62.98532666667673 10.0 +v -85.390741759263 51.074120000014304 10.0 +v -88.70496916666403 31.829449166680053 10.0 +v -88.31385333333677 20.68886246668074 10.0 +v -83.37394222224493 10.433674118824648 10.0 +v -74.9874283333426 3.5516562766714417 10.0 +v -44.29128083334392 8.51818980498911 10.0 +v -91.12281687499541 100.8229889351699 10.0 +v -80.00156129051929 126.6908978414167 10.0 +v -57.78332333334907 136.92172499999768 10.0 +v -17.482849267052096 128.13242638888678 10.0 +v -84.86562759257572 151.29752847219208 10.0 +v -93.5550543518495 203.05916453705288 10.0 +v -95.86783416666265 191.4115000000156 10.0 +v -117.81090745368427 171.24240393518548 10.0 +v -135.05391333332506 151.26404962963795 10.0 +v -152.47327750000352 120.86461101852709 10.0 +v -153.40946379629256 96.15874217593016 10.0 +v -175.48055983795228 79.08949664352045 10.0 +v -190.39654833332625 67.79954666668604 10.0 +v -112.61363976482797 132.37651196857635 10.0 +v -62.794126187428034 26.925572070958196 10.0 +v -132.74869116817663 126.23527104176367 10.0 +v -20.66359310947816 149.39137347776946 10.0 +v -179.69156181921727 60.39157277237746 10.0 +v -107.48106372885374 114.24625118970177 10.0 +v -109.21810432265733 151.66018759499505 10.0 +v -94.86269038634182 135.45345358234098 10.0 +v -123.52016149379807 144.26158254426875 10.0 +v -71.88487417537208 16.65899176023219 10.0 +v -75.71009647407351 32.205572105651505 10.0 +v -124.10280001092862 113.31299015657467 10.0 +v -51.04832026637624 18.558700896176642 10.0 +v -143.2508098410173 127.32575796537697 10.0 +v -97.49071268910893 148.05335475646126 10.0 +v -54.05740310300297 34.69019513104045 10.0 +v -170.9019814538135 69.02904101182762 10.0 +v -65.2889915322752 39.712855367306084 10.0 +v -132.8459531417201 137.74870352128752 10.0 +v -96.66947260896579 120.54485361629601 10.0 +v -120.45179735294654 153.40995811694273 10.0 +v -15.871759930713631 137.78249437455995 10.0 +v -60.38894972246748 12.210702200485459 10.0 +v -102.85345496547308 106.31323695482779 10.0 +v -120.58551674578825 124.50579855243562 10.0 +v -114.7795800313773 161.68170680093095 10.0 +v -30.18574206346438 146.1793633707325 10.0 +v -104.91720124259349 140.65616972555046 10.0 +v -12.950704632958375 155.5691166242777 10.0 +v -79.47794031946907 22.719085188097328 10.0 +v -135.60752775043986 114.92276253513306 10.0 +v -23.513868317172488 157.71701534552506 10.0 +v -104.02504876597546 160.65854566510868 10.0 +v -46.51768506114806 28.629529067959663 10.0 +v -170.4382460616899 58.633248249806435 10.0 +v -124.45710068417264 133.21832106616432 10.0 +v -85.4002835769833 137.0409235615415 10.0 +v -180.72588141053458 69.49557023237567 10.0 +v -74.87800591642414 41.48219118175313 10.0 +v -10.87057202155038 146.23542013347412 10.0 +v -97.35613889490511 114.15554864202421 10.0 +v -98.57130960258112 99.09161278505954 10.0 +v -106.5666497668307 123.69623933588376 10.0 +v -185.7538129574276 61.56469022622263 10.0 +v -142.38570865820594 136.90413894358718 10.0 +v -89.0471335772174 127.95168164118039 10.0 +v -127.56819287210189 147.18832534292295 10.0 +v -68.84743632079375 8.84462574458947 10.0 +v -26.682333077462346 140.69907084238028 10.0 +v -82.13722757315318 214.30708683055687 10.0 +v -75.58281832608827 51.25183024046182 10.0 +v -114.06659932804132 144.29958734278853 10.0 +v -142.30733973898768 118.48202755775482 10.0 +v -89.74748016578735 144.1975480564824 10.0 +v -50.987539729146626 12.235796138012141 10.0 +v -71.4514914213818 24.518368776615684 10.0 +v -115.34408492336009 107.37910985789038 10.0 +v -54.753644159520675 27.540095866655633 10.0 +v -165.47020390849775 74.59206134275321 10.0 +v -102.15947228005643 131.02965339744247 10.0 +v -116.24991264786372 118.69194089054814 10.0 +v -29.206795819261156 153.91930957675152 10.0 +v -64.0372819804237 20.06164387409527 10.0 +v -57.51625586975341 44.49488688221496 10.0 +v -94.92011156920341 92.13678199092148 10.0 +v -81.71918535734214 28.229754562335884 10.0 +v -77.16555954984904 15.978187345693062 10.0 +v -20.664799558686134 133.26579715347685 10.0 +v -118.3086269359735 135.691414362191 10.0 +v -79.587763257123 36.68951183888918 10.0 +v -130.3633504040716 107.8263417305775 10.0 +v -126.87574606269612 120.64944880742733 10.0 +v -133.13756623719271 145.33352134996 10.0 +v -176.56832393098423 54.45182506046542 10.0 +v -66.54012127794655 31.883470628765625 10.0 +v -93.74433282394848 86.30702333472244 10.0 +v -81.89428372790314 62.31292181003704 10.0 +v -135.4794376958717 132.13668494573707 10.0 +v -109.2541471627385 103.47605785834577 10.0 +v -95.12742666015211 155.12818405338663 10.0 +v -85.83935550590081 205.0641914260199 10.0 +v -60.83960169234864 33.69183662870564 10.0 +v -165.22907388171194 65.5644412741443 10.0 +v -75.60703232475981 10.428456097924188 10.0 +v -98.91722462951948 140.8536487605854 10.0 +v -31.758330602827662 138.65591914712004 10.0 +v -176.5870327643798 72.91436322592749 10.0 +v -46.262217846952595 15.511816704556345 10.0 +v -86.93553417805927 74.20042873321275 10.0 +v -89.91788090996734 121.99111666059198 10.0 +v -102.51305084288111 154.4502879198301 10.0 +v -17.840968756026474 161.18931135269943 10.0 +v -138.58310036027464 122.68923657406965 10.0 +v -46.377351676871676 35.57531013637028 10.0 +v -68.8666768011649 46.663393842186345 10.0 +v -148.61184155737973 125.16542586230193 10.0 +v -148.05003260581543 132.19252685675707 10.0 +v -113.16158095979287 125.48394037087797 10.0 +v -138.27510069689401 141.52543913728053 10.0 +v -108.6998243895774 165.25540687556511 10.0 +v -50.728618685192785 41.71045417583674 10.0 +v -122.77090688990447 105.52114657783105 10.0 +v -57.24451439464515 22.516937108008147 10.0 +v -183.646957085236 55.649757206200555 10.0 +v -90.89825784110239 149.38593653933265 10.0 +v -38.23285761547356 144.2299086965887 10.0 +v -103.17670934898433 118.64055054368569 10.0 +v -78.60116614794693 139.61846861315385 10.0 +v -44.17088320560375 22.214632534220133 10.0 +v -185.224251261044 66.6119032219068 10.0 +v -89.93708101268132 80.44389654064581 10.0 +v -88.67945621608992 198.11492678415127 10.0 +v -114.67259568601912 155.63100399560747 10.0 +v -62.71039794180494 6.783561101371762 10.0 +v -128.1718242752539 141.24505127464408 10.0 +v -176.46387971984902 65.91361074063495 10.0 +v -9.295022756077598 140.28467594984272 10.0 +v -154.80576656378688 86.96004552720281 10.0 +v -151.56068129218465 91.17278572956354 10.0 +v -95.37364860863566 129.0445938596803 10.0 +v -79.87515919057925 55.386436107996126 10.0 +v -126.38126598161969 152.6040450303485 10.0 +v -130.25125394537474 132.23814600352435 10.0 +v -142.74283416397503 101.08935229015907 10.0 +v -137.88380127505246 107.10790202536317 10.0 +v -119.6710540772821 165.57142954285834 10.0 +v -97.6913703339818 103.93468193119973 10.0 +v -84.0603436942042 68.1302260473334 10.0 +v -118.99642103444621 147.1408627054416 10.0 +v -147.22465168096423 95.79953524865813 10.0 +v -15.377805279731225 132.73599141350533 10.0 +v -8.178490788127922 152.50345642799454 10.0 +v -66.13341888644547 14.17678182480144 10.0 +v -118.91793994505413 130.31282400540107 10.0 +v -126.00422388247239 127.31435667281222 10.0 +v -111.84350422253367 139.20774846846476 10.0 +v -102.73925499460077 111.87946956642377 10.0 +v -25.78504776466719 149.61370018636947 10.0 +v -49.00684341305548 142.62164852292943 10.0 +v -170.1920386370679 74.91233538657211 10.0 +v -83.22459718541577 18.907332042128427 10.0 +v -102.83231069486008 101.15047760601426 10.0 +v -83.77798471229748 131.13915527305468 10.0 +v -120.27513162406541 159.62573633168427 10.0 +v -103.56908226143673 146.92671864600814 10.0 +v -18.863991888843884 154.57611488571482 10.0 +v -132.80987861826344 120.35726111880774 10.0 +v -108.49287394020055 109.30385741640775 10.0 +v -84.81588491280799 24.51348984319275 10.0 +v -55.81355621549013 15.73767189688498 10.0 +v -26.7585691735779 135.1321523346713 10.0 +v -56.36710707452994 8.510197592189758 10.0 +v -28.482181152571982 160.72053429435744 10.0 +v -188.59886732229197 64.44122709096534 10.0 +v -35.14605780294754 151.94058641811327 10.0 +v -55.298618931071 141.31242602796476 10.0 +v -161.56189185740607 79.29332031483796 10.0 +v -148.96204677132283 138.0668963082169 10.0 +v -91.19931014912805 193.0082170034069 10.0 +v -114.87835533587725 166.9112959015805 10.0 +v -108.98470067308128 158.22285647533954 10.0 +v -84.02525788602065 33.091169269171324 10.0 +v -147.41225974396417 119.80135805038064 10.0 +v -16.621265073661583 143.94777552506966 10.0 +v -71.95835263535592 36.06334363664765 10.0 +v -67.96407680668207 140.17918659291422 10.0 +v -94.33266397453244 97.08812655783045 10.0 +v -99.39221131056253 165.59851466634262 10.0 +v -63.09088819804611 47.58556628315628 10.0 +v -101.6646503585405 125.57241167590148 10.0 +v -121.51116541707808 118.64640043974792 10.0 +v -89.88038281261694 139.28053138299745 10.0 +v -9.040773219884631 158.892712064265 10.0 +v -91.91003719590783 188.14076711231542 10.0 +v -74.14800920058578 21.23760440934918 10.0 +v -110.01475949884141 119.37457438091921 10.0 +v -106.446228584111 134.67923571423322 10.0 +v -108.84871602374449 146.12666165169193 10.0 +v -129.62284374164608 114.96946825201876 10.0 +v -93.38156823838149 111.80437333571398 10.0 +v -89.72368727901542 133.31838988346584 10.0 +v -43.996148393030694 145.3986806148298 10.0 +v -76.2811373801007 27.352713349381915 10.0 +v -97.78137880733482 109.0085816766365 10.0 +v -41.23557227625154 29.380921118044053 10.0 +v -114.59394361840621 150.17527311624409 10.0 +v -165.2795875994173 59.99195817074071 10.0 +v -78.1622595364689 46.12832000877525 10.0 +v -87.04434282596489 212.05165588195266 10.0 +v -171.08466996844345 63.69568543258864 10.0 +v -85.16665229882163 142.13291317199653 10.0 +v -157.85622484948323 82.06134319474958 10.0 +v -50.13766507824386 24.82782925274673 10.0 +v -14.691436252436716 150.37054284571667 10.0 +v -50.70595416894695 30.895639426479697 10.0 +v -123.43804911924559 149.10869755713824 10.0 +v -91.11017637606575 90.48539870409614 10.0 +v -93.85690228060476 182.0541723432715 10.0 +v -69.03251566312554 20.631270677946297 10.0 +v -145.2140546766078 115.00148940980999 10.0 +v -112.8482902689793 113.30373091174762 10.0 +v -168.65351487645964 54.00308469127986 10.0 +v -60.647595400739235 141.1871229676769 10.0 +v -123.48291525400015 138.69753943861318 10.0 +v -93.34268393946915 116.690120003289 10.0 +v -5.765276913217555 146.35002566264848 10.0 +v -99.22146010593194 94.3599450985287 10.0 +v -23.571259330208818 163.1727702469831 10.0 +v -185.32357043705238 70.07729284202841 10.0 +v -182.37499757054152 72.63234005636255 10.0 +v -174.9548547207055 60.28666718068122 10.0 +v -11.596689244637826 134.69252834758157 10.0 +v -57.98056153379969 38.67009437093907 10.0 +v -100.02861794443483 135.70412994233672 10.0 +v -189.3461090083697 61.3540636257212 10.0 +v -188.0250449680746 57.67340490878471 10.0 +v -107.26184612814806 128.95409911412204 10.0 +v -94.20973569807228 143.19423406745048 10.0 +v -130.7065607218849 150.2745281224257 10.0 +v -166.203594585317 70.2542126651304 10.0 +v -67.23760910282147 4.764658638841699 10.0 +v -45.59804557577396 40.565741975161146 10.0 +v -81.05958689501233 135.0208250793613 10.0 +v -151.24040377732902 128.84315250369076 10.0 +v -161.23523515938143 74.00653630768495 10.0 +v -118.36970471146549 141.54978914362792 10.0 +v -76.85238297985545 59.99831447206051 10.0 +v -84.96354615726295 125.69986238922839 10.0 +v -140.950893498254 131.89828077301965 10.0 +v -86.47913530998382 146.8463292825033 10.0 +v -79.65361018697368 32.164916791472955 10.0 +v -118.45837264148139 112.68596015219606 10.0 +v -78.92819673773052 218.6198585691766 10.0 +v -137.65592359013507 136.59052450646803 10.0 +v -86.07192219907705 28.65863232537254 10.0 +v -95.78500244067857 176.36351895660462 10.0 +v -128.05516512007566 136.55663883070335 10.0 +v -166.0473687501964 78.79842142161944 10.0 +v -181.57187743361453 64.7954694387035 10.0 +v -125.11185176776982 157.19827042727886 10.0 +v -81.99341035080363 14.336458622261908 10.0 +v -21.481932430910486 139.0677094448596 10.0 +v -98.66624937952757 160.06687670784856 10.0 +v -144.03307024832472 122.69276120197681 10.0 +v -95.11096110226923 100.89302327462225 10.0 +v -23.56998558660736 144.81649880786347 10.0 +v -23.606659379884576 153.04350269442605 10.0 +v -81.61761551160266 208.90917197923758 10.0 +v -71.45030333794237 29.408002676976903 10.0 +v -79.60076711175371 11.445756564459282 10.0 +v -52.02264592266354 7.073052969855479 10.0 +v -80.80747674200319 41.23981060588351 10.0 +v -32.98221695495612 157.64294772451106 10.0 +v -59.11305344463253 29.471876752306617 10.0 +v -141.00163728049768 112.5875080109367 10.0 +v -86.02947721911154 217.35567758002233 10.0 +v -25.399256736306747 131.5116473257407 10.0 +v -101.97891294178771 96.80511744051623 10.0 +v -60.25846782504612 17.012106254241132 10.0 +v -73.30072772916478 138.43053437553104 10.0 +v -12.281796946736858 161.387784600841 10.0 +v -42.36092783617979 140.96960487852178 10.0 +v -72.86989652928646 7.050578302506484 10.0 +v -138.35446803029726 127.97266195385718 10.0 +v -70.09265515964667 40.75441747867028 10.0 +v -128.38886154571622 102.87608594284286 10.0 +v -71.67914179853301 55.29061261460011 10.0 +v -42.21557164161129 17.451307479555226 10.0 +v -80.51360318574571 50.10824259419291 10.0 +v -71.59641361361157 12.208916381791504 10.0 +v -67.55097331137466 25.57138811755966 10.0 +v -192.2342 60.457245 -10.0 +v -189.31730740740738 52.82884722222222 -10.0 +v -183.41376592592582 47.61546277777778 -10.0 +v -173.6132583333333 45.920255000000004 -10.0 +v -165.85462666666666 48.92924000000001 -10.0 +v -160.16704666666664 56.09198166666665 -10.0 +v -158.8940022222222 63.55143388888888 -10.0 +v -159.85787305555553 69.48050222222223 -10.0 +v -156.35730337962963 75.55829546296297 -10.0 +v -152.8567337037037 81.63608870370372 -10.0 +v -145.51108629629633 90.81706796296298 -10.0 +v -140.0664062037037 95.52332750000002 -10.0 +v -134.6217261111111 100.22958703703705 -10.0 +v -125.79946277777776 97.92726842592593 -10.0 +v -115.953295 97.23594333333337 -10.0 +v -106.06834694444444 96.98207342592596 -10.0 +v -100.3339277777778 87.90088314814818 -10.0 +v -96.23609499999999 80.05152500000003 -10.0 +v -91.15257314814814 68.62492833333336 -10.0 +v -87.03835351851848 57.34572500000003 -10.0 +v -83.74313000000001 44.80251500000002 -10.0 +v -87.66622499999998 37.096515000000025 -10.0 +v -89.74371333333333 26.562383333333358 -10.0 +v -86.88399333333336 14.815341600000025 -10.0 +v -79.86389111111112 6.052006637592616 -10.0 +v -70.11096555555555 1.0513059157407634 -10.0 +v -61.64934916666667 0.09322213000002247 -10.0 +v -55.02271962037037 2.1985434212963106 -10.0 +v -48.39609007407407 4.303864712592599 -10.0 +v -40.186471592592554 12.732514897407409 -10.0 +v -38.24271392129628 19.346265782037037 -10.0 +v -36.29895625 25.960016666666668 -10.0 +v -37.29351061111111 33.92115018518518 -10.0 +v -40.633671194444446 39.63476671296296 -10.0 +v -43.973831777777775 45.34838324074073 -10.0 +v -49.97722092592592 50.13503537037036 -10.0 +v -57.59017840740741 52.96834796296295 -10.0 +v -66.19233837962963 54.088347361111104 -10.0 +v -71.86131314814816 60.90463675925926 -10.0 +v -75.91777944444445 67.1217724074074 -10.0 +v -79.36642833333333 73.53597833333333 -10.0 +v -82.81507722222221 79.95018425925926 -10.0 +v -86.19711277777778 87.81599125 -10.0 +v -89.57914833333334 95.68179824074073 -10.0 +v -92.66648541666666 105.96417962962963 -10.0 +v -86.89993870370371 113.6386588888889 -10.0 +v -83.04949462962965 121.06399111111115 -10.0 +v -76.95362795138888 132.31780457175927 -10.0 +v -70.04030569791666 134.22793747106482 -10.0 +v -63.12698344444444 136.13807037037037 -10.0 +v -52.43966322222221 137.70537962962962 -10.0 +v -45.60637582870369 137.37204777777777 -10.0 +v -38.77308843518518 137.0387159259259 -10.0 +v -31.333042462962958 130.26321814814813 -10.0 +v -22.84061575 127.38542166666666 -10.0 +v -12.125082784074074 128.8794311111111 -10.0 +v -5.313775472592594 133.78004888888893 -10.0 +v -0.5900747368970809 142.69963833333333 -10.0 +v -0.32077573758249756 151.01752499999998 -10.0 +v -3.7391141985185157 159.69738037037033 -10.0 +v -8.05902612481481 164.16445296296294 -10.0 +v -13.517511999999996 167.12332999999995 -10.0 +v -20.675108999999992 168.34940888888886 -10.0 +v -27.64777533333333 167.10740777777775 -10.0 +v -33.877182999999995 163.49677999999994 -10.0 +v -38.19886699999999 158.13752833333325 -10.0 +v -41.82407624999999 150.65757249999996 -10.0 +v -48.64911351851851 148.5135555555555 -10.0 +v -55.12316081481481 147.0686377777777 -10.0 +v -64.58940907407407 145.502692037037 -10.0 +v -73.34119018518518 144.6388659259259 -10.0 +v -81.93915148148147 146.0783130555555 -10.0 +v -87.7921037037037 156.5167438888888 -10.0 +v -93.14944 162.89553333333328 -10.0 +v -92.39023888888889 171.5462068518518 -10.0 +v -90.4536961111111 178.66252370370367 -10.0 +v -88.043635 184.83019666666667 -10.0 +v -85.63357388888889 190.99786962962963 -10.0 +v -82.41569722222222 197.0997860185185 -10.0 +v -77.88146222222221 204.59082476851844 -10.0 +v -72.67621055555556 211.81439907407403 -10.0 +v -73.66474944444445 219.37477092592593 -10.0 +v -78.65621666666667 223.9302066666666 -10.0 +v -86.87440833333335 223.70262166666657 -10.0 +v -92.81708166666664 216.84273999999994 -10.0 +v -92.65223499999999 209.20385499999992 -10.0 +v -94.4578737037037 196.914474074074 -10.0 +v -97.2777946296296 185.9085259259259 -10.0 +v -100.1594729398148 178.62421442129624 -10.0 +v -103.04115125 171.3399029166666 -10.0 +v -112.11144648148147 171.35005407407402 -10.0 +v -123.51036842592592 171.13475379629622 -10.0 +v -126.86862296296295 163.15518481481473 -10.0 +v -131.39186518518517 154.98269925925916 -10.0 +v -138.7159614814815 147.54539999999992 -10.0 +v -145.25479851851856 144.45964333333328 -10.0 +v -153.68033000000003 142.9850049999999 -10.0 +v -155.4393640740741 133.79316740740734 -10.0 +v -154.37636592592597 125.58727259259257 -10.0 +v -150.5701890740741 116.14194944444435 -10.0 +v -145.56223212962965 108.56584944444434 -10.0 +v -150.0574383333333 100.03593583333323 -10.0 +v -156.7614892592593 92.2815485185184 -10.0 +v -163.72093740740743 85.32462814814801 -10.0 +v -170.3772353240741 80.06991004629617 -10.0 +v -180.58388435185188 78.10908324074062 -10.0 +v -188.65461888888893 72.56539074074061 -10.0 +v -192.1384777777778 63.03370259259246 -10.0 +v -149.18391000001193 86.22657833331846 -10.0 +v -103.20113736112101 92.44147828705273 -10.0 +v -93.69433407408025 74.3382266666806 -10.0 +v -89.09546333333697 62.98532666667673 -10.0 +v -85.390741759263 51.074120000014304 -10.0 +v -88.70496916666403 31.829449166680053 -10.0 +v -88.31385333333677 20.68886246668074 -10.0 +v -83.37394222224493 10.433674118824648 -10.0 +v -74.9874283333426 3.5516562766714417 -10.0 +v -44.29128083334392 8.51818980498911 -10.0 +v -91.12281687499541 100.8229889351699 -10.0 +v -80.00156129051929 126.6908978414167 -10.0 +v -57.78332333334907 136.92172499999768 -10.0 +v -17.482849267052096 128.13242638888678 -10.0 +v -84.86562759257572 151.29752847219208 -10.0 +v -93.5550543518495 203.05916453705288 -10.0 +v -95.86783416666265 191.4115000000156 -10.0 +v -117.81090745368427 171.24240393518548 -10.0 +v -135.05391333332506 151.26404962963795 -10.0 +v -152.47327750000352 120.86461101852709 -10.0 +v -153.40946379629256 96.15874217593016 -10.0 +v -175.48055983795228 79.08949664352045 -10.0 +v -190.39654833332625 67.79954666668604 -10.0 +v -112.61363976482797 132.37651196857635 -10.0 +v -62.794126187428034 26.925572070958196 -10.0 +v -132.74869116817663 126.23527104176367 -10.0 +v -20.66359310947816 149.39137347776946 -10.0 +v -179.69156181921727 60.39157277237746 -10.0 +v -107.48106372885374 114.24625118970177 -10.0 +v -109.21810432265733 151.66018759499505 -10.0 +v -94.86269038634182 135.45345358234098 -10.0 +v -123.52016149379807 144.26158254426875 -10.0 +v -71.88487417537208 16.65899176023219 -10.0 +v -75.71009647407351 32.205572105651505 -10.0 +v -124.10280001092862 113.31299015657467 -10.0 +v -51.04832026637624 18.558700896176642 -10.0 +v -143.2508098410173 127.32575796537697 -10.0 +v -97.49071268910893 148.05335475646126 -10.0 +v -54.05740310300297 34.69019513104045 -10.0 +v -170.9019814538135 69.02904101182762 -10.0 +v -65.2889915322752 39.712855367306084 -10.0 +v -132.8459531417201 137.74870352128752 -10.0 +v -96.66947260896579 120.54485361629601 -10.0 +v -120.45179735294654 153.40995811694273 -10.0 +v -15.871759930713631 137.78249437455995 -10.0 +v -60.38894972246748 12.210702200485459 -10.0 +v -102.85345496547308 106.31323695482779 -10.0 +v -120.58551674578825 124.50579855243562 -10.0 +v -114.7795800313773 161.68170680093095 -10.0 +v -30.18574206346438 146.1793633707325 -10.0 +v -104.91720124259349 140.65616972555046 -10.0 +v -12.950704632958375 155.5691166242777 -10.0 +v -79.47794031946907 22.719085188097328 -10.0 +v -135.60752775043986 114.92276253513306 -10.0 +v -23.513868317172488 157.71701534552506 -10.0 +v -104.02504876597546 160.65854566510868 -10.0 +v -46.51768506114806 28.629529067959663 -10.0 +v -170.4382460616899 58.633248249806435 -10.0 +v -124.45710068417264 133.21832106616432 -10.0 +v -85.4002835769833 137.0409235615415 -10.0 +v -180.72588141053458 69.49557023237567 -10.0 +v -74.87800591642414 41.48219118175313 -10.0 +v -10.87057202155038 146.23542013347412 -10.0 +v -97.35613889490511 114.15554864202421 -10.0 +v -98.57130960258112 99.09161278505954 -10.0 +v -106.5666497668307 123.69623933588376 -10.0 +v -185.7538129574276 61.56469022622263 -10.0 +v -142.38570865820594 136.90413894358718 -10.0 +v -89.0471335772174 127.95168164118039 -10.0 +v -127.56819287210189 147.18832534292295 -10.0 +v -68.84743632079375 8.84462574458947 -10.0 +v -26.682333077462346 140.69907084238028 -10.0 +v -82.13722757315318 214.30708683055687 -10.0 +v -75.58281832608827 51.25183024046182 -10.0 +v -114.06659932804132 144.29958734278853 -10.0 +v -142.30733973898768 118.48202755775482 -10.0 +v -89.74748016578735 144.1975480564824 -10.0 +v -50.987539729146626 12.235796138012141 -10.0 +v -71.4514914213818 24.518368776615684 -10.0 +v -115.34408492336009 107.37910985789038 -10.0 +v -54.753644159520675 27.540095866655633 -10.0 +v -165.47020390849775 74.59206134275321 -10.0 +v -102.15947228005643 131.02965339744247 -10.0 +v -116.24991264786372 118.69194089054814 -10.0 +v -29.206795819261156 153.91930957675152 -10.0 +v -64.0372819804237 20.06164387409527 -10.0 +v -57.51625586975341 44.49488688221496 -10.0 +v -94.92011156920341 92.13678199092148 -10.0 +v -81.71918535734214 28.229754562335884 -10.0 +v -77.16555954984904 15.978187345693062 -10.0 +v -20.664799558686134 133.26579715347685 -10.0 +v -118.3086269359735 135.691414362191 -10.0 +v -79.587763257123 36.68951183888918 -10.0 +v -130.3633504040716 107.8263417305775 -10.0 +v -126.87574606269612 120.64944880742733 -10.0 +v -133.13756623719271 145.33352134996 -10.0 +v -176.56832393098423 54.45182506046542 -10.0 +v -66.54012127794655 31.883470628765625 -10.0 +v -93.74433282394848 86.30702333472244 -10.0 +v -81.89428372790314 62.31292181003704 -10.0 +v -135.4794376958717 132.13668494573707 -10.0 +v -109.2541471627385 103.47605785834577 -10.0 +v -95.12742666015211 155.12818405338663 -10.0 +v -85.83935550590081 205.0641914260199 -10.0 +v -60.83960169234864 33.69183662870564 -10.0 +v -165.22907388171194 65.5644412741443 -10.0 +v -75.60703232475981 10.428456097924188 -10.0 +v -98.91722462951948 140.8536487605854 -10.0 +v -31.758330602827662 138.65591914712004 -10.0 +v -176.5870327643798 72.91436322592749 -10.0 +v -46.262217846952595 15.511816704556345 -10.0 +v -86.93553417805927 74.20042873321275 -10.0 +v -89.91788090996734 121.99111666059198 -10.0 +v -102.51305084288111 154.4502879198301 -10.0 +v -17.840968756026474 161.18931135269943 -10.0 +v -138.58310036027464 122.68923657406965 -10.0 +v -46.377351676871676 35.57531013637028 -10.0 +v -68.8666768011649 46.663393842186345 -10.0 +v -148.61184155737973 125.16542586230193 -10.0 +v -148.05003260581543 132.19252685675707 -10.0 +v -113.16158095979287 125.48394037087797 -10.0 +v -138.27510069689401 141.52543913728053 -10.0 +v -108.6998243895774 165.25540687556511 -10.0 +v -50.728618685192785 41.71045417583674 -10.0 +v -122.77090688990447 105.52114657783105 -10.0 +v -57.24451439464515 22.516937108008147 -10.0 +v -183.646957085236 55.649757206200555 -10.0 +v -90.89825784110239 149.38593653933265 -10.0 +v -38.23285761547356 144.2299086965887 -10.0 +v -103.17670934898433 118.64055054368569 -10.0 +v -78.60116614794693 139.61846861315385 -10.0 +v -44.17088320560375 22.214632534220133 -10.0 +v -185.224251261044 66.6119032219068 -10.0 +v -89.93708101268132 80.44389654064581 -10.0 +v -88.67945621608992 198.11492678415127 -10.0 +v -114.67259568601912 155.63100399560747 -10.0 +v -62.71039794180494 6.783561101371762 -10.0 +v -128.1718242752539 141.24505127464408 -10.0 +v -176.46387971984902 65.91361074063495 -10.0 +v -9.295022756077598 140.28467594984272 -10.0 +v -154.80576656378688 86.96004552720281 -10.0 +v -151.56068129218465 91.17278572956354 -10.0 +v -95.37364860863566 129.0445938596803 -10.0 +v -79.87515919057925 55.386436107996126 -10.0 +v -126.38126598161969 152.6040450303485 -10.0 +v -130.25125394537474 132.23814600352435 -10.0 +v -142.74283416397503 101.08935229015907 -10.0 +v -137.88380127505246 107.10790202536317 -10.0 +v -119.6710540772821 165.57142954285834 -10.0 +v -97.6913703339818 103.93468193119973 -10.0 +v -84.0603436942042 68.1302260473334 -10.0 +v -118.99642103444621 147.1408627054416 -10.0 +v -147.22465168096423 95.79953524865813 -10.0 +v -15.377805279731225 132.73599141350533 -10.0 +v -8.178490788127922 152.50345642799454 -10.0 +v -66.13341888644547 14.17678182480144 -10.0 +v -118.91793994505413 130.31282400540107 -10.0 +v -126.00422388247239 127.31435667281222 -10.0 +v -111.84350422253367 139.20774846846476 -10.0 +v -102.73925499460077 111.87946956642377 -10.0 +v -25.78504776466719 149.61370018636947 -10.0 +v -49.00684341305548 142.62164852292943 -10.0 +v -170.1920386370679 74.91233538657211 -10.0 +v -83.22459718541577 18.907332042128427 -10.0 +v -102.83231069486008 101.15047760601426 -10.0 +v -83.77798471229748 131.13915527305468 -10.0 +v -120.27513162406541 159.62573633168427 -10.0 +v -103.56908226143673 146.92671864600814 -10.0 +v -18.863991888843884 154.57611488571482 -10.0 +v -132.80987861826344 120.35726111880774 -10.0 +v -108.49287394020055 109.30385741640775 -10.0 +v -84.81588491280799 24.51348984319275 -10.0 +v -55.81355621549013 15.73767189688498 -10.0 +v -26.7585691735779 135.1321523346713 -10.0 +v -56.36710707452994 8.510197592189758 -10.0 +v -28.482181152571982 160.72053429435744 -10.0 +v -188.59886732229197 64.44122709096534 -10.0 +v -35.14605780294754 151.94058641811327 -10.0 +v -55.298618931071 141.31242602796476 -10.0 +v -161.56189185740607 79.29332031483796 -10.0 +v -148.96204677132283 138.0668963082169 -10.0 +v -91.19931014912805 193.0082170034069 -10.0 +v -114.87835533587725 166.9112959015805 -10.0 +v -108.98470067308128 158.22285647533954 -10.0 +v -84.02525788602065 33.091169269171324 -10.0 +v -147.41225974396417 119.80135805038064 -10.0 +v -16.621265073661583 143.94777552506966 -10.0 +v -71.95835263535592 36.06334363664765 -10.0 +v -67.96407680668207 140.17918659291422 -10.0 +v -94.33266397453244 97.08812655783045 -10.0 +v -99.39221131056253 165.59851466634262 -10.0 +v -63.09088819804611 47.58556628315628 -10.0 +v -101.6646503585405 125.57241167590148 -10.0 +v -121.51116541707808 118.64640043974792 -10.0 +v -89.88038281261694 139.28053138299745 -10.0 +v -9.040773219884631 158.892712064265 -10.0 +v -91.91003719590783 188.14076711231542 -10.0 +v -74.14800920058578 21.23760440934918 -10.0 +v -110.01475949884141 119.37457438091921 -10.0 +v -106.446228584111 134.67923571423322 -10.0 +v -108.84871602374449 146.12666165169193 -10.0 +v -129.62284374164608 114.96946825201876 -10.0 +v -93.38156823838149 111.80437333571398 -10.0 +v -89.72368727901542 133.31838988346584 -10.0 +v -43.996148393030694 145.3986806148298 -10.0 +v -76.2811373801007 27.352713349381915 -10.0 +v -97.78137880733482 109.0085816766365 -10.0 +v -41.23557227625154 29.380921118044053 -10.0 +v -114.59394361840621 150.17527311624409 -10.0 +v -165.2795875994173 59.99195817074071 -10.0 +v -78.1622595364689 46.12832000877525 -10.0 +v -87.04434282596489 212.05165588195266 -10.0 +v -171.08466996844345 63.69568543258864 -10.0 +v -85.16665229882163 142.13291317199653 -10.0 +v -157.85622484948323 82.06134319474958 -10.0 +v -50.13766507824386 24.82782925274673 -10.0 +v -14.691436252436716 150.37054284571667 -10.0 +v -50.70595416894695 30.895639426479697 -10.0 +v -123.43804911924559 149.10869755713824 -10.0 +v -91.11017637606575 90.48539870409614 -10.0 +v -93.85690228060476 182.0541723432715 -10.0 +v -69.03251566312554 20.631270677946297 -10.0 +v -145.2140546766078 115.00148940980999 -10.0 +v -112.8482902689793 113.30373091174762 -10.0 +v -168.65351487645964 54.00308469127986 -10.0 +v -60.647595400739235 141.1871229676769 -10.0 +v -123.48291525400015 138.69753943861318 -10.0 +v -93.34268393946915 116.690120003289 -10.0 +v -5.765276913217555 146.35002566264848 -10.0 +v -99.22146010593194 94.3599450985287 -10.0 +v -23.571259330208818 163.1727702469831 -10.0 +v -185.32357043705238 70.07729284202841 -10.0 +v -182.37499757054152 72.63234005636255 -10.0 +v -174.9548547207055 60.28666718068122 -10.0 +v -11.596689244637826 134.69252834758157 -10.0 +v -57.98056153379969 38.67009437093907 -10.0 +v -100.02861794443483 135.70412994233672 -10.0 +v -189.3461090083697 61.3540636257212 -10.0 +v -188.0250449680746 57.67340490878471 -10.0 +v -107.26184612814806 128.95409911412204 -10.0 +v -94.20973569807228 143.19423406745048 -10.0 +v -130.7065607218849 150.2745281224257 -10.0 +v -166.203594585317 70.2542126651304 -10.0 +v -67.23760910282147 4.764658638841699 -10.0 +v -45.59804557577396 40.565741975161146 -10.0 +v -81.05958689501233 135.0208250793613 -10.0 +v -151.24040377732902 128.84315250369076 -10.0 +v -161.23523515938143 74.00653630768495 -10.0 +v -118.36970471146549 141.54978914362792 -10.0 +v -76.85238297985545 59.99831447206051 -10.0 +v -84.96354615726295 125.69986238922839 -10.0 +v -140.950893498254 131.89828077301965 -10.0 +v -86.47913530998382 146.8463292825033 -10.0 +v -79.65361018697368 32.164916791472955 -10.0 +v -118.45837264148139 112.68596015219606 -10.0 +v -78.92819673773052 218.6198585691766 -10.0 +v -137.65592359013507 136.59052450646803 -10.0 +v -86.07192219907705 28.65863232537254 -10.0 +v -95.78500244067857 176.36351895660462 -10.0 +v -128.05516512007566 136.55663883070335 -10.0 +v -166.0473687501964 78.79842142161944 -10.0 +v -181.57187743361453 64.7954694387035 -10.0 +v -125.11185176776982 157.19827042727886 -10.0 +v -81.99341035080363 14.336458622261908 -10.0 +v -21.481932430910486 139.0677094448596 -10.0 +v -98.66624937952757 160.06687670784856 -10.0 +v -144.03307024832472 122.69276120197681 -10.0 +v -95.11096110226923 100.89302327462225 -10.0 +v -23.56998558660736 144.81649880786347 -10.0 +v -23.606659379884576 153.04350269442605 -10.0 +v -81.61761551160266 208.90917197923758 -10.0 +v -71.45030333794237 29.408002676976903 -10.0 +v -79.60076711175371 11.445756564459282 -10.0 +v -52.02264592266354 7.073052969855479 -10.0 +v -80.80747674200319 41.23981060588351 -10.0 +v -32.98221695495612 157.64294772451106 -10.0 +v -59.11305344463253 29.471876752306617 -10.0 +v -141.00163728049768 112.5875080109367 -10.0 +v -86.02947721911154 217.35567758002233 -10.0 +v -25.399256736306747 131.5116473257407 -10.0 +v -101.97891294178771 96.80511744051623 -10.0 +v -60.25846782504612 17.012106254241132 -10.0 +v -73.30072772916478 138.43053437553104 -10.0 +v -12.281796946736858 161.387784600841 -10.0 +v -42.36092783617979 140.96960487852178 -10.0 +v -72.86989652928646 7.050578302506484 -10.0 +v -138.35446803029726 127.97266195385718 -10.0 +v -70.09265515964667 40.75441747867028 -10.0 +v -128.38886154571622 102.87608594284286 -10.0 +v -71.67914179853301 55.29061261460011 -10.0 +v -42.21557164161129 17.451307479555226 -10.0 +v -80.51360318574571 50.10824259419291 -10.0 +v -71.59641361361157 12.208916381791504 -10.0 +v -67.55097331137466 25.57138811755966 -10.0 +f 90 75 367 +f 127 95 204 +f 33 225 316 +f 138 222 292 +f 186 118 219 +f 221 177 251 +f 33 34 225 +f 127 204 350 +f 373 295 377 +f 184 162 224 +f 75 90 299 +f 5 6 333 +f 26 27 352 +f 96 176 230 +f 201 142 296 +f 229 132 265 +f 189 147 385 +f 240 32 316 +f 140 178 246 +f 151 221 251 +f 130 106 218 +f 181 81 364 +f 245 28 283 +f 318 166 333 +f 249 104 323 +f 255 102 261 +f 147 189 326 +f 40 41 259 +f 118 186 382 +f 36 195 232 +f 93 94 371 +f 36 37 195 +f 54 55 388 +f 217 158 237 +f 263 60 304 +f 3 4 205 +f 180 373 377 +f 180 158 217 +f 149 195 300 +f 172 151 238 +f 133 194 234 +f 11 12 261 +f 59 60 263 +f 53 54 217 +f 78 243 290 +f 198 215 401 +f 27 28 245 +f 222 164 292 +f 208 40 259 +f 100 101 331 +f 231 164 299 +f 53 217 237 +f 90 231 299 +f 31 32 240 +f 206 133 213 +f 62 63 223 +f 178 140 327 +f 144 186 219 +f 12 255 261 +f 151 172 336 +f 141 198 401 +f 287 69 334 +f 81 181 379 +f 218 106 341 +f 196 17 207 +f 206 380 402 +f 139 303 349 +f 170 201 296 +f 111 220 242 +f 153 248 295 +f 179 245 264 +f 156 192 229 +f 170 226 319 +f 147 213 385 +f 15 188 233 +f 216 139 349 +f 224 162 278 +f 29 118 382 +f 55 122 199 +f 150 204 230 +f 191 251 345 +f 133 206 402 +f 78 79 243 +f 234 144 324 +f 158 180 377 +f 149 206 213 +f 174 238 301 +f 147 225 232 +f 134 203 266 +f 101 102 255 +f 95 96 230 +f 86 124 212 +f 43 44 328 +f 17 196 338 +f 189 234 324 +f 251 139 345 +f 178 204 246 +f 112 20 208 +f 57 58 248 +f 69 70 334 +f 204 178 350 +f 210 16 273 +f 142 201 362 +f 268 155 315 +f 218 169 247 +f 188 15 210 +f 56 57 343 +f 204 95 230 +f 156 229 265 +f 193 158 269 +f 163 193 378 +f 118 30 219 +f 226 149 300 +f 192 156 302 +f 245 154 264 +f 104 105 369 +f 176 96 289 +f 81 82 364 +f 195 149 344 +f 148 218 247 +f 73 211 236 +f 226 182 319 +f 248 171 295 +f 73 74 211 +f 83 84 364 +f 18 111 242 +f 155 210 273 +f 193 163 284 +f 98 99 355 +f 238 151 301 +f 25 117 394 +f 133 234 385 +f 198 141 306 +f 161 198 306 +f 186 144 281 +f 201 22 293 +f 144 219 240 +f 137 238 307 +f 79 80 212 +f 158 193 286 +f 132 229 348 +f 238 174 307 +f 225 165 316 +f 194 133 402 +f 143 202 233 +f 215 25 394 +f 270 69 287 +f 66 67 286 +f 97 98 289 +f 46 47 221 +f 223 63 339 +f 3 205 235 +f 165 240 316 +f 14 15 233 +f 161 197 280 +f 232 225 353 +f 197 161 314 +f 146 211 222 +f 216 159 345 +f 41 220 259 +f 130 218 271 +f 88 89 329 +f 203 156 266 +f 159 308 345 +f 167 200 335 +f 79 212 243 +f 227 145 228 +f 265 167 266 +f 147 232 344 +f 139 251 312 +f 132 200 265 +f 123 73 236 +f 183 267 309 +f 196 44 298 +f 197 314 362 +f 107 131 340 +f 160 223 277 +f 111 19 220 +f 251 177 312 +f 136 205 342 +f 208 20 252 +f 295 135 377 +f 66 286 384 +f 85 86 320 +f 202 162 256 +f 216 146 276 +f 131 108 285 +f 318 214 321 +f 131 241 340 +f 205 136 235 +f 7 8 214 +f 199 122 262 +f 222 138 276 +f 200 167 265 +f 204 150 246 +f 105 130 271 +f 267 159 309 +f 198 161 272 +f 211 146 236 +f 71 72 239 +f 92 93 257 +f 234 189 385 +f 203 134 278 +f 364 84 387 +f 68 69 270 +f 153 262 343 +f 13 202 256 +f 74 75 299 +f 186 281 283 +f 136 175 235 +f 35 36 232 +f 99 128 227 +f 110 17 338 +f 229 174 348 +f 156 265 266 +f 150 209 254 +f 140 335 357 +f 212 124 243 +f 335 200 357 +f 98 228 289 +f 159 216 276 +f 185 236 349 +f 223 163 277 +f 314 142 362 +f 51 270 287 +f 358 252 398 +f 206 149 296 +f 200 132 267 +f 236 146 349 +f 202 143 310 +f 281 154 283 +f 209 134 254 +f 241 175 370 +f 12 13 255 +f 141 264 330 +f 172 268 315 +f 137 307 332 +f 351 8 356 +f 380 187 402 +f 286 193 384 +f 78 290 305 +f 232 195 344 +f 182 226 398 +f 153 199 262 +f 112 208 259 +f 176 228 360 +f 205 166 342 +f 9 10 323 +f 190 351 356 +f 126 92 257 +f 20 113 252 +f 220 42 242 +f 207 18 242 +f 248 58 337 +f 94 253 371 +f 307 192 332 +f 251 191 301 +f 124 87 243 +f 26 352 394 +f 252 182 398 +f 160 263 304 +f 220 19 259 +f 244 157 275 +f 77 78 305 +f 210 155 279 +f 117 26 394 +f 152 244 275 +f 248 153 343 +f 150 230 365 +f 255 13 256 +f 263 160 325 +f 188 210 279 +f 43 207 242 +f 89 90 367 +f 32 33 316 +f 227 228 355 +f 228 145 360 +f 264 194 330 +f 84 85 387 +f 80 81 379 +f 55 199 388 +f 202 13 397 +f 276 138 309 +f 120 48 274 +f 272 161 280 +f 42 43 242 +f 162 184 386 +f 175 136 370 +f 214 8 351 +f 156 203 302 +f 162 202 310 +f 13 14 397 +f 164 222 374 +f 254 134 266 +f 134 209 395 +f 173 258 273 +f 149 213 344 +f 51 52 270 +f 166 318 321 +f 41 42 220 +f 169 218 341 +f 144 240 324 +f 218 148 271 +f 239 72 322 +f 171 263 325 +f 243 87 290 +f 195 37 300 +f 223 160 392 +f 271 148 351 +f 231 91 291 +f 153 295 373 +f 103 249 250 +f 143 233 363 +f 109 11 250 +f 140 260 327 +f 224 145 375 +f 231 157 292 +f 184 224 375 +f 163 223 339 +f 190 271 351 +f 7 214 318 +f 209 150 365 +f 213 133 385 +f 203 143 302 +f 155 258 315 +f 258 155 273 +f 237 158 286 +f 44 196 328 +f 221 47 359 +f 244 138 292 +f 86 212 320 +f 214 148 321 +f 177 221 359 +f 244 152 317 +f 167 254 266 +f 129 103 250 +f 157 231 291 +f 233 188 363 +f 168 239 322 +f 146 222 276 +f 154 245 283 +f 224 134 395 +f 10 109 249 +f 188 279 332 +f 27 245 352 +f 152 260 317 +f 38 39 398 +f 6 7 318 +f 96 97 289 +f 166 205 333 +f 222 211 374 +f 228 176 289 +f 238 137 268 +f 19 112 259 +f 144 234 281 +f 226 38 398 +f 122 56 262 +f 172 238 268 +f 229 192 307 +f 199 153 373 +f 201 170 383 +f 250 11 261 +f 64 65 284 +f 2 3 235 +f 67 237 286 +f 183 309 317 +f 296 149 396 +f 25 215 381 +f 160 304 392 +f 227 128 294 +f 143 203 310 +f 126 257 291 +f 85 320 387 +f 253 152 371 +f 46 221 336 +f 102 129 261 +f 226 170 396 +f 249 109 250 +f 40 208 358 +f 269 158 377 +f 257 157 291 +f 134 224 278 +f 148 214 351 +f 180 217 282 +f 115 24 272 +f 239 48 391 +f 329 89 367 +f 157 257 275 +f 129 250 261 +f 146 216 349 +f 282 199 373 +f 48 239 354 +f 23 115 280 +f 225 147 326 +f 105 271 369 +f 49 50 297 +f 298 173 338 +f 196 298 338 +f 149 226 396 +f 274 48 354 +f 360 209 365 +f 296 142 380 +f 48 49 391 +f 217 54 282 +f 213 147 344 +f 205 4 333 +f 165 225 326 +f 181 364 387 +f 157 244 292 +f 171 248 337 +f 221 151 336 +f 279 137 332 +f 207 43 328 +f 267 183 357 +f 135 295 325 +f 253 94 350 +f 193 269 378 +f 28 29 382 +f 309 138 317 +f 194 264 390 +f 215 198 381 +f 121 51 287 +f 294 100 331 +f 200 267 357 +f 240 165 324 +f 119 45 376 +f 139 216 345 +f 8 9 356 +f 45 258 376 +f 115 272 280 +f 288 9 323 +f 264 154 390 +f 30 31 399 +f 176 360 365 +f 123 236 361 +f 219 30 399 +f 87 125 290 +f 152 275 371 +f 174 229 307 +f 128 100 294 +f 196 207 328 +f 155 268 279 +f 175 241 285 +f 260 140 357 +f 62 223 392 +f 271 190 369 +f 39 40 358 +f 235 175 347 +f 91 126 291 +f 161 306 314 +f 164 231 292 +f 206 296 380 +f 257 93 275 +f 239 168 354 +f 22 114 293 +f 185 303 322 +f 236 185 361 +f 267 132 308 +f 346 1 347 +f 297 50 334 +f 178 253 350 +f 240 219 399 +f 303 168 322 +f 50 121 334 +f 35 232 353 +f 116 25 381 +f 37 38 300 +f 306 187 314 +f 268 137 279 +f 145 224 395 +f 180 282 373 +f 245 179 352 +f 44 119 298 +f 183 260 357 +f 256 162 386 +f 308 191 345 +f 241 131 285 +f 67 68 313 +f 203 278 310 +f 225 34 353 +f 4 5 333 +f 260 183 317 +f 113 21 400 +f 234 194 390 +f 275 93 371 +f 58 59 337 +f 125 88 305 +f 60 61 304 +f 76 77 329 +f 237 67 313 +f 184 331 386 +f 233 202 397 +f 295 171 325 +f 270 52 393 +f 308 132 348 +f 303 185 349 +f 99 227 355 +f 192 302 363 +f 151 251 301 +f 290 125 305 +f 53 237 393 +f 258 45 315 +f 148 247 321 +f 313 270 393 +f 247 169 370 +f 64 284 339 +f 269 135 378 +f 260 152 327 +f 191 308 348 +f 101 255 256 +f 70 71 297 +f 247 136 342 +f 179 264 401 +f 10 249 323 +f 274 168 312 +f 293 114 366 +f 277 135 325 +f 75 76 367 +f 174 301 348 +f 301 191 348 +f 352 179 394 +f 16 110 389 +f 152 253 327 +f 38 226 300 +f 121 287 334 +f 278 162 310 +f 31 240 399 +f 253 178 327 +f 302 143 363 +f 177 274 312 +f 264 141 401 +f 189 324 326 +f 138 244 317 +f 184 294 331 +f 246 150 368 +f 135 277 378 +f 324 165 326 +f 63 64 339 +f 252 113 400 +f 45 311 315 +f 159 267 308 +f 211 74 374 +f 76 329 367 +f 228 98 355 +f 263 171 337 +f 140 246 335 +f 197 293 366 +f 284 163 339 +f 288 190 356 +f 59 263 337 +f 159 276 309 +f 136 247 370 +f 150 254 368 +f 61 62 392 +f 68 270 313 +f 34 35 353 +f 190 288 369 +f 94 127 350 +f 47 120 359 +f 258 173 376 +f 254 167 368 +f 72 123 361 +f 65 66 384 +f 208 252 358 +f 120 274 359 +f 303 139 312 +f 21 319 400 +f 114 23 366 +f 14 233 397 +f 24 116 372 +f 274 177 359 +f 160 277 325 +f 230 176 365 +f 281 234 390 +f 52 53 393 +f 262 56 343 +f 82 83 364 +f 241 169 340 +f 311 46 336 +f 145 227 375 +f 285 108 346 +f 212 80 379 +f 282 54 388 +f 135 269 377 +f 168 303 312 +f 311 172 315 +f 77 305 329 +f 320 181 387 +f 321 247 342 +f 288 104 369 +f 305 88 329 +f 169 241 370 +f 101 256 386 +f 272 24 372 +f 168 274 354 +f 39 358 398 +f 283 28 382 +f 173 273 389 +f 273 16 389 +f 175 346 347 +f 172 311 336 +f 306 141 330 +f 182 252 400 +f 23 280 366 +f 198 272 372 +f 186 283 382 +f 199 282 388 +f 187 306 330 +f 9 288 356 +f 57 248 343 +f 110 338 389 +f 142 314 380 +f 104 288 323 +f 330 194 402 +f 280 197 366 +f 193 284 384 +f 215 394 401 +f 71 239 391 +f 284 65 384 +f 277 163 378 +f 227 294 375 +f 154 281 390 +f 394 179 401 +f 322 72 361 +f 2 235 347 +f 314 187 380 +f 298 119 376 +f 299 164 374 +f 293 197 362 +f 173 298 376 +f 170 319 383 +f 70 297 334 +f 167 335 368 +f 335 246 368 +f 185 322 361 +f 201 293 362 +f 74 299 374 +f 294 184 375 +f 319 21 383 +f 304 61 392 +f 340 169 341 +f 188 332 363 +f 166 321 342 +f 332 192 363 +f 170 296 396 +f 297 71 391 +f 320 212 379 +f 181 320 379 +f 108 1 346 +f 49 297 391 +f 372 116 381 +f 237 313 393 +f 360 145 395 +f 198 372 381 +f 338 173 389 +f 187 330 402 +f 175 285 346 +f 319 182 400 +f 331 101 386 +f 209 360 395 +f 1 2 347 +f 45 46 311 +f 106 107 341 +f 107 340 341 +f 6 318 333 +f 15 16 210 +f 17 18 207 +f 21 22 383 +f 22 201 383 +f 90 91 231 +f 103 104 249 +f 769 477 492 +f 606 497 529 +f 718 627 435 +f 694 624 540 +f 621 520 588 +f 653 579 623 +f 627 436 435 +f 752 606 529 +f 779 697 775 +f 626 564 586 +f 701 492 477 +f 735 408 407 +f 754 429 428 +f 632 578 498 +f 698 544 603 +f 667 534 631 +f 787 549 591 +f 718 434 642 +f 648 580 542 +f 653 623 553 +f 620 508 532 +f 766 483 583 +f 685 430 647 +f 735 568 720 +f 725 506 651 +f 663 504 657 +f 728 591 549 +f 661 443 442 +f 784 588 520 +f 634 597 438 +f 773 496 495 +f 597 439 438 +f 790 457 456 +f 639 560 619 +f 706 462 665 +f 607 406 405 +f 779 775 582 +f 619 560 582 +f 702 597 551 +f 640 553 574 +f 636 596 535 +f 663 414 413 +f 665 462 461 +f 619 456 455 +f 692 645 480 +f 803 617 600 +f 647 430 429 +f 694 566 624 +f 661 442 610 +f 733 503 502 +f 701 566 633 +f 639 619 455 +f 701 633 492 +f 642 434 433 +f 615 535 608 +f 625 465 464 +f 729 542 580 +f 621 588 546 +f 663 657 414 +f 738 574 553 +f 803 600 543 +f 736 471 689 +f 781 583 483 +f 743 508 620 +f 609 419 598 +f 804 782 608 +f 751 705 541 +f 698 603 572 +f 644 622 513 +f 697 650 555 +f 666 647 581 +f 631 594 558 +f 721 628 572 +f 787 615 549 +f 635 590 417 +f 751 541 618 +f 680 564 626 +f 784 520 431 +f 601 524 457 +f 632 606 552 +f 747 653 593 +f 804 608 535 +f 645 481 480 +f 726 546 636 +f 779 582 560 +f 615 608 551 +f 703 640 576 +f 634 627 549 +f 668 605 536 +f 657 504 503 +f 632 498 497 +f 614 526 488 +f 730 446 445 +f 740 598 419 +f 726 636 591 +f 747 541 653 +f 648 606 580 +f 610 422 514 +f 650 460 459 +f 736 472 471 +f 752 580 606 +f 675 418 612 +f 764 603 544 +f 717 557 670 +f 649 571 620 +f 612 417 590 +f 745 459 458 +f 632 497 606 +f 667 631 558 +f 671 560 595 +f 780 595 565 +f 621 432 520 +f 702 551 628 +f 704 558 594 +f 666 556 647 +f 771 507 506 +f 691 498 578 +f 766 484 483 +f 746 551 597 +f 649 620 550 +f 638 613 475 +f 721 584 628 +f 697 573 650 +f 613 476 475 +f 766 486 485 +f 644 513 420 +f 675 612 557 +f 686 565 595 +f 757 501 500 +f 703 553 640 +f 796 519 427 +f 787 636 535 +f 708 543 600 +f 708 600 563 +f 683 546 588 +f 695 424 603 +f 642 621 546 +f 709 640 539 +f 614 482 481 +f 688 595 560 +f 750 631 534 +f 709 576 640 +f 718 567 627 +f 804 535 596 +f 635 604 545 +f 796 427 617 +f 689 471 672 +f 688 469 468 +f 691 500 499 +f 623 449 448 +f 741 465 625 +f 637 607 405 +f 718 642 567 +f 635 417 416 +f 682 599 563 +f 755 627 634 +f 716 563 599 +f 624 613 548 +f 747 561 618 +f 661 622 443 +f 673 620 532 +f 731 491 490 +f 668 558 605 +f 747 710 561 +f 737 602 569 +f 645 614 481 +f 630 547 629 +f 668 569 667 +f 746 634 549 +f 714 653 541 +f 667 602 534 +f 638 475 525 +f 711 669 585 +f 700 446 598 +f 764 716 599 +f 742 533 509 +f 679 625 562 +f 622 421 513 +f 714 579 653 +f 744 607 538 +f 654 422 610 +f 779 537 697 +f 786 688 468 +f 722 488 487 +f 658 564 604 +f 678 548 618 +f 687 510 533 +f 723 616 720 +f 742 643 533 +f 637 538 607 +f 616 410 409 +f 664 524 601 +f 678 540 624 +f 667 569 602 +f 648 552 606 +f 673 532 507 +f 711 561 669 +f 674 563 600 +f 638 548 613 +f 641 474 473 +f 659 495 494 +f 787 591 636 +f 680 536 605 +f 789 486 766 +f 672 471 470 +f 745 664 555 +f 658 604 415 +f 701 477 476 +f 685 683 588 +f 637 577 538 +f 634 438 437 +f 629 530 501 +f 740 419 512 +f 750 576 631 +f 668 667 558 +f 656 611 552 +f 759 737 542 +f 645 526 614 +f 759 602 737 +f 691 630 500 +f 678 618 561 +f 751 638 587 +f 679 565 625 +f 764 544 716 +f 689 672 453 +f 800 654 760 +f 698 551 608 +f 669 534 602 +f 751 548 638 +f 712 545 604 +f 685 556 683 +f 656 536 611 +f 772 577 643 +f 657 415 414 +f 732 666 543 +f 717 670 574 +f 734 709 539 +f 758 410 753 +f 804 589 782 +f 786 595 688 +f 707 692 480 +f 746 597 634 +f 800 628 584 +f 664 601 555 +f 661 610 514 +f 762 630 578 +f 744 568 607 +f 725 412 411 +f 758 753 592 +f 659 494 528 +f 654 515 422 +f 644 444 622 +f 644 420 609 +f 739 460 650 +f 773 655 496 +f 734 594 709 +f 703 593 653 +f 645 489 526 +f 796 754 428 +f 800 584 654 +f 706 665 562 +f 661 421 622 +f 677 559 646 +f 707 480 479 +f 681 557 612 +f 796 428 519 +f 677 646 554 +f 745 555 650 +f 767 632 552 +f 658 415 657 +f 727 562 665 +f 681 612 590 +f 644 609 445 +f 769 492 491 +f 718 435 434 +f 757 630 629 +f 762 547 630 +f 732 596 666 +f 789 487 486 +f 781 483 482 +f 790 601 457 +f 799 415 604 +f 711 540 678 +f 676 450 522 +f 682 563 674 +f 644 445 444 +f 788 586 564 +f 772 538 577 +f 753 410 616 +f 704 605 558 +f 712 604 564 +f 799 416 415 +f 776 624 566 +f 668 536 656 +f 797 611 536 +f 675 660 575 +f 746 615 551 +f 672 454 453 +f 723 720 568 +f 622 444 443 +f 743 620 571 +f 726 642 546 +f 673 550 620 +f 724 474 641 +f 727 665 573 +f 692 489 645 +f 702 439 597 +f 794 562 625 +f 753 550 673 +f 693 493 633 +f 775 697 555 +f 652 651 505 +f 765 635 545 +f 652 413 511 +f 729 662 542 +f 777 547 626 +f 694 559 633 +f 777 626 586 +f 741 625 565 +f 753 673 592 +f 720 616 409 +f 767 552 611 +f 787 535 615 +f 704 545 605 +f 717 660 557 +f 675 557 660 +f 688 560 639 +f 730 598 446 +f 761 449 623 +f 694 540 646 +f 722 614 488 +f 723 550 616 +f 761 623 579 +f 719 554 646 +f 668 656 569 +f 652 505 531 +f 693 633 559 +f 765 590 635 +f 724 641 570 +f 678 624 548 +f 685 647 556 +f 797 536 626 +f 651 511 412 +f 734 681 590 +f 754 647 429 +f 719 662 554 +f 800 441 440 +f 720 409 408 +f 691 499 498 +f 735 607 568 +f 776 613 624 +f 691 578 630 +f 670 539 640 +f 661 514 421 +f 683 636 546 +f 800 440 628 +f 664 458 524 +f 670 640 574 +f 709 594 631 +f 775 555 601 +f 785 572 603 +f 663 413 652 +f 686 467 466 +f 637 405 404 +f 688 639 469 +f 719 711 585 +f 798 551 698 +f 783 617 427 +f 794 706 562 +f 696 530 629 +f 712 605 545 +f 693 659 528 +f 789 722 487 +f 773 554 655 +f 738 623 448 +f 663 531 504 +f 798 572 628 +f 652 511 651 +f 760 610 442 +f 779 560 671 +f 693 559 659 +f 680 626 536 +f 753 616 550 +f 684 619 582 +f 674 426 517 +f 793 450 641 +f 769 491 731 +f 677 659 559 +f 663 652 531 +f 751 618 548 +f 775 601 684 +f 756 641 450 +f 682 517 425 +f 728 549 627 +f 771 673 507 +f 699 452 451 +f 740 575 700 +f 740 700 598 +f 798 628 551 +f 756 450 676 +f 767 611 762 +f 782 544 698 +f 793 451 450 +f 684 456 619 +f 746 549 615 +f 735 406 607 +f 728 627 567 +f 789 766 583 +f 694 646 559 +f 739 650 573 +f 738 553 623 +f 734 539 681 +f 730 445 609 +f 759 585 669 +f 727 697 537 +f 752 496 655 +f 780 671 595 +f 784 431 430 +f 719 540 711 +f 792 666 596 +f 783 600 617 +f 689 453 523 +f 733 502 696 +f 759 669 602 +f 726 567 642 +f 778 447 521 +f 747 618 541 +f 758 411 410 +f 778 660 447 +f 682 674 517 +f 725 411 690 +f 792 556 666 +f 801 433 432 +f 767 762 578 +f 763 638 525 +f 801 432 621 +f 692 527 489 +f 773 677 554 +f 709 631 576 +f 696 502 530 +f 730 609 598 +f 681 670 557 +f 687 643 577 +f 759 542 662 +f 794 625 464 +f 771 592 673 +f 760 442 441 +f 749 577 637 +f 693 528 493 +f 716 708 563 +f 694 633 566 +f 782 698 608 +f 677 495 659 +f 756 570 641 +f 695 516 424 +f 724 705 587 +f 763 587 638 +f 710 534 669 +f 749 403 748 +f 736 452 699 +f 752 655 580 +f 801 621 642 +f 724 570 705 +f 736 523 452 +f 755 634 437 +f 783 427 518 +f 702 440 439 +f 716 589 708 +f 681 539 670 +f 797 626 547 +f 775 684 582 +f 754 581 647 +f 700 521 446 +f 759 662 585 +f 788 564 658 +f 747 593 710 +f 687 533 643 +f 715 470 469 +f 712 680 605 +f 755 436 627 +f 735 407 406 +f 719 585 662 +f 802 423 515 +f 792 596 636 +f 773 495 677 +f 739 461 460 +f 707 490 527 +f 706 463 462 +f 731 479 478 +f 715 469 639 +f 788 733 586 +f 799 604 635 +f 727 573 697 +f 795 454 672 +f 750 534 710 +f 751 587 705 +f 757 629 501 +f 765 704 594 +f 703 653 553 +f 707 527 692 +f 795 639 455 +f 717 447 660 +f 723 649 550 +f 795 672 715 +f 772 571 649 +f 741 686 466 +f 780 537 671 +f 729 554 662 +f 750 710 593 +f 658 657 503 +f 699 473 472 +f 744 538 649 +f 803 666 581 +f 725 651 412 +f 714 570 676 +f 768 516 695 +f 727 537 679 +f 769 478 477 +f 750 703 576 +f 750 593 703 +f 796 581 754 +f 791 512 418 +f 729 655 554 +f 702 628 440 +f 736 689 523 +f 712 564 680 +f 801 642 433 +f 729 580 655 +f 765 545 704 +f 714 676 579 +f 803 543 666 +f 728 726 591 +f 719 646 540 +f 733 696 586 +f 770 552 648 +f 780 679 537 +f 728 567 726 +f 741 466 465 +f 802 515 654 +f 717 713 447 +f 710 669 561 +f 776 476 613 +f 769 731 478 +f 757 500 630 +f 739 573 665 +f 737 648 542 +f 768 695 599 +f 741 565 686 +f 758 592 690 +f 739 665 461 +f 711 678 561 +f 772 649 538 +f 770 656 552 +f 794 464 463 +f 715 672 470 +f 755 437 436 +f 771 690 592 +f 752 529 496 +f 761 522 449 +f 778 575 660 +f 770 569 656 +f 763 525 474 +f 786 468 467 +f 760 654 610 +f 761 676 522 +f 714 541 705 +f 802 721 423 +f 768 425 516 +f 799 635 416 +f 774 518 426 +f 761 579 676 +f 727 679 562 +f 767 578 632 +f 792 636 683 +f 795 455 454 +f 745 458 664 +f 766 485 484 +f 742 571 643 +f 738 448 713 +f 777 629 547 +f 748 510 687 +f 781 482 614 +f 790 456 684 +f 779 671 537 +f 714 705 570 +f 717 574 713 +f 731 707 479 +f 789 583 722 +f 744 649 723 +f 771 506 690 +f 731 490 707 +f 772 643 571 +f 788 658 503 +f 774 426 674 +f 756 676 570 +f 800 760 441 +f 784 430 685 +f 791 675 575 +f 791 418 675 +f 749 748 577 +f 738 713 574 +f 732 543 708 +f 802 654 584 +f 768 682 425 +f 774 674 600 +f 784 685 588 +f 790 684 601 +f 732 708 589 +f 758 690 411 +f 745 650 459 +f 791 740 512 +f 782 716 544 +f 725 690 506 +f 804 596 732 +f 768 599 682 +f 786 686 595 +f 803 796 617 +f 793 641 473 +f 786 467 686 +f 780 565 679 +f 777 696 629 +f 792 683 556 +f 803 581 796 +f 763 474 724 +f 749 637 404 +f 782 589 716 +f 778 521 700 +f 776 566 701 +f 764 599 695 +f 778 700 575 +f 785 721 572 +f 736 699 472 +f 770 737 569 +f 770 648 737 +f 763 724 587 +f 764 695 603 +f 776 701 476 +f 777 586 696 +f 785 423 721 +f 794 463 706 +f 743 571 742 +f 765 734 590 +f 744 723 568 +f 765 594 734 +f 798 698 572 +f 793 473 699 +f 781 614 722 +f 781 722 583 +f 748 403 510 +f 793 699 451 +f 783 518 774 +f 795 715 639 +f 797 547 762 +f 783 774 600 +f 791 575 740 +f 804 732 589 +f 748 687 577 +f 802 584 721 +f 788 503 733 +f 797 762 611 +f 749 404 403 +f 713 448 447 +f 743 509 508 +f 743 742 509 +f 735 720 408 +f 612 418 417 +f 609 420 419 +f 785 424 423 +f 785 603 424 +f 633 493 492 +f 651 506 505 +f 478 76 75 +f 75 477 478 +f 479 77 76 +f 76 478 479 +f 480 78 77 +f 77 479 480 +f 481 79 78 +f 78 480 481 +f 482 80 79 +f 79 481 482 +f 483 81 80 +f 80 482 483 +f 484 82 81 +f 81 483 484 +f 485 83 82 +f 82 484 485 +f 486 84 83 +f 83 485 486 +f 487 85 84 +f 84 486 487 +f 488 86 85 +f 85 487 488 +f 526 124 86 +f 86 488 526 +f 489 87 124 +f 124 526 489 +f 527 125 87 +f 87 489 527 +f 490 88 125 +f 125 527 490 +f 491 89 88 +f 88 490 491 +f 492 90 89 +f 89 491 492 +f 493 91 90 +f 90 492 493 +f 528 126 91 +f 91 493 528 +f 494 92 126 +f 126 528 494 +f 495 93 92 +f 92 494 495 +f 496 94 93 +f 93 495 496 +f 529 127 94 +f 94 496 529 +f 497 95 127 +f 127 529 497 +f 498 96 95 +f 95 497 498 +f 499 97 96 +f 96 498 499 +f 500 98 97 +f 97 499 500 +f 501 99 98 +f 98 500 501 +f 530 128 99 +f 99 501 530 +f 502 100 128 +f 128 530 502 +f 503 101 100 +f 100 502 503 +f 504 102 101 +f 101 503 504 +f 531 129 102 +f 102 504 531 +f 505 103 129 +f 129 531 505 +f 506 104 103 +f 103 505 506 +f 507 105 104 +f 104 506 507 +f 532 130 105 +f 105 507 532 +f 508 106 130 +f 130 532 508 +f 509 107 106 +f 106 508 509 +f 533 131 107 +f 107 509 533 +f 510 108 131 +f 131 533 510 +f 403 1 108 +f 108 510 403 +f 404 2 1 +f 1 403 404 +f 405 3 2 +f 2 404 405 +f 406 4 3 +f 3 405 406 +f 407 5 4 +f 4 406 407 +f 408 6 5 +f 5 407 408 +f 409 7 6 +f 6 408 409 +f 410 8 7 +f 7 409 410 +f 411 9 8 +f 8 410 411 +f 412 10 9 +f 9 411 412 +f 511 109 10 +f 10 412 511 +f 413 11 109 +f 109 511 413 +f 414 12 11 +f 11 413 414 +f 415 13 12 +f 12 414 415 +f 416 14 13 +f 13 415 416 +f 417 15 14 +f 14 416 417 +f 418 16 15 +f 15 417 418 +f 512 110 16 +f 16 418 512 +f 419 17 110 +f 110 512 419 +f 420 18 17 +f 17 419 420 +f 513 111 18 +f 18 420 513 +f 421 19 111 +f 111 513 421 +f 514 112 19 +f 19 421 514 +f 422 20 112 +f 112 514 422 +f 515 113 20 +f 20 422 515 +f 423 21 113 +f 113 515 423 +f 424 22 21 +f 21 423 424 +f 516 114 22 +f 22 424 516 +f 425 23 114 +f 114 516 425 +f 517 115 23 +f 23 425 517 +f 426 24 115 +f 115 517 426 +f 518 116 24 +f 24 426 518 +f 427 25 116 +f 116 518 427 +f 519 117 25 +f 25 427 519 +f 428 26 117 +f 117 519 428 +f 429 27 26 +f 26 428 429 +f 430 28 27 +f 27 429 430 +f 431 29 28 +f 28 430 431 +f 520 118 29 +f 29 431 520 +f 432 30 118 +f 118 520 432 +f 433 31 30 +f 30 432 433 +f 434 32 31 +f 31 433 434 +f 435 33 32 +f 32 434 435 +f 436 34 33 +f 33 435 436 +f 437 35 34 +f 34 436 437 +f 438 36 35 +f 35 437 438 +f 439 37 36 +f 36 438 439 +f 440 38 37 +f 37 439 440 +f 441 39 38 +f 38 440 441 +f 442 40 39 +f 39 441 442 +f 443 41 40 +f 40 442 443 +f 444 42 41 +f 41 443 444 +f 445 43 42 +f 42 444 445 +f 446 44 43 +f 43 445 446 +f 521 119 44 +f 44 446 521 +f 447 45 119 +f 119 521 447 +f 448 46 45 +f 45 447 448 +f 449 47 46 +f 46 448 449 +f 522 120 47 +f 47 449 522 +f 450 48 120 +f 120 522 450 +f 451 49 48 +f 48 450 451 +f 452 50 49 +f 49 451 452 +f 523 121 50 +f 50 452 523 +f 453 51 121 +f 121 523 453 +f 454 52 51 +f 51 453 454 +f 455 53 52 +f 52 454 455 +f 456 54 53 +f 53 455 456 +f 457 55 54 +f 54 456 457 +f 524 122 55 +f 55 457 524 +f 458 56 122 +f 122 524 458 +f 459 57 56 +f 56 458 459 +f 460 58 57 +f 57 459 460 +f 461 59 58 +f 58 460 461 +f 462 60 59 +f 59 461 462 +f 463 61 60 +f 60 462 463 +f 464 62 61 +f 61 463 464 +f 465 63 62 +f 62 464 465 +f 466 64 63 +f 63 465 466 +f 467 65 64 +f 64 466 467 +f 468 66 65 +f 65 467 468 +f 469 67 66 +f 66 468 469 +f 470 68 67 +f 67 469 470 +f 471 69 68 +f 68 470 471 +f 472 70 69 +f 69 471 472 +f 473 71 70 +f 70 472 473 +f 474 72 71 +f 71 473 474 +f 525 123 72 +f 72 474 525 +f 475 73 123 +f 123 525 475 +f 476 74 73 +f 73 475 476 +f 477 75 74 +f 74 476 477 diff --git a/share/mesh/SOFA_volume.vtk b/share/mesh/SOFA_volume.vtk new file mode 100644 index 00000000000..a8154f93049 --- /dev/null +++ b/share/mesh/SOFA_volume.vtk @@ -0,0 +1,27110 @@ +# vtk DataFile Version 2.0 +SOFA Exported Mesh file +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 959 float +-62.9340105 0.238680527 0.0726657012 +-60.8621492 0.343320431 6.53189141 +-64.1565509 0.377105165 -6.28200574 +-61.9997025 0.619668927 -10 +-68.2981047 0.846041041 -8.99210949 +-69.8279696 1.01926313 -3.61391911 +-70.4142073 1.20678962 3.38779665 +-58.1236573 1.21335628 -3.60133154 +-57.8310204 1.30632884 -8.39389041 +-72.2277481 2.13666189 -8.00040902 +-53.6074808 2.64817356 2.72361783 +-53.1820512 2.78333518 -4.21780712 +-75.61466 3.87326212 8.72558373 +-67.778393 3.9123025 10 +-50.9757007 3.98429226 -10 +-49.2646865 4.02790625 -5.43068725 +-54.6665053 4.02831804 -10 +-76.1498914 4.1476959 -8.37174522 +-70.9945718 4.41700682 -10 +-76.8207192 4.49165513 -3.42225543 +-51.6954964 5.10071125 10 +-78.183835 5.19057716 2.3567598 +-65.8742461 5.26722757 -10 +-60.4341048 5.74126208 -10 +-46.5440538 6.20531313 -8.06185262 +-46.5409692 6.20848002 -1.84011218 +-80.34929 6.65793985 7.98010566 +-80.903891 7.35025945 -8.96111781 +-49.5011473 7.46247027 -10 +-45.293714 7.48901183 3.61845162 +-74.9589502 8.07404677 -10 +-55.5190286 8.33902969 -10 +-60.8403856 8.60539167 10 +-82.0418856 8.77084098 -3.18644186 +-45.0227049 9.55502208 -10 +-82.9743959 9.93491243 3.95290225 +-61.2504459 10.2672477 -0.278628941 +-42.3969448 10.4630665 -5.76765758 +-77.3970565 11.694885 10 +-84.6447581 12.0200592 9.41056195 +-69.4569699 12.3219599 -10 +-61.5271028 12.643136 -10 +-77.6737262 12.6685156 -10 +-70.2852753 12.8745076 10 +-40.1108257 12.9899044 -9.4454898 +-85.9892785 13.698451 -5.44048445 +-86.341303 14.1378903 0.721743989 +-52.8313015 14.1978674 -10 +-39.7362619 14.2643802 -0.198302551 +-84.6147828 14.2677401 -10 +-53.1740532 14.3921817 10 +-41.1040316 14.4410184 10 +-86.7838503 14.690331 6.66838572 +-43.7763445 15.5377622 -10 +-73.3097012 15.8105291 0.131556283 +-84.8521212 16.1025483 10 +-87.5300635 17.4692424 -8.71911382 +-79.3248663 17.5215179 10 +-38.6910127 17.8209026 -6.93990588 +-78.5888549 18.6962211 -10 +-87.9674966 19.2661124 8.84658698 +-47.2483416 20.0283768 -10 +-88.2794806 20.5476675 -4.19508717 +-65.4742267 20.69585 -10 +-62.7370243 21.4216675 10 +-88.6414794 22.0346714 2.94430915 +-84.3107888 22.4448899 -10 +-56.6362104 22.6469482 -10 +-37.1941065 22.9142148 -1.32443532 +-50.528741 24.3625936 10 +-83.1988424 24.3643531 10 +-89.2285388 24.4461704 9.12889899 +-73.0729908 24.5978683 -10 +-36.5991256 24.9386728 8.9243724 +-39.8604999 25.0496921 -10 +-74.0953922 25.0528469 10 +-89.5424657 25.7357067 -9.00195313 +-49.6757555 28.0852139 -10 +-89.3010136 28.8071406 -3.35000149 +-81.7654656 29.4854301 -10 +-89.0489577 30.0852178 5.47595139 +-36.8300891 30.2115891 -6.33138301 +-36.891107 30.7000205 1.93306844 +-44.9376755 30.9865912 10 +-62.88132 31.8097941 -10 +-43.9753883 31.9597873 -10 +-82.8427257 32.4732641 10 +-37.121061 32.5407385 8.68640426 +-46.7367021 32.8055134 -0.748682708 +-66.3555559 33.0538588 10 +-54.9769072 34.5171697 10 +-40.4208855 34.939324 -10 +-53.3616238 35.670692 -10 +-38.6403912 36.225099 -2.23876322 +-87.8209528 36.3119509 -1.0827908 +-73.5492282 36.3508886 -10 +-38.9003181 36.6697252 -7.83778792 +-40.3403639 37.0368639 10 +-75.8634462 37.9871186 10 +-45.8551501 38.074289 -10 +-84.9537316 38.2857066 -10 +-40.4482036 39.3175092 3.57843379 +-40.8330782 39.7501424 -10 +-86.1868189 40.0024614 7.93025611 +-47.5488815 40.1108083 10 +-55.0515043 40.1749969 0.0700446927 +-41.774517 41.5862763 -5.85248083 +-60.9343217 41.6466603 10 +-41.9730251 41.9258406 8.68085547 +-65.262679 41.9503113 -10 +-50.4459353 41.9740966 -10 +-44.3983028 42.9907075 -10 +-56.798216 43.1460685 -10 +-43.3180982 44.2266976 -0.561040314 +-83.9459522 44.4041183 2.83667253 +-68.6228853 44.6301953 -0.348412299 +-51.8754402 44.7738608 10 +-79.6797708 45.5632755 10 +-70.1974496 45.6298417 10 +-77.3833272 45.9537616 -10 +-44.7428644 45.9615522 -6.84398364 +-173.258062 46.1933102 10 +-84.1326518 46.2852227 -3.11918453 +-175.930298 46.3210367 4.41961605 +-175.997426 46.3326479 -3.11769523 +-176.094134 46.3493756 8.71363536 +-172.474491 46.3618964 6.7767965 +-45.3206517 46.4222364 7.64549644 +-171.209881 46.852343 0.980656741 +-179.207166 46.8878412 -8.65075711 +-174.121667 46.9822641 -10 +-48.2617486 47.0164286 -10 +-179.951333 47.0165608 3.09769912 +-170.314515 47.1995876 -4.73529869 +-183.289481 47.593965 -1.13233898 +-171.460098 47.7222174 10 +-183.547666 47.7337092 -7.06964608 +-83.7829831 47.7771445 -10 +-179.551808 48.0560962 10 +-70.8339521 48.1177558 -10 +-61.6497518 48.1580616 -10 +-167.834557 48.1613751 -8.53877077 +-167.777993 48.183312 5.02296587 +-168.982856 48.6855081 10 +-48.248165 48.7564159 2.30193864 +-48.3759814 48.8583271 -3.37981938 +-63.2318933 49.152167 10 +-55.6051983 49.2006518 -10 +-55.8531133 49.2689286 10 +-185.438566 49.4035523 6.63439302 +-175.464045 49.4285925 10 +-164.950402 50.0679896 -3.86003686 +-50.5567996 50.350737 7.79831141 +-84.6793053 50.4148455 10 +-164.598413 50.5112721 8.05494163 +-51.20639 50.5924949 -7.64733077 +-66.1292081 50.7308781 -10 +-171.203116 50.9418101 -10 +-187.370476 51.1096113 -3.44231215 +-163.795337 51.5226379 1.68672975 +-165.638188 51.8495522 -10 +-182.54069 51.898468 -10 +-55.2163948 52.0848975 2.12426221 +-55.3040591 52.1175235 -4.26918387 +-181.899626 52.3985949 10 +-62.4294843 52.6019924 -10 +-85.8102466 52.6709576 -3.83451627 +-85.8398483 52.7836362 4.15221977 +-85.8425447 52.7938999 -9.87865718 +-76.2088247 52.9809496 10 +-58.4510213 53.0804295 -9.38732716 +-188.633848 53.2080959 -10 +-59.5579747 53.2245546 7.64431274 +-60.8875099 53.3976598 -6.31612275 +-62.6521084 53.6274102 3.99494958 +-62.7693012 53.6426687 -2.11809852 +-170.672683 53.821916 10 +-175.842231 53.8748308 10 +-161.871353 53.9456372 -8.86961219 +-65.5459102 54.0041826 -7.95521373 +-176.38002 54.1109668 -10 +-187.741618 54.1906249 10 +-189.889888 54.3262872 3.51036383 +-68.5578723 54.4940363 10 +-69.1786698 54.7417663 -10 +-80.7991039 55.0163548 -10 +-160.829972 55.2571169 7.27751451 +-190.249658 55.2671743 -2.26088109 +-83.1000136 55.8241526 10 +-75.0727404 55.8727849 -10 +-160.268766 55.9638795 -4.2800623 +-165.568732 56.1203949 10 +-67.9940658 56.2547172 2.81409289 +-190.630364 56.2628149 -7.36804949 +-68.4947659 56.8567514 -4.3304966 +-169.706854 57.2038771 -10 +-87.0501244 57.3779949 -7.45994265 +-173.039676 57.600155 0.0860111392 +-186.410411 58.3151934 -10 +-159.747081 58.5527838 0.552937842 +-162.161473 58.5900663 -10 +-87.5572111 58.768182 5.00883297 +-181.458616 58.7821555 10 +-87.6685001 59.0732827 9.47467287 +-190.636631 59.3296593 -10 +-180.831134 59.4499253 -10 +-70.6962069 59.5037306 -8.35379553 +-87.850576 59.5724467 -0.838445627 +-190.530587 59.7974716 10 +-192.12241 60.1648876 -2.24539238 +-192.234131 60.4591061 3.71861502 +-192.228215 60.6183285 -7.78961498 +-174.178451 60.8962827 10 +-161.091396 61.5284369 10 +-72.3577424 61.6654881 -0.195204336 +-72.406262 61.7398516 7.39561754 +-83.0154175 61.7532523 10 +-77.7334279 61.7735209 10 +-85.0163928 62.0523543 -10 +-183.345818 62.1609099 0.502213891 +-189.143613 62.3121969 -10 +-185.594693 62.3822509 10 +-192.162513 62.3867772 7.72852621 +-78.6322668 62.3950001 -10 +-189.980643 63.1699068 10 +-158.946056 63.2464209 4.27071153 +-192.038927 63.3060697 -9.80814067 +-158.929644 63.3425874 -7.43629237 +-191.960614 63.5203302 -5.34152523 +-166.417445 63.5918833 -10 +-73.6480078 63.6430111 -7.29344007 +-89.4996933 64.09353 6.57648883 +-87.4619885 64.114228 10 +-167.688465 64.4627621 10 +-174.590502 64.489496 -10 +-89.7472712 64.772269 -6.17165997 +-185.368838 64.8305994 -10 +-190.60302 64.8368303 -10 +-191.262037 65.4316056 4.39177894 +-191.232929 65.5112456 -0.880878704 +-191.127159 65.8006267 9.81403883 +-180.343833 66.8253422 10 +-190.705332 66.9547282 -5.28319486 +-77.6460214 67.2369608 -10 +-186.759586 67.3997033 10 +-90.7217223 67.4437435 2.23017346 +-159.529596 67.4611685 -2.08019009 +-190.431703 67.7033648 -9.68498076 +-76.3941068 68.0077025 -4.70970434 +-90.5774436 68.2130867 10 +-159.682933 68.4043891 7.5281324 +-76.6819705 68.5431055 1.68118947 +-87.5158102 68.5774254 -10 +-83.84074 68.8167917 10 +-189.83858 69.3261229 7.30925702 +-82.3205234 69.5851567 -10 +-180.941403 69.651569 -10 +-162.612066 70.4744179 -10 +-77.755403 70.5396026 8.42839651 +-174.77609 70.5728225 10 +-189.341799 70.6852963 2.74141306 +-186.996956 70.7003299 -10 +-77.9682946 70.9355635 -9.79859329 +-188.952878 71.7493663 -6.27861092 +-188.351594 71.7810967 10 +-166.95933 72.1618705 10 +-92.7863327 72.2972469 -7.81158295 +-92.8660757 72.476491 -1.42246762 +-158.6862 73.1709705 10 +-93.1785186 73.1787911 7.38928803 +-187.458923 73.3867004 -1.72586736 +-183.086818 73.625144 10 +-88.9067797 73.7446087 10 +-79.5152314 73.81274 -6.56749811 +-169.778001 73.9408147 -10 +-157.182655 74.125296 -1.20121753 +-89.5929723 75.2906181 -10 +-184.653992 75.3133742 4.2476868 +-83.2235018 75.6101043 -10 +-184.115978 75.68293 -8.68904136 +-80.7528792 76.1146639 -2.16768393 +-176.5286 76.3058485 -10 +-83.3560122 76.5491127 10 +-81.0404504 76.6495229 4.85688713 +-172.781503 76.7359802 10 +-155.676534 76.7402668 -8.42209103 +-178.300731 76.8491032 10 +-95.2249535 77.7787097 3.74641693 +-154.970964 77.965299 3.77544845 +-180.482677 78.1285264 -1.94190739 +-180.295612 78.1644639 6.08064959 +-164.932508 78.3556036 10 +-177.710655 78.661067 -7.62327676 +-93.4110473 78.8988318 10 +-162.91814 78.915711 -10 +-174.213277 79.3329578 4.40186518 +-154.178436 79.3413098 -8.87172785 +-94.8465056 79.6778535 -10 +-172.321279 79.6964346 -1.82791272 +-172.305846 79.6993994 -9.30744024 +-96.2104405 79.9938596 -3.45598606 +-159.066535 80.0771446 10 +-83.7058635 80.4182923 -10 +-88.75081 80.6925687 -10 +-153.367451 80.7493669 8.64958331 +-169.510253 80.754337 8.6059412 +-89.1198819 81.3440575 10 +-152.992619 81.4001607 -3.0202489 +-168.669067 81.4183984 -9.09693894 +-97.2721881 82.036151 8.30634128 +-83.7545019 82.1350618 0.789326288 +-83.8133659 82.2719653 -6.02062789 +-151.997016 82.7106091 -8.71926877 +-84.4299544 83.1391814 10 +-158.223672 83.2193022 3.32142203 +-166.315138 83.276674 9.53169431 +-166.003143 83.5229742 -5.41213223 +-165.907306 83.5986308 0.461085711 +-165.702108 83.7606214 5.19169272 +-158.36056 84.0511033 -10 +-98.4041894 84.2044885 -8.59003889 +-98.420324 84.2353941 2.77847717 +-162.578487 84.7249323 10 +-91.708671 84.9915926 -10 +-150.149563 85.019654 2.78728835 +-93.941783 85.1125666 10 +-86.4309955 85.680775 -10 +-158.480659 85.8023615 10 +-148.709729 86.8192347 8.45042827 +-87.0012508 86.8773608 10 +-99.9273201 87.1220302 8.3440159 +-85.9809702 87.3132952 3.89310711 +-100.139287 87.5280506 -5.59824681 +-154.286869 87.6120548 10 +-161.388963 87.655756 -6.80879764 +-147.979127 87.7323794 -3.98390177 +-161.033349 88.0112408 7.28675072 +-99.0891928 88.0878524 -10 +-94.6830479 88.1149461 -10 +-86.3826952 88.2476117 -4.38267543 +-100.798675 88.6368696 -1.23931708 +-160.300891 88.7434327 1.28348563 +-151.853494 89.0538805 -10 +-91.8218817 89.4159008 10 +-102.054422 90.6255065 -9.20681583 +-145.511653 90.8163593 3.00011477 +-156.256196 90.9941704 -10 +-157.987898 91.0555848 8.40733764 +-97.5781761 91.2306691 10 +-150.115263 91.4193833 10 +-102.808363 91.8194697 8.79635477 +-102.823435 91.8433376 3.56482026 +-144.233838 91.9210928 -8.1940019 +-89.0643696 91.9318406 -10 +-87.9874513 91.9798912 8.43020983 +-98.1890216 92.0784045 -10 +-143.957265 92.160156 8.36361286 +-154.434603 92.7308926 10 +-151.467507 93.0846805 -10 +-155.99508 93.168033 -2.21164085 +-155.937124 93.2350684 4.98797646 +-142.648806 93.2911593 -2.11265166 +-103.900819 93.5495146 -6.26444935 +-149.078574 93.6331401 -3.17124192 +-147.131803 93.6646408 -10 +-88.8797466 94.0551568 2.95242962 +-88.9437544 94.2040237 -2.7996719 +-93.8523468 94.2487441 -10 +-154.761989 94.5943139 -7.60508197 +-94.6785992 95.5227982 10 +-139.86077 95.7010747 4.88446038 +-148.893689 95.7017406 10 +-100.080845 95.7072565 -10 +-153.374315 95.7327257 10 +-144.689219 95.7520883 10 +-105.472753 96.0388733 -1.28538803 +-104.666002 96.3723501 -10 +-139.448091 96.8396483 10 +-102.370504 96.8775578 10 +-138.338862 97.0165784 -5.3020549 +-108.429594 97.0427161 4.72758798 +-110.034744 97.0839403 -6.16669814 +-90.0110017 97.1200866 9.01678724 +-114.977479 97.210882 -0.987650274 +-115.506286 97.224463 6.03459738 +-152.466744 97.2491597 2.37823891 +-97.6159752 97.3206478 -1.22465467 +-152.282296 97.4625058 -8.55096118 +-119.779724 97.5046069 -5.06087286 +-121.135513 97.5998004 -9.1945078 +-121.24987 97.6526219 10 +-152.090189 97.6847099 8.72063502 +-90.1832776 97.6938518 -7.91968273 +-123.519977 97.7672198 1.03321648 +-148.8445 97.8437115 -10 +-125.220763 97.8866364 -9.49755182 +-126.423187 98.0900399 -5.42991373 +-151.723515 98.1088323 -4.01401041 +-115.37014 98.2400156 -10 +-140.190493 98.4133342 -10 +-136.623418 98.4993693 1.16700984 +-95.9622163 98.843818 -10 +-109.567343 98.9477022 10 +-130.57735 99.1741389 3.9642615 +-131.871175 99.5117842 -3.82141244 +-110.41073 99.575666 -10 +-128.655726 99.7972247 10 +-148.648384 99.8323199 10 +-128.332912 99.9400722 -10 +-144.478589 100.358262 -10 +-91.0485198 100.575542 2.64678833 +-91.0717647 100.65296 9.16523976 +-101.095383 100.656671 -10 +-133.765218 101.084179 -10 +-142.550681 101.110899 10 +-149.484411 101.123288 5.55725002 +-149.290413 101.49141 -8.14082912 +-136.805512 101.75806 10 +-98.0949774 101.782918 10 +-93.5658092 101.838835 -10 +-116.871115 102.165702 10 +-91.5889839 102.375559 -4.2949372 +-124.53914 102.663537 -10 +-148.606243 102.789662 -3.29717502 +-106.914747 102.93616 -10 +-148.481171 103.026993 1.43010477 +-146.971621 103.24877 10 +-92.1319595 104.18394 8.63789346 +-139.7352 104.339136 -1.31004424 +-119.194091 104.852079 -10 +-106.944619 104.974429 10 +-147.297649 105.272795 -8.59135557 +-142.742171 105.674301 -10 +-137.140101 106.052381 -10 +-130.163565 106.846323 -10 +-91.9835783 106.873035 4.08227484 +-92.6412639 107.485133 -10 +-101.08789 107.516248 -10 +-91.458961 107.571228 -0.20991377 +-127.627033 107.59368 10 +-146.060028 107.621253 1.58055245 +-103.568204 107.639137 0.0097468279 +-122.348694 107.903004 -0.259715515 +-145.75765 108.195033 7.62570885 +-90.9378514 108.264753 8.5591931 +-111.778613 108.569932 -10 +-145.811058 108.942276 -5.0864221 +-138.743416 109.003904 10 +-100.807068 109.676125 10 +-90.5262966 109.695998 -10 +-89.6368165 109.996252 -4.88981477 +-145.49453 110.903897 -10 +-115.882988 111.229706 10 +-88.1362786 111.993261 8.25564758 +-140.746456 112.373417 -10 +-87.7202177 112.54698 -9.03386027 +-148.299119 112.706246 0.642448042 +-95.7790241 112.815974 -10 +-87.4457245 112.912293 1.87613242 +-125.29943 113.372674 -10 +-135.155598 113.991629 0.179605273 +-149.309948 114.235441 -7.45601643 +-145.83074 115.190626 10 +-134.208399 115.221367 -10 +-94.5814104 115.985178 10 +-87.6174703 116.015239 10 +-85.1443689 117.024162 -5.22674161 +-117.962264 117.175813 -10 +-127.216619 117.453118 10 +-151.271296 117.8818 2.45997872 +-136.458737 118.299249 10 +-97.0199516 118.537811 -10 +-84.341668 118.572118 2.97736605 +-104.987944 118.682795 10 +-151.616417 118.738246 -9.0351437 +-107.655208 118.938113 -10 +-151.717216 118.988387 -3.67432615 +-84.032241 119.168828 8.42779445 +-151.924865 119.503683 7.12264525 +-143.017204 119.88631 -10 +-87.5355909 121.288586 -10 +-87.6462705 122.076774 10 +-95.2202144 122.141231 0.226104572 +-118.169849 122.757925 10 +-142.894729 123.285042 10 +-81.3500895 124.201328 7.26736842 +-81.347595 124.205933 -3.06224083 +-150.802257 124.46164 -10 +-154.368784 125.568458 -2.98255984 +-154.37644 125.587843 6.67168137 +-92.871082 125.900382 10 +-132.040075 126.319191 -10 +-149.562644 126.484199 10 +-22.0352279 127.497713 -4.86213429 +-98.9535859 127.541196 -10 +-21.1016634 127.627874 6.69300343 +-120.288828 127.732419 -10 +-24.1920593 127.84338 1.15581761 +-24.7250693 128.023999 7.79952109 +-17.998543 128.060526 0.451348723 +-19.0736549 128.175943 10 +-16.4673272 128.274015 5.7365399 +-142.9183 128.474655 -10 +-14.4250813 128.558755 -7.24796046 +-14.1643087 128.595113 -3.24061207 +-154.39891 128.644038 -10 +-12.5227979 128.82398 7.58243708 +-27.5679782 128.987365 4.86451278 +-27.722941 129.039877 -8.99554285 +-108.756505 129.120079 10 +-11.7059677 129.180977 1.93876611 +-82.1843945 129.195221 -10 +-15.4610985 129.326284 10 +-29.0053301 129.474435 -4.74654398 +-22.2161005 129.553874 10 +-22.3108394 129.907358 -10 +-129.790236 129.973208 10 +-27.4670083 129.999112 10 +-31.0414745 130.164416 7.25846895 +-31.1548811 130.202845 0.822271168 +-16.8406077 130.42743 -10 +-155.014875 130.516292 2.89838288 +-77.9212759 130.531393 3.09146543 +-80.573377 130.569865 10 +-9.47268676 130.787784 -8.42883666 +-12.6412806 130.920085 -10 +-9.16286626 131.010695 -4.16578547 +-8.83973401 131.243183 6.54376865 +-30.9509521 131.591355 -10 +-18.9668541 131.797154 10 +-153.93677 131.836779 10 +-10.6899707 131.916594 10 +-33.3812931 132.128518 -7.45128326 +-139.79821 132.284186 10 +-7.15719759 132.453739 1.41452447 +-7.09429135 132.498999 -8.84525441 +-33.9622681 132.6576 6.84417862 +-75.5773549 132.698065 -2.42655986 +-34.0908338 132.774682 -3.18270051 +-110.008768 132.776636 -10 +-6.68273067 132.795109 9.14453432 +-155.333223 132.973806 -9.10490695 +-74.3297429 133.042777 7.70204483 +-74.1336495 133.096957 -9.30362235 +-98.8438482 133.155877 10 +-24.7425407 133.553528 10 +-155.435169 133.815087 -2.44126798 +-14.8614013 133.877176 10 +-5.25668386 133.887853 -7.04387561 +-90.5194956 133.930759 -10 +-5.09332382 134.19632 -2.67605156 +-70.0256238 134.231994 8.06032168 +-35.4695652 134.370978 -10 +-147.387402 134.463705 -10 +-31.1209629 134.842964 10 +-88.513897 134.90692 10 +-67.5725428 134.909774 3.07500037 +-4.70174839 134.935717 5.2394171 +-68.2934845 135.041635 -10 +-145.933811 135.05708 0.696086993 +-14.6967762 135.073212 -10 +-147.607234 135.197688 10 +-36.9608329 135.388332 2.87337545 +-65.4769958 135.488768 -3.18240702 +-37.0922201 135.507983 -6.8123733 +-137.541049 135.645673 -10 +-79.163286 135.93636 10 +-133.677161 135.966717 -0.067837189 +-155.012239 136.025109 -7.98339504 +-37.8879535 136.232642 9.03718969 +-23.5195229 136.265238 -10 +-5.52710415 136.282244 10 +-154.946272 136.369819 6.07829658 +-66.1911841 136.382907 10 +-30.6501739 136.547428 -10 +-118.557634 136.621413 10 +-9.59653855 136.664613 -10 +-4.93046745 136.69752 -10 +-57.9741434 136.893741 2.47178605 +-63.8274325 136.907022 -10 +-57.7760515 136.922791 -6.84151146 +-39.737772 137.085774 -2.05741995 +-72.6814061 137.202278 10 +-10.7129831 137.231016 10 +-19.9038166 137.240547 10 +-45.5024998 137.366981 5.26336559 +-45.7786968 137.380454 -2.43914166 +-46.3270164 137.407201 -8.00478212 +-53.0599943 137.614407 9.0227439 +-39.4536165 137.639732 -10 +-51.8901047 137.678572 -1.90482427 +-60.5494818 137.704744 10 +-151.355925 137.838723 -10 +-25.3839385 137.844873 0.978207179 +-3.13142442 137.900902 -6.3535054 +-2.9821194 138.182829 0.379890479 +-124.026465 138.77426 -10 +-2.53859084 139.020327 6.05305334 +-35.712671 139.037868 -10 +-51.701559 139.138961 -10 +-79.554654 139.230595 -10 +-151.617367 139.45111 10 +-154.323658 139.623292 -5.12961656 +-143.23663 139.64598 10 +-134.851585 139.924569 10 +-70.6280465 140.031049 -10 +-100.192851 140.204707 -10 +-154.173732 140.406733 4.97703928 +-154.153821 140.510774 0.152675703 +-14.2452503 140.764695 -0.132167146 +-44.0340612 140.786444 10 +-75.3151907 140.802123 10 +-4.82504671 140.820247 10 +-15.24581 140.94692 -10 +-34.6049305 141.164971 10 +-33.5829217 141.204041 -1.9577231 +-44.316822 141.24156 -10 +-66.9095978 141.26168 10 +-25.3675397 141.268597 10 +-1.34076279 141.282142 -5.60887182 +-135.375113 141.449616 -10 +-153.965234 141.496239 -9.42696901 +-83.6040375 141.583609 10 +-63.2489841 141.58928 -10 +-1.02670929 141.875157 7.43363199 +-144.700574 141.90079 -10 +-57.2053729 142.044423 -10 +-149.453826 142.089375 -10 +-15.4696092 142.401807 10 +-106.940597 142.511882 10 +-153.287207 143.05381 8.17913057 +-56.345194 143.129203 10 +-6.58455093 143.132838 -10 +-152.117986 143.258447 -5.60896711 +-141.049357 143.33444 -10 +-29.274736 143.372986 -10 +-150.832561 143.483422 3.39215768 +-150.588893 143.526069 8.31827172 +-86.1552282 143.907925 -10 +-147.961601 143.985898 -3.44539822 +-126.742107 144.038609 10 +-51.0890542 144.326875 -10 +-0.535577106 144.382916 -0.138648926 +-145.06842 144.547598 2.75498066 +-144.696848 144.722947 8.28506493 +-74.0711153 144.761068 9.43668247 +-37.021929 144.792316 -10 +-74.4278904 144.820798 2.99813729 +-94.3475463 144.842399 10 +-70.9284677 144.877009 -7.04671732 +-49.2072964 145.052856 10 +-69.1403535 145.053501 0.0117436779 +-68.0693574 145.159211 7.14454907 +-111.050073 145.181271 -10 +-2.54173493 145.228909 10 +-20.7933311 145.343266 -10 +-9.13491379 145.432009 10 +-130.716552 145.565038 -10 +-0.495948489 145.606933 -7.78968512 +-79.343555 145.643765 6.67302029 +-63.0324242 145.760255 -2.99206592 +-142.433582 145.79101 -7.3212809 +-62.6267285 145.827367 -8.8650119 +-80.5168272 145.840191 -3.80676917 +-62.0853265 145.916928 6.63162457 +-142.122321 145.937898 -2.05905854 +-0.484874036 145.948991 4.95675188 +-137.871701 146.390177 -10 +-43.6732426 146.476683 -10 +-57.041336 146.751325 0.364719697 +-56.7334473 146.802258 -7.18617527 +-29.2866788 147.000775 10 +-55.1657324 147.061595 6.77870949 +-38.4562258 147.080683 10 +-139.462806 147.192955 8.99824512 +-139.149593 147.340764 3.89083394 +-51.0123417 147.986116 -8.19042852 +-95.9571955 148.147026 -10 +-50.1651605 148.175195 -2.24988711 +-49.0316479 148.428179 4.17505949 +-137.807456 148.467947 -6.1075532 +-83.4993299 148.860809 8.92182715 +-45.7573845 149.421963 -6.86331613 +-0.370149726 149.492502 8.23380381 +-8.72403209 149.630169 -10 +-44.4682876 149.82692 8.48076712 +-29.5290009 149.842948 0.0960971675 +-17.9454578 149.900353 10 +-136.342703 149.95534 -9.45325094 +-43.4548346 150.145286 0.470762937 +-120.055623 150.262836 -10 +-135.953978 150.350073 -0.2341669 +-3.87794275 150.399314 10 +-42.182089 150.545106 -8.17600684 +-0.33243567 150.657383 0.365499101 +-33.4063003 151.069519 -10 +-41.4969812 151.332473 6.76452431 +-132.65248 151.340776 -10 +-0.448904643 151.34287 -7.94812642 +-118.739411 151.346425 10 +-127.50513 151.374962 -10 +-134.776734 151.545513 7.87756619 +-10.0112341 151.836368 10 +-85.4585811 152.35503 2.00739386 +-25.4953958 152.376494 -10 +-33.1097335 152.531407 10 +-1.02921475 152.816395 6.01095038 +-133.330786 153.01381 -4.98441269 +-40.6390655 153.102625 -3.93949846 +-16.272758 153.222791 -10 +-88.009258 153.592586 -10 +-107.588158 153.622834 10 +-24.5336388 153.644465 10 +-40.053381 154.311078 8.67737777 +-98.0607964 154.397997 10 +-39.9994707 154.422312 -9.9375842 +-86.7899845 154.729517 -4.89028204 +-13.5735329 154.847839 -0.407298383 +-1.85206806 154.905787 -3.55966412 +-131.371417 155.019644 -8.42676126 +-90.0787635 155.098837 10 +-103.824457 155.163492 -10 +-39.6228992 155.199298 2.58915435 +-1.99747867 155.275014 9.85759238 +-6.37511234 156.07348 10 +-95.5950274 156.194645 -10 +-36.3996517 156.19885 10 +-130.706837 156.220392 2.5742836 +-2.45154963 156.427993 1.90490734 +-111.411725 156.519577 -10 +-3.4888874 156.681354 -10 +-35.9820403 156.970553 -10 +-125.861499 157.844943 -10 +-117.412472 157.926333 0.0977199044 +-38.2839351 157.962006 -7.02532682 +-30.6524584 157.985726 -10 +-8.9244636 158.131424 -10 +-11.7867833 158.150786 10 +-128.720699 158.346921 10 +-89.4268796 158.463213 5.20898514 +-3.25783896 158.475325 9.35578441 +-3.29341252 158.565653 5.59870978 +-129.16137 159.012705 -4.65758945 +-37.4833426 159.024839 5.75650066 +-37.4360418 159.083496 -1.62392617 +-31.0352516 159.239546 10 +-3.59088086 159.320986 -5.12836025 +-14.1721671 159.613682 -10 +-36.6880095 160.011119 9.60522072 +-90.7633835 160.054541 -8.41108876 +-4.14047266 160.112411 -9.51642157 +-119.865486 160.168752 -10 +-17.1762065 160.243738 10 +-5.2978594 160.877974 10 +-91.4988866 160.930278 -2.10312605 +-21.8656913 160.983411 -10 +-5.19518113 161.203049 -0.575958483 +-114.738714 161.301738 10 +-35.5729655 161.393867 -9.31450341 +-25.1401857 161.414488 10 +-94.5751368 161.942833 10 +-6.08084664 162.118885 -6.69993572 +-105.307548 162.196543 -0.442459223 +-121.565387 162.272567 10 +-26.3784788 162.39209 -10 +-96.1864379 162.458906 -10 +-6.45335098 162.504079 4.55941159 +-113.490401 162.672053 -10 +-101.404099 162.741122 10 +-34.4787883 162.750739 -5.89632477 +-126.873669 163.146067 6.84765461 +-34.068008 163.260141 2.74346971 +-33.8125019 163.53427 9.50461805 +-102.385099 163.603478 -10 +-126.641018 163.695999 -9.01407557 +-93.0731194 163.765164 3.12380628 +-107.471196 163.766883 10 +-16.7871819 163.993707 -10 +-7.94518838 164.046737 -8.4819356 +-126.480573 164.077234 -2.45293426 +-31.4107118 164.185187 -10 +-11.1114585 164.41208 -10 +-8.95074142 164.647824 8.55608378 +-9.16564865 164.764319 -3.23488736 +-119.253702 165.304104 -4.08279839 +-30.4199196 165.500645 -3.75477446 +-121.842361 165.540028 -10 +-29.8436214 165.834673 8.07306658 +-125.675365 165.990492 2.57454094 +-19.7754907 166.231022 10 +-13.2560359 166.253779 -10 +-107.851704 166.394414 -10 +-117.415251 166.67449 -10 +-13.0519349 166.870955 0.941427202 +-28.0093784 166.897819 1.55539458 +-13.3050285 167.008149 8.17985915 +-125.219287 167.074181 -6.9100898 +-92.7652546 167.273112 -8.08672476 +-14.5651935 167.302795 -5.45225752 +-25.9980289 167.401268 -7.46663994 +-25.9831837 167.403912 9.66245224 +-92.7475137 167.475259 7.36899991 +-96.2531705 167.53256 10 +-112.170959 167.60557 -10 +-23.5738286 167.833077 5.50166526 +-17.6867609 167.837512 4.9090059 +-18.9740346 168.058019 -9.02563661 +-21.4194367 168.216826 -2.21364807 +-96.7808578 168.369058 -10 +-92.6575539 168.500301 -3.02271966 +-123.987686 168.797895 -10 +-124.407361 169.003404 9.15661339 +-104.021746 169.071521 10 +-118.152541 169.18881 10 +-103.56487 169.286785 -10 +-111.178343 169.41152 10 +-115.078844 170.239211 -10 +-123.873992 170.270746 -2.08101067 +-123.64127 170.823718 -6.71843373 +-121.520177 171.172344 -9.33554273 +-121.445298 171.173758 3.90178233 +-119.798211 171.204868 -5.79934762 +-118.521097 171.22899 -9.03990167 +-118.136286 171.236258 -1.62391303 +-114.983726 171.295803 4.79094769 +-114.155496 171.311447 -6.26755196 +-104.389334 171.341412 5.99280162 +-107.693534 171.34511 -6.41022088 +-108.597687 171.346122 3.97471026 +-110.945122 171.348749 -1.42183092 +-111.153709 171.348982 -9.55346029 +-92.3192397 171.807111 2.60870073 +-102.824968 171.88637 -7.6245013 +-98.7090296 172.038436 -10 +-92.2520013 172.054196 -8.15497656 +-98.1418025 172.132733 10 +-102.695677 172.213194 -1.84768905 +-102.003814 173.13366 -10 +-91.7874496 173.761309 8.73027891 +-101.74362 174.619805 8.4677359 +-96.1146458 174.948592 -10 +-91.4303673 175.073498 -3.14491766 +-101.430029 175.412502 3.18316063 +-92.3600546 176.444848 -10 +-95.1473175 176.927041 10 +-100.679027 177.310884 -6.19753617 +-99.6764757 177.59521 10 +-90.639855 177.978436 4.68149162 +-90.4907948 178.526195 -7.84874417 +-93.2260553 179.621295 -10 +-98.1735837 179.720784 -10 +-99.5477718 180.170474 -0.0611601446 +-99.4975968 180.297306 5.27965725 +-89.7784953 180.390454 -1.5485897 +-89.6529815 180.711661 9.37666512 +-96.2645643 181.271559 10 +-98.907244 181.789601 8.81936735 +-89.579655 181.895389 -10 +-89.0047594 182.370549 -5.94963823 +-93.4664009 183.002166 10 +-95.1258598 183.294503 -10 +-98.2112769 183.548868 -3.76082504 +-88.3887174 183.947084 1.96920453 +-88.2978427 184.179645 6.98002011 +-97.7381296 184.74489 -8.21315358 +-91.3953372 184.789873 -10 +-87.9744576 185.007231 -8.86970955 +-97.4667938 185.430773 7.10808627 +-89.9991092 185.51952 10 +-96.8352076 187.635911 2.12277728 +-86.9336647 187.670761 -4.32541424 +-92.5714091 188.134412 -10 +-95.2367312 188.682081 10 +-86.4001438 189.036113 7.16279108 +-96.3238258 189.631797 -3.22122239 +-96.2798595 189.803395 -8.69772734 +-89.8571391 190.013227 10 +-85.7689433 190.651441 1.0923438 +-86.5225448 190.674275 -10 +-95.8619235 191.434569 7.01050963 +-84.5788693 192.997859 8.35457696 +-93.3424803 193.055659 10 +-92.3029057 193.279673 -10 +-90.2004973 193.304824 3.63775972 +-88.5049283 193.531759 10 +-95.0959667 194.424043 8.28088183 +-95.034015 194.665836 2.08150295 +-94.9940782 194.821707 -5.88255308 +-83.3275346 195.370709 -4.96258933 +-91.3179891 196.200787 10 +-94.570931 196.210407 10 +-82.7748059 196.418824 3.59905643 +-83.5695152 197.579731 10 +-87.2205004 197.58077 10 +-88.1473012 197.598058 -10 +-94.3270224 197.805063 6.07960483 +-93.7662182 198.528687 10 +-94.0923137 199.402517 -1.42306659 +-94.0520259 199.67672 -8.71470268 +-80.2530447 200.672718 6.9580859 +-89.6448562 200.78306 10 +-93.8546254 201.02025 7.76410333 +-81.2379054 201.223887 -10 +-79.7560753 201.493765 -0.69925503 +-83.562082 201.761402 10 +-93.0544759 202.955545 10 +-93.5468699 203.114869 3.88355653 +-93.5437483 203.136115 -9.35588739 +-78.3736441 203.777688 9.78886967 +-87.2932756 204.136543 -10 +-93.3112166 204.718752 -3.35645739 +-92.8817421 205.444425 -10 +-84.5205663 206.173167 10 +-76.5839785 206.391404 4.33500719 +-89.2812921 206.599366 10 +-85.4639515 207.331011 -0.990995272 +-75.8393949 207.424698 -2.32608297 +-92.8179116 208.076242 8.09687897 +-92.369416 208.650571 -10 +-92.6980723 208.891881 2.25679628 +-92.6867751 208.968771 -6.19169806 +-74.4940699 209.291669 9.38100886 +-74.3455572 209.497768 -7.32411078 +-84.0236712 209.584276 -10 +-81.3845595 210.244356 10 +-77.4429106 210.343351 -10 +-72.7435342 212.329292 3.25120405 +-92.7197851 212.33408 -1.82541838 +-87.5305655 212.794323 10 +-76.5422193 212.882198 10 +-89.6957521 213.159946 -10 +-72.9366732 213.806424 7.34581118 +-92.7652539 214.441076 6.90113712 +-81.7198852 214.770237 1.45664846 +-92.7812194 215.180907 -6.80547969 +-73.1422126 215.378395 -1.32672659 +-80.0140006 215.956679 -10 +-73.3574228 217.024328 -7.46491831 +-79.1948542 217.038338 10 +-73.3892754 217.267938 9.03469164 +-85.7658291 217.83228 -10 +-91.6752089 218.160853 1.19977451 +-84.2104654 218.237574 10 +-90.7450992 218.586303 -10 +-90.31359 219.732627 9.19178373 +-74.5177195 220.15323 3.62285803 +-89.8815899 220.231304 -4.40210594 +-74.8826293 220.486262 9.00552594 +-77.3039036 221.101689 -10 +-75.8120717 221.334513 -2.71714872 +-81.5491329 222.622964 -10 +-87.5064838 222.97299 2.32226673 +-87.3501649 223.153436 -8.91299766 +-77.8344432 223.18022 8.97336604 +-78.2412357 223.551477 -7.22062931 +-85.3497298 223.744844 -3.57835386 +-84.5052302 223.768231 8.25422157 +-80.5807366 223.876911 -2.88573978 +-80.2993634 223.884703 3.05234436 +CELLS 13072 50401 +2 0 36 +2 0 13 +2 0 1 +2 13 36 +2 1 36 +2 1 13 +2 5 36 +2 0 5 +2 2 5 +2 2 36 +2 0 2 +2 0 6 +2 6 13 +2 1 6 +2 6 36 +2 7 10 +2 7 36 +2 0 7 +2 10 36 +2 0 10 +2 5 6 +2 2 7 +2 1 10 +2 20 32 +2 10 20 +2 1 20 +2 10 32 +2 1 32 +2 13 32 +2 32 36 +2 3 23 +2 2 3 +2 3 8 +2 2 23 +2 8 23 +2 2 8 +2 23 36 +2 22 36 +2 22 23 +2 2 22 +2 5 22 +2 3 22 +2 7 23 +2 7 8 +2 2 4 +2 3 4 +2 4 22 +2 4 5 +2 18 22 +2 4 18 +2 5 18 +2 5 9 +2 4 9 +2 9 18 +2 22 40 +2 5 40 +2 18 40 +2 6 54 +2 36 54 +2 5 54 +2 18 19 +2 19 40 +2 5 19 +2 36 40 +2 19 54 +2 40 54 +2 6 19 +2 9 19 +2 43 54 +2 21 54 +2 6 43 +2 6 21 +2 21 43 +2 36 43 +2 12 43 +2 6 12 +2 12 21 +2 13 43 +2 19 21 +2 12 13 +2 7 31 +2 23 31 +2 8 31 +2 7 11 +2 11 36 +2 11 31 +2 31 36 +2 10 11 +2 11 16 +2 7 16 +2 8 16 +2 8 11 +2 16 31 +2 16 23 +2 9 30 +2 17 30 +2 18 30 +2 9 17 +2 17 18 +2 19 30 +2 17 19 +2 20 50 +2 32 50 +2 10 50 +2 20 29 +2 29 50 +2 10 29 +2 25 36 +2 10 25 +2 11 25 +2 29 36 +2 36 50 +2 25 29 +2 15 31 +2 11 15 +2 15 16 +2 15 25 +2 25 31 +2 11 14 +2 14 15 +2 14 16 +2 21 38 +2 21 26 +2 12 38 +2 12 26 +2 26 38 +2 38 43 +2 32 43 +2 15 24 +2 15 28 +2 14 24 +2 24 28 +2 14 28 +2 28 31 +2 14 31 +2 15 47 +2 28 47 +2 31 47 +2 25 47 +2 25 28 +2 24 25 +2 17 27 +2 27 30 +2 19 27 +2 30 40 +2 30 54 +2 30 42 +2 19 42 +2 42 54 +2 19 33 +2 27 33 +2 30 33 +2 33 42 +2 33 54 +2 21 33 +2 50 51 +2 29 51 +2 20 51 +2 38 54 +2 35 38 +2 35 54 +2 21 35 +2 33 35 +2 26 35 +2 36 41 +2 22 41 +2 23 41 +2 40 41 +2 31 41 +2 28 37 +2 28 34 +2 24 37 +2 34 37 +2 24 34 +2 25 37 +2 25 50 +2 36 47 +2 37 48 +2 25 48 +2 47 48 +2 37 47 +2 29 47 +2 47 50 +2 29 37 +2 29 48 +2 38 39 +2 26 39 +2 35 39 +2 27 42 +2 33 49 +2 27 49 +2 42 49 +2 33 45 +2 27 45 +2 45 49 +2 34 47 +2 48 51 +2 48 50 +2 40 42 +2 41 47 +2 50 64 +2 32 64 +2 36 64 +2 43 64 +2 33 46 +2 46 54 +2 35 46 +2 42 45 +2 45 54 +2 45 46 +2 34 44 +2 34 53 +2 37 44 +2 37 53 +2 44 53 +2 47 53 +2 38 57 +2 39 57 +2 35 57 +2 52 57 +2 35 52 +2 46 52 +2 46 57 +2 54 57 +2 39 52 +2 63 64 +2 54 64 +2 36 63 +2 54 63 +2 63 67 +2 41 63 +2 36 67 +2 41 67 +2 50 67 +2 64 67 +2 47 67 +2 40 63 +2 37 61 +2 47 61 +2 53 61 +2 48 61 +2 37 58 +2 48 58 +2 48 53 +2 53 58 +2 44 58 +2 43 57 +2 55 57 +2 39 55 +2 52 55 +2 54 72 +2 59 72 +2 40 72 +2 54 59 +2 40 59 +2 63 72 +2 42 59 +2 49 59 +2 45 59 +2 54 75 +2 64 75 +2 43 75 +2 57 75 +2 59 62 +2 56 59 +2 56 62 +2 45 62 +2 45 56 +2 49 56 +2 46 59 +2 46 62 +2 57 65 +2 52 65 +2 46 65 +2 54 65 +2 62 65 +2 54 62 +2 50 61 +2 61 67 +2 68 69 +2 51 69 +2 48 69 +2 51 68 +2 48 68 +2 50 69 +2 61 69 +2 48 73 +2 51 73 +2 68 73 +2 58 61 +2 61 68 +2 58 68 +2 59 66 +2 56 66 +2 49 66 +2 67 69 +2 64 69 +2 69 73 +2 57 60 +2 60 65 +2 52 60 +2 55 60 +2 53 74 +2 58 74 +2 61 74 +2 72 75 +2 75 79 +2 72 79 +2 54 79 +2 66 79 +2 54 66 +2 59 79 +2 63 75 +2 62 79 +2 65 79 +2 62 66 +2 54 70 +2 70 75 +2 57 70 +2 65 75 +2 65 70 +2 55 70 +2 60 70 +2 62 76 +2 66 76 +2 56 76 +2 68 74 +2 60 71 +2 70 71 +2 65 71 +2 74 88 +2 68 88 +2 61 88 +2 67 88 +2 69 88 +2 61 77 +2 67 77 +2 77 88 +2 74 77 +2 65 78 +2 78 79 +2 62 78 +2 66 78 +2 76 78 +2 64 72 +2 63 84 +2 64 84 +2 84 89 +2 63 89 +2 64 89 +2 67 84 +2 72 89 +2 72 84 +2 64 90 +2 84 90 +2 67 90 +2 69 90 +2 75 89 +2 89 90 +2 78 80 +2 70 80 +2 65 80 +2 70 78 +2 70 79 +2 71 80 +2 76 79 +2 88 90 +2 84 88 +2 84 92 +2 67 92 +2 88 92 +2 77 92 +2 74 81 +2 81 88 +2 68 81 +2 83 88 +2 82 88 +2 68 83 +2 82 83 +2 68 82 +2 69 83 +2 73 83 +2 81 82 +2 73 82 +2 83 90 +2 78 86 +2 80 86 +2 70 86 +2 79 86 +2 75 86 +2 71 86 +2 75 95 +2 72 95 +2 79 95 +2 89 95 +2 84 95 +2 73 87 +2 83 87 +2 82 87 +2 85 88 +2 77 85 +2 74 85 +2 81 85 +2 89 98 +2 95 98 +2 75 98 +2 86 95 +2 86 98 +2 79 100 +2 78 100 +2 76 100 +2 85 92 +2 86 94 +2 78 94 +2 80 94 +2 94 100 +2 79 94 +2 94 95 +2 95 100 +2 80 103 +2 86 103 +2 94 103 +2 85 91 +2 81 91 +2 91 93 +2 85 93 +2 81 93 +2 88 93 +2 82 93 +2 81 96 +2 91 96 +2 93 96 +2 87 101 +2 83 101 +2 82 101 +2 88 101 +2 93 101 +2 83 104 +2 88 104 +2 101 104 +2 90 104 +2 97 104 +2 83 97 +2 97 101 +2 87 97 +2 88 105 +2 90 105 +2 84 105 +2 84 109 +2 109 115 +2 95 109 +2 84 115 +2 95 115 +2 105 109 +2 109 112 +2 105 112 +2 84 112 +2 105 115 +2 92 105 +2 89 115 +2 89 105 +2 92 112 +2 88 96 +2 85 96 +2 85 99 +2 96 99 +2 91 99 +2 92 99 +2 88 99 +2 94 98 +2 98 103 +2 88 106 +2 88 113 +2 106 113 +2 93 106 +2 93 113 +2 99 106 +2 93 99 +2 88 110 +2 99 110 +2 99 105 +2 105 110 +2 92 110 +2 105 113 +2 104 113 +2 104 105 +2 101 113 +2 99 113 +2 90 107 +2 105 107 +2 89 107 +2 98 115 +2 107 115 +2 107 118 +2 115 118 +2 89 118 +2 98 118 +2 104 116 +2 90 116 +2 105 116 +2 107 116 +2 96 102 +2 99 102 +2 91 102 +2 110 112 +2 96 106 +2 95 114 +2 98 114 +2 94 114 +2 100 122 +2 95 122 +2 94 122 +2 103 114 +2 114 122 +2 115 119 +2 95 119 +2 119 139 +2 115 139 +2 95 139 +2 109 139 +2 114 115 +2 100 119 +2 119 122 +2 115 122 +2 102 106 +2 101 108 +2 104 108 +2 97 108 +2 115 117 +2 98 117 +2 117 118 +2 114 117 +2 103 117 +2 106 110 +2 110 113 +2 110 111 +2 106 111 +2 99 111 +2 102 111 +2 122 137 +2 119 137 +2 100 137 +2 108 127 +2 101 127 +2 113 127 +2 108 113 +2 104 127 +2 104 144 +2 116 144 +2 127 144 +2 116 127 +2 113 144 +2 105 144 +2 116 148 +2 116 162 +2 148 162 +2 105 148 +2 105 162 +2 110 145 +2 113 145 +2 105 145 +2 105 174 +2 107 162 +2 107 174 +2 162 174 +2 109 140 +2 105 140 +2 112 140 +2 115 140 +2 140 175 +2 115 175 +2 105 175 +2 107 148 +2 115 174 +2 115 162 +2 162 175 +2 163 175 +2 162 163 +2 105 163 +2 140 163 +2 144 162 +2 112 163 +2 112 145 +2 145 163 +2 145 162 +2 144 145 +2 106 120 +2 111 120 +2 110 120 +2 113 120 +2 107 146 +2 146 148 +2 146 162 +2 115 146 +2 146 174 +2 118 146 +2 109 156 +2 115 156 +2 139 156 +2 140 156 +2 145 155 +2 110 155 +2 112 155 +2 120 145 +2 131 155 +2 131 145 +2 110 131 +2 120 131 +2 111 131 +2 110 147 +2 131 147 +2 147 155 +2 112 147 +2 155 163 +2 147 163 +2 140 147 +2 117 153 +2 114 153 +2 153 167 +2 117 167 +2 114 167 +2 167 169 +2 122 169 +2 114 169 +2 122 167 +2 117 169 +2 115 169 +2 115 189 +2 139 189 +2 119 189 +2 189 194 +2 115 194 +2 139 194 +2 156 175 +2 118 169 +2 139 179 +2 115 179 +2 179 194 +2 169 192 +2 115 192 +2 122 192 +2 174 192 +2 174 175 +2 175 192 +2 118 192 +2 156 179 +2 175 179 +2 175 194 +2 118 174 +2 192 194 +2 122 189 +2 122 194 +2 152 162 +2 144 152 +2 116 152 +2 148 152 +2 127 152 +2 153 169 +2 118 183 +2 146 183 +2 174 183 +2 183 192 +2 169 183 +2 119 185 +2 185 189 +2 122 185 +2 137 185 +2 126 150 +2 125 126 +2 121 126 +2 125 150 +2 121 150 +2 121 125 +2 135 150 +2 126 135 +2 121 135 +2 166 167 +2 166 169 +2 122 166 +2 166 189 +2 166 185 +2 166 192 +2 166 194 +2 137 166 +2 176 177 +2 123 176 +2 126 176 +2 123 177 +2 126 177 +2 123 126 +2 132 138 +2 123 132 +2 132 150 +2 123 138 +2 138 150 +2 123 150 +2 123 125 +2 125 138 +2 123 197 +2 124 197 +2 128 197 +2 123 124 +2 123 128 +2 124 128 +2 132 177 +2 150 177 +2 176 197 +2 126 197 +2 126 128 +2 177 197 +2 132 197 +2 124 132 +2 125 132 +2 124 180 +2 124 133 +2 124 157 +2 133 180 +2 157 180 +2 133 157 +2 130 133 +2 124 130 +2 130 157 +2 129 136 +2 124 129 +2 129 161 +2 124 136 +2 136 161 +2 124 161 +2 129 180 +2 161 180 +2 129 130 +2 130 180 +2 124 134 +2 134 161 +2 134 180 +2 180 197 +2 134 197 +2 133 197 +2 128 133 +2 134 136 +2 132 134 +2 128 176 +2 150 176 +2 135 142 +2 142 176 +2 126 142 +2 135 176 +2 128 142 +2 135 143 +2 126 143 +2 142 143 +2 128 151 +2 151 197 +2 133 151 +2 159 197 +2 128 159 +2 142 159 +2 142 197 +2 151 159 +2 133 141 +2 141 157 +2 130 141 +2 138 177 +2 132 219 +2 132 149 +2 134 219 +2 149 219 +2 134 149 +2 164 219 +2 132 164 +2 149 164 +2 197 219 +2 164 197 +2 164 177 +2 138 149 +2 138 164 +2 151 157 +2 141 151 +2 157 197 +2 161 197 +2 134 158 +2 136 158 +2 158 161 +2 134 182 +2 182 219 +2 149 182 +2 158 197 +2 158 182 +2 149 158 +2 158 219 +2 143 176 +2 158 171 +2 136 171 +2 161 171 +2 137 168 +2 166 168 +2 168 185 +2 184 189 +2 184 194 +2 139 184 +2 156 184 +2 179 184 +2 140 173 +2 156 173 +2 173 175 +2 163 173 +2 147 173 +2 165 173 +2 140 165 +2 156 165 +2 140 170 +2 170 173 +2 165 170 +2 147 170 +2 141 160 +2 157 160 +2 151 160 +2 142 154 +2 154 176 +2 159 176 +2 154 159 +2 143 154 +2 172 183 +2 146 172 +2 172 174 +2 162 172 +2 148 172 +2 163 170 +2 164 181 +2 149 181 +2 181 182 +2 164 182 +2 151 195 +2 195 197 +2 157 195 +2 160 195 +2 151 190 +2 190 197 +2 190 195 +2 151 178 +2 178 195 +2 178 190 +2 159 190 +2 160 178 +2 153 188 +2 169 188 +2 167 188 +2 159 191 +2 186 191 +2 154 191 +2 159 186 +2 154 186 +2 176 191 +2 173 179 +2 165 179 +2 180 195 +2 161 219 +2 198 205 +2 158 205 +2 205 219 +2 158 198 +2 198 219 +2 171 198 +2 161 198 +2 161 205 +2 193 198 +2 171 193 +2 158 193 +2 187 219 +2 182 187 +2 158 187 +2 187 198 +2 187 193 +2 159 199 +2 197 199 +2 191 199 +2 191 197 +2 186 199 +2 190 199 +2 195 200 +2 178 200 +2 160 200 +2 180 205 +2 197 205 +2 182 202 +2 181 202 +2 164 202 +2 197 202 +2 202 219 +2 177 202 +2 166 207 +2 166 196 +2 185 207 +2 196 207 +2 185 196 +2 207 214 +2 166 214 +2 185 214 +2 168 196 +2 194 214 +2 189 214 +2 167 192 +2 167 214 +2 167 207 +2 192 214 +2 201 214 +2 201 207 +2 167 201 +2 167 217 +2 188 217 +2 201 217 +2 188 201 +2 214 217 +2 169 214 +2 188 214 +2 183 215 +2 169 215 +2 192 215 +2 169 217 +2 214 215 +2 215 217 +2 191 212 +2 197 212 +2 176 212 +2 177 212 +2 202 212 +2 190 200 +2 205 234 +2 180 234 +2 197 234 +2 195 234 +2 202 221 +2 181 221 +2 182 221 +2 182 208 +2 208 221 +2 181 208 +2 182 210 +2 210 219 +2 187 210 +2 208 210 +2 210 221 +2 219 221 +2 184 206 +2 189 206 +2 194 206 +2 185 223 +2 207 223 +2 214 223 +2 185 218 +2 218 223 +2 196 223 +2 196 218 +2 189 223 +2 186 213 +2 199 213 +2 191 213 +2 186 225 +2 199 225 +2 213 225 +2 187 209 +2 198 209 +2 193 209 +2 209 210 +2 209 219 +2 188 216 +2 216 217 +2 201 216 +2 203 216 +2 201 203 +2 188 203 +2 189 230 +2 206 223 +2 206 230 +2 223 230 +2 214 230 +2 206 214 +2 197 229 +2 190 229 +2 195 229 +2 200 229 +2 227 229 +2 200 227 +2 190 227 +2 199 229 +2 199 227 +2 191 233 +2 197 233 +2 199 233 +2 191 225 +2 213 233 +2 225 233 +2 212 233 +2 198 211 +2 198 204 +2 193 211 +2 193 204 +2 204 211 +2 209 211 +2 229 234 +2 207 218 +2 196 235 +2 207 235 +2 218 235 +2 212 259 +2 197 259 +2 233 259 +2 229 246 +2 234 246 +2 197 246 +2 197 225 +2 212 219 +2 197 274 +2 259 274 +2 246 274 +2 246 259 +2 225 246 +2 233 246 +2 219 234 +2 219 259 +2 234 259 +2 197 241 +2 241 259 +2 212 241 +2 234 274 +2 199 246 +2 219 241 +2 198 220 +2 198 228 +2 219 220 +2 219 228 +2 220 228 +2 209 228 +2 211 228 +2 219 236 +2 198 236 +2 220 236 +2 205 236 +2 211 220 +2 204 220 +2 227 246 +2 214 251 +2 217 251 +2 201 251 +2 207 251 +2 207 231 +2 201 231 +2 231 251 +2 201 232 +2 216 231 +2 216 232 +2 231 232 +2 216 251 +2 203 232 +2 203 231 +2 202 241 +2 221 241 +2 220 226 +2 211 226 +2 204 226 +2 219 256 +2 234 256 +2 205 256 +2 236 256 +2 218 248 +2 235 248 +2 207 248 +2 214 248 +2 248 251 +2 223 248 +2 235 251 +2 207 245 +2 231 245 +2 245 251 +2 235 245 +2 221 222 +2 208 222 +2 210 222 +2 221 224 +2 222 224 +2 208 224 +2 210 239 +2 219 239 +2 209 239 +2 228 239 +2 238 239 +2 219 238 +2 210 238 +2 221 238 +2 222 238 +2 226 228 +2 213 250 +2 233 250 +2 225 250 +2 215 251 +2 230 248 +2 217 258 +2 215 258 +2 251 258 +2 217 253 +2 253 258 +2 216 253 +2 216 258 +2 251 253 +2 231 253 +2 232 253 +2 235 255 +2 218 255 +2 248 255 +2 223 255 +2 218 252 +2 235 252 +2 252 255 +2 236 242 +2 228 236 +2 219 242 +2 228 242 +2 219 260 +2 239 260 +2 238 260 +2 219 289 +2 256 289 +2 234 289 +2 219 277 +2 219 270 +2 260 277 +2 260 270 +2 270 277 +2 219 244 +2 221 244 +2 238 244 +2 259 277 +2 241 277 +2 241 260 +2 241 244 +2 244 260 +2 259 289 +2 239 270 +2 263 270 +2 242 263 +2 219 263 +2 242 270 +2 256 263 +2 236 263 +2 239 242 +2 256 270 +2 277 289 +2 270 289 +2 228 237 +2 220 237 +2 226 237 +2 220 242 +2 237 242 +2 236 237 +2 224 238 +2 224 244 +2 224 240 +2 222 240 +2 238 240 +2 243 248 +2 223 243 +2 243 255 +2 230 243 +2 240 244 +2 246 250 +2 229 257 +2 246 257 +2 227 257 +2 229 274 +2 257 274 +2 231 249 +2 249 253 +2 232 249 +2 245 249 +2 245 253 +2 233 265 +2 246 265 +2 250 265 +2 259 265 +2 234 281 +2 256 281 +2 281 289 +2 234 298 +2 259 298 +2 289 298 +2 274 298 +2 274 281 +2 281 298 +2 245 248 +2 245 280 +2 248 280 +2 235 280 +2 255 280 +2 252 280 +2 267 280 +2 252 267 +2 235 267 +2 235 266 +2 252 266 +2 266 267 +2 245 267 +2 237 247 +2 242 247 +2 236 247 +2 236 261 +2 261 263 +2 256 261 +2 242 261 +2 247 261 +2 238 254 +2 254 260 +2 244 254 +2 240 254 +2 244 277 +2 259 271 +2 241 271 +2 271 277 +2 244 271 +2 247 263 +2 255 262 +2 248 262 +2 243 262 +2 254 277 +2 254 271 +2 254 264 +2 244 264 +2 264 271 +2 245 269 +2 245 272 +2 269 272 +2 267 269 +2 267 272 +2 280 283 +2 251 280 +2 245 283 +2 251 283 +2 253 283 +2 272 283 +2 267 283 +2 249 272 +2 253 272 +2 249 269 +2 257 275 +2 274 275 +2 246 275 +2 265 298 +2 246 298 +2 275 298 +2 265 275 +2 250 275 +2 255 273 +2 248 273 +2 273 280 +2 262 273 +2 265 268 +2 268 275 +2 250 268 +2 258 283 +2 255 278 +2 252 278 +2 273 278 +2 252 273 +2 278 280 +2 252 276 +2 266 276 +2 267 276 +2 276 280 +2 276 278 +2 253 282 +2 282 283 +2 272 282 +2 258 282 +2 264 277 +2 260 264 +2 262 278 +2 256 279 +2 270 279 +2 279 289 +2 256 292 +2 279 292 +2 289 292 +2 279 281 +2 281 292 +2 263 279 +2 261 279 +2 275 294 +2 274 294 +2 257 294 +2 257 285 +2 285 294 +2 275 285 +2 286 295 +2 259 286 +2 286 290 +2 259 295 +2 290 295 +2 259 290 +2 259 284 +2 265 284 +2 284 295 +2 265 295 +2 289 295 +2 295 298 +2 284 286 +2 271 290 +2 277 290 +2 289 290 +2 271 286 +2 295 305 +2 284 305 +2 265 305 +2 268 291 +2 265 291 +2 275 291 +2 291 298 +2 291 305 +2 298 305 +2 298 317 +2 265 317 +2 275 317 +2 291 317 +2 284 291 +2 267 300 +2 276 300 +2 266 300 +2 266 297 +2 276 297 +2 297 300 +2 269 283 +2 283 287 +2 267 287 +2 269 287 +2 267 311 +2 267 303 +2 300 311 +2 300 303 +2 303 311 +2 300 310 +2 287 300 +2 267 310 +2 287 310 +2 276 311 +2 276 303 +2 283 310 +2 280 310 +2 280 311 +2 310 311 +2 268 301 +2 288 301 +2 301 304 +2 268 288 +2 268 304 +2 288 304 +2 288 291 +2 275 288 +2 291 301 +2 272 287 +2 269 306 +2 269 293 +2 272 306 +2 272 293 +2 293 306 +2 287 306 +2 287 293 +2 282 306 +2 283 306 +2 306 310 +2 272 310 +2 281 299 +2 274 299 +2 298 299 +2 274 316 +2 298 316 +2 294 316 +2 294 298 +2 308 316 +2 298 308 +2 274 308 +2 299 308 +2 294 308 +2 275 316 +2 314 317 +2 316 317 +2 275 314 +2 314 316 +2 291 314 +2 275 307 +2 307 316 +2 294 307 +2 285 307 +2 307 314 +2 288 314 +2 288 307 +2 278 311 +2 278 303 +2 297 303 +2 302 303 +2 302 311 +2 278 302 +2 292 298 +2 292 299 +2 282 313 +2 306 313 +2 283 313 +2 310 313 +2 307 319 +2 294 319 +2 285 319 +2 296 307 +2 296 319 +2 285 296 +2 306 325 +2 287 325 +2 293 325 +2 306 331 +2 310 331 +2 287 331 +2 287 321 +2 321 325 +2 309 321 +2 287 309 +2 309 325 +2 325 331 +2 321 331 +2 300 331 +2 300 321 +2 293 309 +2 288 324 +2 314 324 +2 307 324 +2 304 314 +2 304 324 +2 301 314 +2 315 322 +2 291 315 +2 315 318 +2 291 322 +2 318 322 +2 291 318 +2 314 318 +2 317 318 +2 301 318 +2 301 322 +2 305 317 +2 305 318 +2 305 315 +2 316 319 +2 295 317 +2 295 318 +2 307 312 +2 296 312 +2 312 319 +2 300 323 +2 320 323 +2 297 323 +2 300 320 +2 297 320 +2 303 323 +2 331 339 +2 300 339 +2 321 339 +2 332 339 +2 300 332 +2 332 338 +2 338 339 +2 300 338 +2 310 339 +2 303 339 +2 323 339 +2 311 339 +2 323 338 +2 321 332 +2 320 332 +2 320 338 +2 304 327 +2 314 327 +2 301 327 +2 322 327 +2 314 322 +2 311 326 +2 302 326 +2 303 326 +2 311 323 +2 323 326 +2 314 333 +2 324 333 +2 304 333 +2 327 333 +2 324 328 +2 304 328 +2 328 333 +2 313 331 +2 329 331 +2 306 329 +2 325 329 +2 313 329 +2 334 341 +2 307 341 +2 314 341 +2 307 334 +2 314 334 +2 312 342 +2 307 342 +2 319 342 +2 342 359 +2 334 342 +2 307 359 +2 334 359 +2 312 335 +2 307 335 +2 335 342 +2 335 359 +2 316 334 +2 319 334 +2 324 341 +2 341 359 +2 324 359 +2 324 335 +2 309 330 +2 325 330 +2 321 330 +2 326 339 +2 322 336 +2 327 336 +2 314 336 +2 333 336 +2 324 360 +2 333 360 +2 314 360 +2 317 334 +2 341 360 +2 317 341 +2 318 341 +2 318 336 +2 333 347 +2 314 347 +2 336 347 +2 347 360 +2 336 341 +2 341 347 +2 334 346 +2 342 346 +2 319 346 +2 332 337 +2 337 338 +2 320 337 +2 343 348 +2 343 365 +2 321 343 +2 348 365 +2 321 348 +2 321 365 +2 340 365 +2 365 366 +2 340 366 +2 321 340 +2 321 366 +2 325 343 +2 330 343 +2 331 365 +2 339 365 +2 339 366 +2 331 343 +2 348 351 +2 330 351 +2 321 351 +2 330 348 +2 339 340 +2 340 348 +2 332 340 +2 340 351 +2 323 353 +2 339 353 +2 326 353 +2 338 353 +2 335 363 +2 324 363 +2 359 363 +2 328 360 +2 345 349 +2 328 349 +2 324 349 +2 328 345 +2 324 345 +2 335 345 +2 345 363 +2 345 360 +2 360 363 +2 359 360 +2 349 360 +2 329 343 +2 325 348 +2 327 347 +2 333 349 +2 345 356 +2 349 356 +2 328 356 +2 343 354 +2 329 354 +2 331 354 +2 350 351 +2 348 350 +2 330 350 +2 354 365 +2 344 355 +2 332 355 +2 355 362 +2 332 344 +2 344 362 +2 332 362 +2 332 366 +2 337 344 +2 337 355 +2 338 366 +2 338 367 +2 332 367 +2 366 367 +2 340 386 +2 332 386 +2 366 386 +2 338 355 +2 362 386 +2 340 362 +2 367 386 +2 355 367 +2 355 386 +2 333 357 +2 357 360 +2 347 357 +2 349 357 +2 346 359 +2 345 361 +2 361 363 +2 335 361 +2 342 364 +2 335 364 +2 358 364 +2 342 358 +2 335 358 +2 342 352 +2 335 352 +2 352 364 +2 352 361 +2 352 363 +2 342 363 +2 358 363 +2 363 364 +2 353 366 +2 353 367 +2 365 386 +2 340 375 +2 351 386 +2 351 375 +2 375 386 +2 351 365 +2 362 375 +2 363 368 +2 342 368 +2 358 368 +2 346 368 +2 359 368 +2 346 358 +2 343 369 +2 365 369 +2 354 369 +2 348 369 +2 355 372 +2 362 372 +2 344 372 +2 362 376 +2 372 376 +2 344 376 +2 361 385 +2 361 425 +2 345 385 +2 385 425 +2 345 425 +2 371 374 +2 345 374 +2 356 374 +2 345 371 +2 356 371 +2 349 371 +2 363 385 +2 361 370 +2 361 415 +2 345 370 +2 345 415 +2 370 415 +2 360 385 +2 371 415 +2 374 415 +2 415 425 +2 385 415 +2 370 374 +2 356 370 +2 349 385 +2 371 385 +2 369 386 +2 348 386 +2 351 369 +2 369 378 +2 351 378 +2 348 378 +2 350 378 +2 385 391 +2 349 391 +2 371 391 +2 371 373 +2 349 373 +2 373 391 +2 357 373 +2 360 373 +2 360 391 +2 378 380 +2 350 380 +2 351 380 +2 378 386 +2 375 378 +2 375 380 +2 352 409 +2 363 409 +2 364 409 +2 352 399 +2 352 379 +2 399 409 +2 379 399 +2 379 409 +2 361 409 +2 364 399 +2 361 379 +2 367 392 +2 366 392 +2 353 392 +2 354 382 +2 365 382 +2 369 382 +2 367 372 +2 372 386 +2 374 377 +2 356 377 +2 370 377 +2 358 387 +2 368 387 +2 363 387 +2 364 387 +2 358 394 +2 364 394 +2 387 394 +2 368 397 +2 359 397 +2 363 397 +2 385 397 +2 359 385 +2 379 423 +2 409 423 +2 361 423 +2 423 428 +2 423 425 +2 361 428 +2 425 428 +2 363 423 +2 361 400 +2 400 428 +2 379 428 +2 379 400 +2 370 425 +2 363 425 +2 370 428 +2 370 400 +2 376 381 +2 375 376 +2 362 381 +2 375 381 +2 375 412 +2 386 412 +2 362 412 +2 372 412 +2 376 412 +2 387 397 +2 409 416 +2 416 423 +2 363 416 +2 363 394 +2 394 397 +2 397 425 +2 394 409 +2 397 423 +2 397 416 +2 394 416 +2 369 410 +2 365 410 +2 382 410 +2 386 410 +2 366 410 +2 386 392 +2 386 421 +2 392 421 +2 366 421 +2 410 421 +2 386 401 +2 367 401 +2 372 401 +2 392 401 +2 386 418 +2 410 418 +2 369 418 +2 411 418 +2 410 411 +2 369 411 +2 382 411 +2 378 418 +2 370 414 +2 377 414 +2 374 414 +2 377 417 +2 370 417 +2 414 417 +2 414 415 +2 400 417 +2 400 414 +2 414 428 +2 414 425 +2 391 415 +2 371 407 +2 374 407 +2 407 415 +2 391 407 +2 401 412 +2 407 414 +2 386 441 +2 380 386 +2 375 441 +2 380 441 +2 412 424 +2 375 424 +2 376 424 +2 381 441 +2 424 441 +2 381 424 +2 381 383 +2 383 441 +2 375 383 +2 412 441 +2 380 383 +2 381 405 +2 376 405 +2 405 424 +2 380 402 +2 402 430 +2 378 402 +2 380 430 +2 378 430 +2 380 418 +2 418 430 +2 428 433 +2 379 433 +2 413 433 +2 413 428 +2 379 413 +2 379 404 +2 404 428 +2 400 404 +2 404 413 +2 409 428 +2 399 428 +2 399 413 +2 399 433 +2 418 441 +2 383 430 +2 430 441 +2 380 420 +2 380 384 +2 420 430 +2 384 420 +2 384 430 +2 402 420 +2 384 402 +2 383 384 +2 381 445 +2 424 445 +2 441 445 +2 383 445 +2 398 405 +2 383 398 +2 381 398 +2 383 405 +2 405 445 +2 383 393 +2 393 442 +2 384 393 +2 383 442 +2 384 442 +2 429 445 +2 383 429 +2 405 429 +2 442 445 +2 429 442 +2 420 442 +2 383 420 +2 383 388 +2 388 398 +2 398 429 +2 388 429 +2 441 442 +2 388 442 +2 388 393 +2 420 441 +2 384 390 +2 390 420 +2 390 393 +2 393 420 +2 435 441 +2 386 435 +2 418 435 +2 435 438 +2 410 435 +2 410 438 +2 386 438 +2 412 421 +2 421 441 +2 401 421 +2 438 441 +2 421 438 +2 387 416 +2 393 396 +2 388 396 +2 396 442 +2 389 398 +2 388 389 +2 389 429 +2 388 422 +2 422 442 +2 396 422 +2 389 422 +2 389 396 +2 422 429 +2 395 422 +2 389 395 +2 395 396 +2 390 439 +2 390 442 +2 420 439 +2 439 442 +2 393 439 +2 406 439 +2 393 406 +2 390 406 +2 392 419 +2 419 421 +2 401 419 +2 403 442 +2 393 403 +2 403 404 +2 404 442 +2 393 404 +2 403 406 +2 403 439 +2 396 404 +2 395 408 +2 396 408 +2 408 422 +2 434 442 +2 422 434 +2 396 434 +2 404 408 +2 404 422 +2 404 434 +2 399 432 +2 428 432 +2 432 433 +2 409 432 +2 400 403 +2 403 428 +2 417 428 +2 403 417 +2 412 419 +2 417 439 +2 406 417 +2 403 460 +2 403 447 +2 428 460 +2 447 460 +2 428 447 +2 404 460 +2 417 447 +2 439 447 +2 442 460 +2 439 460 +2 434 460 +2 428 434 +2 408 434 +2 404 433 +2 433 434 +2 413 434 +2 408 413 +2 414 426 +2 415 426 +2 407 426 +2 423 432 +2 409 431 +2 416 431 +2 423 431 +2 431 432 +2 418 427 +2 410 427 +2 411 427 +2 427 435 +2 437 441 +2 412 437 +2 421 437 +2 424 437 +2 419 437 +2 428 440 +2 440 443 +2 414 440 +2 428 443 +2 414 443 +2 414 447 +2 425 443 +2 425 426 +2 426 443 +2 425 440 +2 443 447 +2 415 443 +2 441 448 +2 435 448 +2 418 448 +2 427 448 +2 430 448 +2 421 436 +2 436 437 +2 419 436 +2 430 452 +2 420 452 +2 441 452 +2 439 452 +2 442 452 +2 437 438 +2 436 438 +2 421 450 +2 436 450 +2 438 450 +2 422 459 +2 442 459 +2 429 459 +2 434 459 +2 423 440 +2 423 446 +2 440 446 +2 428 446 +2 431 446 +2 428 431 +2 437 445 +2 444 448 +2 427 444 +2 435 444 +2 440 447 +2 440 460 +2 446 460 +2 433 446 +2 446 454 +2 428 454 +2 433 454 +2 454 460 +2 432 446 +2 433 460 +2 429 467 +2 442 467 +2 445 467 +2 459 467 +2 452 473 +2 441 473 +2 430 473 +2 448 473 +2 446 451 +2 432 451 +2 431 451 +2 432 454 +2 451 454 +2 434 463 +2 460 463 +2 433 463 +2 454 463 +2 459 460 +2 459 463 +2 444 453 +2 453 464 +2 435 453 +2 444 464 +2 435 464 +2 441 464 +2 448 464 +2 438 464 +2 458 464 +2 438 458 +2 435 458 +2 453 458 +2 436 457 +2 437 457 +2 438 457 +2 436 449 +2 450 457 +2 449 457 +2 449 450 +2 457 475 +2 441 475 +2 437 475 +2 441 457 +2 445 475 +2 441 482 +2 438 482 +2 457 482 +2 450 482 +2 458 482 +2 464 482 +2 450 458 +2 460 468 +2 460 470 +2 439 468 +2 439 470 +2 468 470 +2 442 468 +2 447 470 +2 452 468 +2 446 456 +2 440 456 +2 456 460 +2 443 460 +2 443 456 +2 473 475 +2 452 475 +2 441 471 +2 471 482 +2 457 471 +2 473 482 +2 475 482 +2 441 467 +2 467 475 +2 448 482 +2 471 475 +2 452 467 +2 445 452 +2 459 468 +2 442 483 +2 468 483 +2 467 468 +2 467 483 +2 452 483 +2 460 462 +2 447 462 +2 443 462 +2 456 462 +2 454 461 +2 446 461 +2 451 461 +2 456 461 +2 454 456 +2 462 470 +2 464 473 +2 449 455 +2 455 457 +2 450 455 +2 450 471 +2 455 466 +2 450 466 +2 457 466 +2 458 466 +2 466 482 +2 466 471 +2 461 479 +2 451 479 +2 454 479 +2 475 483 +2 473 483 +2 453 465 +2 458 465 +2 465 472 +2 453 472 +2 458 472 +2 464 465 +2 460 479 +2 456 479 +2 463 479 +2 455 471 +2 455 480 +2 466 480 +2 471 480 +2 456 484 +2 460 484 +2 462 484 +2 469 476 +2 456 476 +2 476 479 +2 456 469 +2 469 479 +2 469 484 +2 462 469 +2 461 476 +2 460 469 +2 466 472 +2 472 482 +2 464 472 +2 468 496 +2 459 496 +2 467 496 +2 468 491 +2 491 496 +2 459 491 +2 460 491 +2 463 491 +2 460 502 +2 479 491 +2 491 502 +2 479 502 +2 491 516 +2 460 516 +2 468 516 +2 479 484 +2 470 484 +2 484 567 +2 470 567 +2 460 567 +2 470 516 +2 516 567 +2 484 502 +2 491 567 +2 484 491 +2 474 479 +2 474 476 +2 461 474 +2 462 478 +2 478 484 +2 469 478 +2 465 482 +2 464 481 +2 465 481 +2 481 482 +2 464 490 +2 482 490 +2 481 490 +2 473 490 +2 472 481 +2 477 481 +2 472 477 +2 465 477 +2 466 486 +2 472 486 +2 482 486 +2 480 482 +2 480 486 +2 475 496 +2 483 496 +2 496 516 +2 483 516 +2 469 559 +2 484 559 +2 476 559 +2 476 484 +2 488 559 +2 488 492 +2 469 488 +2 492 559 +2 469 492 +2 476 488 +2 484 492 +2 478 492 +2 469 489 +2 489 492 +2 478 489 +2 488 489 +2 484 516 +2 482 494 +2 475 494 +2 471 494 +2 480 494 +2 481 485 +2 472 485 +2 477 485 +2 482 485 +2 485 486 +2 473 509 +2 482 509 +2 509 544 +2 473 544 +2 482 544 +2 475 509 +2 490 544 +2 483 509 +2 476 487 +2 474 487 +2 479 487 +2 494 509 +2 509 539 +2 494 539 +2 475 539 +2 496 509 +2 496 539 +2 487 502 +2 476 502 +2 488 502 +2 487 488 +2 502 559 +2 480 549 +2 494 549 +2 482 549 +2 486 549 +2 480 511 +2 511 549 +2 486 511 +2 490 555 +2 485 490 +2 481 555 +2 485 555 +2 481 523 +2 523 555 +2 485 523 +2 494 544 +2 544 549 +2 544 555 +2 482 555 +2 486 490 +2 486 555 +2 549 555 +2 483 575 +2 496 575 +2 509 575 +2 516 575 +2 559 567 +2 502 567 +2 533 567 +2 484 533 +2 533 559 +2 492 533 +2 516 533 +2 522 523 +2 522 555 +2 485 522 +2 486 522 +2 511 537 +2 511 522 +2 522 537 +2 486 537 +2 522 549 +2 487 553 +2 488 553 +2 505 553 +2 487 505 +2 488 505 +2 502 553 +2 492 521 +2 488 521 +2 489 521 +2 521 559 +2 488 546 +2 521 546 +2 546 559 +2 553 559 +2 546 553 +2 505 546 +2 521 530 +2 492 530 +2 489 530 +2 567 596 +2 565 567 +2 491 596 +2 565 596 +2 491 565 +2 496 567 +2 502 565 +2 496 596 +2 521 561 +2 559 561 +2 492 561 +2 530 561 +2 533 561 +2 493 560 +2 504 560 +2 499 560 +2 493 504 +2 493 499 +2 499 504 +2 515 570 +2 513 515 +2 493 515 +2 513 570 +2 493 570 +2 493 513 +2 493 508 +2 508 513 +2 508 515 +2 493 593 +2 570 593 +2 499 570 +2 499 593 +2 497 593 +2 493 497 +2 497 513 +2 513 593 +2 520 570 +2 493 520 +2 515 520 +2 497 499 +2 504 520 +2 520 560 +2 560 570 +2 503 504 +2 503 520 +2 493 503 +2 539 544 +2 539 606 +2 544 606 +2 494 606 +2 549 606 +2 498 507 +2 498 545 +2 495 498 +2 507 545 +2 495 507 +2 495 545 +2 499 529 +2 495 499 +2 529 593 +2 495 529 +2 495 593 +2 495 497 +2 497 507 +2 497 545 +2 545 593 +2 514 545 +2 498 514 +2 495 514 +2 514 529 +2 500 514 +2 495 500 +2 500 529 +2 499 501 +2 501 529 +2 495 501 +2 529 545 +2 500 501 +2 497 498 +2 539 575 +2 539 596 +2 575 596 +2 567 575 +2 507 593 +2 497 519 +2 513 519 +2 519 593 +2 507 519 +2 507 517 +2 517 545 +2 498 517 +2 514 517 +2 499 609 +2 499 584 +2 584 609 +2 501 609 +2 501 584 +2 593 609 +2 584 593 +2 529 584 +2 501 510 +2 499 510 +2 510 609 +2 560 593 +2 560 609 +2 504 609 +2 504 510 +2 512 529 +2 501 512 +2 500 512 +2 547 584 +2 547 609 +2 501 547 +2 506 547 +2 501 506 +2 506 512 +2 512 547 +2 510 547 +2 506 510 +2 529 547 +2 559 565 +2 553 565 +2 503 560 +2 503 526 +2 526 560 +2 504 526 +2 503 525 +2 525 560 +2 525 526 +2 524 525 +2 503 524 +2 524 526 +2 520 525 +2 526 609 +2 510 526 +2 505 541 +2 541 553 +2 541 546 +2 510 527 +2 527 547 +2 506 527 +2 506 531 +2 531 547 +2 527 531 +2 512 531 +2 518 545 +2 545 554 +2 518 554 +2 507 518 +2 507 554 +2 517 518 +2 518 519 +2 518 593 +2 554 593 +2 528 570 +2 528 574 +2 508 528 +2 570 574 +2 508 570 +2 508 574 +2 513 574 +2 513 528 +2 575 629 +2 509 629 +2 539 629 +2 544 629 +2 527 609 +2 510 534 +2 526 534 +2 534 609 +2 527 534 +2 537 543 +2 543 600 +2 511 543 +2 537 600 +2 511 600 +2 549 600 +2 537 549 +2 532 574 +2 513 532 +2 528 532 +2 513 538 +2 532 538 +2 538 574 +2 538 593 +2 519 538 +2 574 593 +2 516 640 +2 516 604 +2 567 640 +2 604 640 +2 567 604 +2 533 604 +2 575 640 +2 517 554 +2 536 593 +2 536 554 +2 518 536 +2 519 536 +2 562 593 +2 538 562 +2 519 562 +2 536 562 +2 559 572 +2 521 572 +2 561 572 +2 546 572 +2 530 572 +2 522 659 +2 622 659 +2 659 663 +2 522 622 +2 522 663 +2 622 663 +2 537 663 +2 537 659 +2 555 566 +2 522 566 +2 523 566 +2 522 647 +2 537 647 +2 647 659 +2 537 542 +2 542 647 +2 522 542 +2 523 542 +2 542 566 +2 555 663 +2 549 663 +2 555 622 +2 566 622 +2 566 659 +2 566 647 +2 526 576 +2 524 576 +2 535 576 +2 526 535 +2 524 535 +2 524 560 +2 560 576 +2 525 576 +2 550 576 +2 548 550 +2 526 550 +2 548 576 +2 526 548 +2 550 609 +2 534 550 +2 576 609 +2 535 548 +2 527 583 +2 527 540 +2 531 583 +2 540 583 +2 531 540 +2 534 583 +2 534 557 +2 557 583 +2 527 557 +2 547 583 +2 583 609 +2 540 557 +2 528 552 +2 532 552 +2 552 574 +2 545 584 +2 530 601 +2 561 601 +2 572 601 +2 564 574 +2 538 564 +2 532 564 +2 552 564 +2 561 603 +2 559 603 +2 533 603 +2 567 603 +2 603 604 +2 595 609 +2 550 595 +2 534 595 +2 557 609 +2 557 595 +2 548 577 +2 576 577 +2 535 577 +2 554 614 +2 554 569 +2 536 614 +2 569 614 +2 536 569 +2 554 562 +2 562 614 +2 562 569 +2 647 663 +2 537 563 +2 537 558 +2 537 605 +2 558 563 +2 563 605 +2 558 605 +2 647 651 +2 556 647 +2 556 651 +2 537 651 +2 537 556 +2 563 649 +2 537 649 +2 605 649 +2 647 649 +2 649 651 +2 543 563 +2 543 558 +2 600 663 +2 600 649 +2 649 663 +2 543 605 +2 556 563 +2 563 651 +2 600 605 +2 542 556 +2 562 615 +2 593 615 +2 538 615 +2 562 581 +2 581 615 +2 538 581 +2 564 581 +2 564 615 +2 574 615 +2 575 653 +2 596 653 +2 539 653 +2 629 653 +2 606 629 +2 606 653 +2 571 583 +2 540 571 +2 557 571 +2 553 568 +2 541 568 +2 546 568 +2 541 592 +2 553 592 +2 568 592 +2 566 611 +2 611 647 +2 542 611 +2 582 611 +2 542 582 +2 566 582 +2 542 551 +2 556 582 +2 551 556 +2 551 582 +2 582 647 +2 544 648 +2 555 648 +2 549 648 +2 606 648 +2 629 648 +2 584 618 +2 593 618 +2 545 618 +2 554 618 +2 546 592 +2 546 602 +2 546 608 +2 559 602 +2 559 608 +2 602 608 +2 572 608 +2 553 602 +2 592 602 +2 568 602 +2 547 628 +2 609 628 +2 583 628 +2 584 628 +2 548 594 +2 576 594 +2 577 594 +2 550 594 +2 555 638 +2 638 663 +2 549 638 +2 600 638 +2 638 648 +2 606 638 +2 594 595 +2 594 609 +2 573 617 +2 556 573 +2 551 573 +2 556 617 +2 551 617 +2 573 582 +2 582 617 +2 564 589 +2 564 598 +2 589 598 +2 552 589 +2 552 598 +2 574 598 +2 592 627 +2 553 627 +2 627 639 +2 592 639 +2 553 639 +2 559 592 +2 625 639 +2 559 639 +2 553 625 +2 559 625 +2 625 627 +2 565 625 +2 593 614 +2 614 618 +2 648 663 +2 622 648 +2 556 664 +2 651 664 +2 578 664 +2 556 578 +2 578 651 +2 556 652 +2 651 652 +2 652 664 +2 582 652 +2 617 652 +2 647 652 +2 556 591 +2 578 591 +2 591 664 +2 617 664 +2 591 617 +2 573 591 +2 578 660 +2 563 578 +2 556 660 +2 563 660 +2 651 660 +2 597 609 +2 583 597 +2 557 597 +2 571 612 +2 583 612 +2 557 612 +2 571 597 +2 597 612 +2 595 597 +2 579 605 +2 563 579 +2 558 579 +2 559 643 +2 567 643 +2 603 643 +2 639 665 +2 559 665 +2 643 665 +2 639 643 +2 625 665 +2 608 639 +2 608 636 +2 559 636 +2 636 639 +2 636 643 +2 567 665 +2 565 665 +2 603 636 +2 625 634 +2 565 634 +2 559 634 +2 559 607 +2 607 608 +2 572 607 +2 634 665 +2 602 639 +2 607 636 +2 561 607 +2 561 636 +2 609 613 +2 560 613 +2 576 613 +2 570 609 +2 570 613 +2 561 637 +2 636 637 +2 603 637 +2 601 603 +2 601 637 +2 601 607 +2 601 636 +2 562 585 +2 581 585 +2 585 610 +2 562 610 +2 581 610 +2 562 673 +2 581 673 +2 615 673 +2 614 673 +2 610 614 +2 610 673 +2 569 610 +2 614 615 +2 569 585 +2 578 580 +2 580 660 +2 563 580 +2 563 623 +2 579 623 +2 580 623 +2 579 580 +2 649 660 +2 623 660 +2 623 649 +2 605 623 +2 581 598 +2 598 615 +2 581 589 +2 620 665 +2 620 634 +2 565 620 +2 567 620 +2 596 620 +2 611 659 +2 611 622 +2 665 691 +2 680 691 +2 567 691 +2 665 680 +2 567 680 +2 643 675 +2 665 675 +2 567 675 +2 640 657 +2 657 691 +2 567 657 +2 640 691 +2 620 657 +2 596 657 +2 620 680 +2 657 680 +2 675 691 +2 640 675 +2 604 675 +2 603 675 +2 596 640 +2 592 621 +2 602 621 +2 568 621 +2 613 655 +2 609 655 +2 570 655 +2 635 655 +2 593 635 +2 570 635 +2 593 655 +2 574 635 +2 615 635 +2 598 635 +2 653 690 +2 575 690 +2 596 690 +2 640 690 +2 575 699 +2 640 699 +2 690 699 +2 653 699 +2 629 699 +2 576 632 +2 609 632 +2 594 632 +2 577 632 +2 613 632 +2 594 619 +2 619 632 +2 577 619 +2 580 669 +2 660 669 +2 578 669 +2 660 664 +2 590 669 +2 578 590 +2 580 590 +2 578 631 +2 631 672 +2 588 631 +2 578 672 +2 578 588 +2 588 672 +2 664 669 +2 590 672 +2 669 672 +2 591 631 +2 588 591 +2 588 590 +2 664 672 +2 631 664 +2 579 626 +2 623 626 +2 580 626 +2 580 670 +2 669 670 +2 590 670 +2 660 670 +2 590 626 +2 626 670 +2 599 626 +2 590 599 +2 580 599 +2 626 660 +2 581 646 +2 581 616 +2 589 646 +2 616 646 +2 589 616 +2 598 646 +2 586 668 +2 581 668 +2 668 689 +2 581 586 +2 586 689 +2 581 689 +2 646 689 +2 615 646 +2 615 689 +2 586 587 +2 586 616 +2 581 587 +2 587 616 +2 616 668 +2 646 668 +2 587 589 +2 585 673 +2 585 689 +2 673 689 +2 585 586 +2 611 652 +2 611 617 +2 583 656 +2 609 656 +2 628 656 +2 609 612 +2 612 656 +2 593 628 +2 618 628 +2 610 689 +2 588 650 +2 650 679 +2 585 650 +2 588 679 +2 585 588 +2 585 679 +2 610 679 +2 679 689 +2 586 679 +2 588 610 +2 610 650 +2 590 679 +2 585 590 +2 586 590 +2 590 678 +2 590 641 +2 586 678 +2 641 678 +2 586 641 +2 586 682 +2 616 682 +2 668 682 +2 682 689 +2 678 679 +2 678 689 +2 616 678 +2 678 682 +2 587 641 +2 616 641 +2 587 590 +2 599 616 +2 587 599 +2 599 641 +2 650 672 +2 631 650 +2 672 679 +2 669 678 +2 669 679 +2 670 678 +2 641 670 +2 626 641 +2 627 633 +2 592 633 +2 621 633 +2 621 627 +2 602 633 +2 633 639 +2 618 687 +2 593 687 +2 609 687 +2 609 618 +2 593 686 +2 593 671 +2 615 686 +2 671 686 +2 615 671 +2 618 686 +2 686 687 +2 618 671 +2 614 671 +2 655 686 +2 609 686 +2 635 686 +2 609 619 +2 595 619 +2 597 642 +2 642 656 +2 595 642 +2 597 656 +2 595 656 +2 619 642 +2 609 642 +2 657 690 +2 597 666 +2 656 666 +2 612 666 +2 642 666 +2 597 624 +2 612 624 +2 624 666 +2 624 642 +2 635 646 +2 607 637 +2 630 637 +2 601 630 +2 607 630 +2 608 633 +2 637 643 +2 643 644 +2 644 675 +2 603 644 +2 637 644 +2 674 675 +2 604 674 +2 603 674 +2 644 674 +2 675 701 +2 604 701 +2 674 701 +2 640 701 +2 606 677 +2 629 677 +2 653 677 +2 648 677 +2 638 677 +2 630 636 +2 609 684 +2 642 684 +2 632 684 +2 632 642 +2 613 684 +2 613 709 +2 609 709 +2 655 709 +2 628 687 +2 656 717 +2 609 717 +2 642 717 +2 656 687 +2 686 717 +2 687 717 +2 684 717 +2 655 717 +2 684 709 +2 709 717 +2 679 685 +2 610 685 +2 650 685 +2 673 685 +2 685 689 +2 645 647 +2 645 652 +2 611 645 +2 617 645 +2 645 659 +2 612 654 +2 654 656 +2 624 656 +2 624 654 +2 614 686 +2 671 673 +2 673 686 +2 646 686 +2 646 708 +2 686 708 +2 615 708 +2 689 708 +2 686 689 +2 646 695 +2 635 695 +2 615 695 +2 686 695 +2 641 682 +2 641 668 +2 671 687 +2 619 658 +2 642 658 +2 632 658 +2 661 665 +2 620 661 +2 634 661 +2 620 667 +2 667 680 +2 657 667 +2 661 680 +2 634 680 +2 634 667 +2 622 703 +2 663 703 +2 659 703 +2 648 703 +2 622 681 +2 681 703 +2 648 681 +2 659 681 +2 649 662 +2 623 662 +2 660 662 +2 626 662 +2 654 666 +2 625 661 +2 639 661 +2 662 670 +2 711 714 +2 677 714 +2 629 714 +2 677 711 +2 629 711 +2 653 711 +2 653 733 +2 711 733 +2 629 733 +2 629 721 +2 653 721 +2 711 721 +2 699 733 +2 699 711 +2 648 714 +2 677 721 +2 658 684 +2 661 667 +2 686 704 +2 695 704 +2 635 704 +2 655 704 +2 663 716 +2 703 716 +2 638 716 +2 638 703 +2 638 710 +2 677 710 +2 710 716 +2 677 716 +2 677 703 +2 663 710 +2 657 700 +2 640 700 +2 691 700 +2 691 701 +2 700 727 +2 690 700 +2 640 727 +2 690 727 +2 640 738 +2 727 738 +2 699 727 +2 699 738 +2 707 727 +2 691 727 +2 640 707 +2 691 707 +2 701 727 +2 700 707 +2 701 738 +2 641 676 +2 676 678 +2 676 682 +2 670 676 +2 668 676 +2 656 694 +2 666 694 +2 642 694 +2 694 717 +2 684 694 +2 658 694 +2 646 693 +2 689 693 +2 668 693 +2 695 708 +2 693 695 +2 693 708 +2 703 714 +2 648 720 +2 703 720 +2 714 720 +2 681 720 +2 690 733 +2 653 729 +2 711 729 +2 721 729 +2 690 729 +2 729 733 +2 654 692 +2 666 692 +2 683 692 +2 654 683 +2 666 683 +2 656 692 +2 704 717 +2 704 709 +2 687 702 +2 656 702 +2 702 717 +2 692 702 +2 666 702 +2 694 702 +2 657 707 +2 697 707 +2 697 700 +2 657 697 +2 680 697 +2 680 707 +2 680 688 +2 657 688 +2 688 697 +2 667 688 +2 694 698 +2 684 698 +2 658 698 +2 692 706 +2 683 706 +2 666 706 +2 692 694 +2 694 706 +2 682 693 +2 671 705 +2 686 705 +2 673 705 +2 686 712 +2 671 712 +2 705 712 +2 687 712 +2 696 705 +2 705 713 +2 673 696 +2 696 713 +2 673 713 +2 686 696 +2 689 696 +2 685 696 +2 714 725 +2 714 754 +2 677 725 +2 677 754 +2 725 754 +2 716 754 +2 716 725 +2 710 725 +2 703 754 +2 714 721 +2 721 725 +2 688 707 +2 682 708 +2 683 723 +2 706 723 +2 692 723 +2 694 718 +2 684 718 +2 698 718 +2 684 730 +2 718 730 +2 730 736 +2 684 736 +2 718 736 +2 717 718 +2 709 736 +2 717 736 +2 698 730 +2 686 735 +2 686 785 +2 686 764 +2 735 785 +2 735 764 +2 764 785 +2 743 745 +2 705 743 +2 686 743 +2 705 745 +2 686 745 +2 744 785 +2 686 744 +2 735 744 +2 686 722 +2 705 722 +2 696 722 +2 695 735 +2 695 744 +2 686 759 +2 686 771 +2 745 759 +2 745 771 +2 759 771 +2 708 744 +2 759 794 +2 717 759 +2 686 794 +2 717 794 +2 712 717 +2 712 745 +2 712 759 +2 771 794 +2 771 785 +2 785 794 +2 755 785 +2 686 755 +2 755 764 +2 704 755 +2 704 764 +2 755 794 +2 708 722 +2 689 722 +2 744 771 +2 717 755 +2 704 735 +2 743 771 +2 743 744 +2 722 743 +2 722 744 +2 687 752 +2 687 737 +2 717 752 +2 717 737 +2 737 752 +2 712 752 +2 702 737 +2 733 742 +2 732 733 +2 690 742 +2 690 732 +2 732 742 +2 733 751 +2 690 751 +2 732 751 +2 729 751 +2 700 742 +2 700 732 +2 727 733 +2 700 733 +2 692 724 +2 706 724 +2 723 724 +2 702 706 +2 702 724 +2 708 715 +2 695 715 +2 693 715 +2 706 728 +2 694 728 +2 702 728 +2 718 728 +2 717 728 +2 695 731 +2 731 735 +2 731 744 +2 708 734 +2 695 734 +2 734 744 +2 731 734 +2 708 731 +2 715 731 +2 713 722 +2 697 719 +2 707 719 +2 700 719 +2 733 738 +2 699 757 +2 711 757 +2 733 757 +2 738 763 +2 733 763 +2 699 763 +2 757 763 +2 707 742 +2 727 742 +2 719 742 +2 719 732 +2 724 728 +2 724 737 +2 717 724 +2 714 739 +2 703 739 +2 739 754 +2 720 739 +2 716 739 +2 709 755 +2 726 745 +2 726 743 +2 705 726 +2 722 726 +2 713 726 +2 706 741 +2 724 741 +2 728 741 +2 723 741 +2 715 734 +2 717 747 +2 709 747 +2 747 755 +2 736 747 +2 716 749 +2 725 749 +2 710 749 +2 721 762 +2 729 762 +2 711 762 +2 762 768 +2 711 768 +2 768 776 +2 762 776 +2 711 776 +2 757 776 +2 757 762 +2 733 762 +2 714 762 +2 714 768 +2 752 759 +2 713 743 +2 714 775 +2 739 775 +2 760 775 +2 714 760 +2 739 760 +2 754 775 +2 762 775 +2 754 762 +2 720 760 +2 768 775 +2 725 762 +2 760 768 +2 749 754 +2 717 783 +2 756 783 +2 766 783 +2 717 756 +2 717 766 +2 756 766 +2 717 741 +2 777 798 +2 747 798 +2 717 798 +2 747 777 +2 717 777 +2 717 793 +2 752 793 +2 737 793 +2 717 807 +2 794 807 +2 755 807 +2 752 804 +2 759 804 +2 717 804 +2 766 793 +2 737 766 +2 736 746 +2 717 746 +2 746 761 +2 736 761 +2 717 761 +2 804 807 +2 752 807 +2 717 805 +2 752 805 +2 793 805 +2 741 766 +2 737 741 +2 759 807 +2 718 746 +2 798 807 +2 755 798 +2 755 777 +2 747 783 +2 736 783 +2 746 756 +2 718 756 +2 761 783 +2 783 793 +2 793 798 +2 783 798 +2 728 766 +2 728 756 +2 756 761 +2 805 807 +2 793 807 +2 728 746 +2 730 746 +2 721 773 +2 725 773 +2 762 773 +2 729 773 +2 723 740 +2 724 740 +2 740 741 +2 740 753 +2 724 753 +2 741 753 +2 753 766 +2 724 766 +2 737 753 +2 762 765 +2 725 765 +2 754 765 +2 765 773 +2 749 765 +2 726 748 +2 745 748 +2 743 748 +2 727 779 +2 727 770 +2 733 779 +2 733 770 +2 770 779 +2 738 770 +2 742 779 +2 741 756 +2 729 791 +2 762 791 +2 773 791 +2 733 767 +2 751 767 +2 729 767 +2 762 767 +2 767 791 +2 730 750 +2 746 750 +2 736 750 +2 734 735 +2 731 758 +2 731 769 +2 758 769 +2 735 758 +2 735 769 +2 734 769 +2 734 758 +2 732 774 +2 732 779 +2 774 779 +2 751 774 +2 751 779 +2 742 751 +2 742 774 +2 779 788 +2 733 788 +2 770 788 +2 763 788 +2 763 820 +2 733 820 +2 788 820 +2 733 784 +2 779 784 +2 784 788 +2 733 829 +2 762 829 +2 784 829 +2 762 784 +2 751 784 +2 757 824 +2 762 824 +2 733 824 +2 784 820 +2 820 824 +2 784 824 +2 767 784 +2 824 829 +2 763 770 +2 763 824 +2 744 769 +2 780 785 +2 764 780 +2 735 780 +2 769 785 +2 758 780 +2 769 780 +2 750 761 +2 761 778 +2 747 778 +2 736 778 +2 747 761 +2 778 781 +2 747 781 +2 736 781 +2 750 778 +2 737 795 +2 793 795 +2 752 795 +2 737 782 +2 753 782 +2 766 782 +2 782 793 +2 782 795 +2 771 772 +2 745 772 +2 743 772 +2 748 772 +2 769 771 +2 772 787 +2 745 787 +2 771 787 +2 759 787 +2 781 798 +2 781 783 +2 777 781 +2 778 783 +2 754 797 +2 749 797 +2 765 797 +2 774 784 +2 784 786 +2 774 786 +2 751 786 +2 784 792 +2 751 792 +2 767 792 +2 786 792 +2 759 789 +2 752 789 +2 789 804 +2 804 805 +2 789 805 +2 795 805 +2 789 795 +2 754 809 +2 775 809 +2 762 809 +2 765 809 +2 797 809 +2 785 807 +2 764 807 +2 806 807 +2 777 807 +2 755 806 +2 777 806 +2 799 807 +2 755 799 +2 799 806 +2 764 799 +2 762 828 +2 757 828 +2 824 828 +2 776 828 +2 776 824 +2 757 813 +2 813 824 +2 813 815 +2 757 815 +2 815 824 +2 776 815 +2 763 813 +2 800 804 +2 759 800 +2 789 800 +2 794 804 +2 787 804 +2 787 794 +2 787 800 +2 760 801 +2 760 802 +2 775 801 +2 801 802 +2 775 802 +2 768 802 +2 776 826 +2 768 826 +2 762 826 +2 775 836 +2 809 836 +2 762 836 +2 826 836 +2 775 826 +2 791 814 +2 791 827 +2 762 814 +2 762 827 +2 814 827 +2 767 829 +2 773 809 +2 773 836 +2 828 836 +2 828 829 +2 829 836 +2 803 829 +2 762 803 +2 767 803 +2 814 836 +2 827 836 +2 826 828 +2 827 829 +2 773 814 +2 791 829 +2 791 803 +2 763 811 +2 788 811 +2 770 811 +2 811 820 +2 813 820 +2 811 813 +2 785 799 +2 780 799 +2 765 808 +2 808 809 +2 797 808 +2 773 808 +2 792 803 +2 784 803 +2 768 812 +2 812 826 +2 802 826 +2 802 812 +2 776 812 +2 814 832 +2 773 832 +2 832 836 +2 808 836 +2 808 814 +2 808 832 +2 784 796 +2 779 796 +2 774 796 +2 796 810 +2 786 796 +2 786 810 +2 774 810 +2 801 831 +2 826 831 +2 775 831 +2 801 826 +2 809 831 +2 831 836 +2 812 828 +2 812 815 +2 815 828 +2 798 806 +2 790 798 +2 777 790 +2 790 806 +2 781 790 +2 788 817 +2 784 817 +2 779 817 +2 796 817 +2 823 824 +2 784 823 +2 820 823 +2 786 821 +2 784 821 +2 792 821 +2 818 821 +2 796 821 +2 784 818 +2 796 818 +2 817 820 +2 784 825 +2 792 825 +2 803 825 +2 825 829 +2 823 829 +2 821 825 +2 817 821 +2 817 818 +2 817 823 +2 821 823 +2 823 825 +2 794 799 +2 786 818 +2 818 819 +2 786 819 +2 819 821 +2 810 819 +2 810 818 +2 792 819 +2 803 827 +2 827 830 +2 791 830 +2 803 830 +2 819 822 +2 792 822 +2 821 822 +2 822 825 +2 792 816 +2 816 825 +2 816 822 +2 803 816 +2 808 834 +2 809 834 +2 797 834 +2 831 835 +2 831 838 +2 801 835 +2 835 838 +2 801 838 +2 802 835 +2 802 838 +2 802 831 +2 812 835 +2 826 835 +2 825 827 +2 825 830 +2 816 830 +2 809 833 +2 833 836 +2 808 833 +2 833 834 +2 814 833 +2 832 833 +2 834 841 +2 809 841 +2 833 841 +2 836 841 +2 831 841 +2 815 826 +2 812 839 +2 835 839 +2 826 839 +2 814 837 +2 833 837 +2 832 837 +2 827 832 +2 836 842 +2 831 842 +2 826 842 +2 839 842 +2 835 842 +2 835 844 +2 838 844 +2 831 844 +2 841 851 +2 831 851 +2 842 851 +2 841 842 +2 842 844 +2 831 847 +2 847 851 +2 842 847 +2 844 847 +2 841 847 +2 838 847 +2 833 845 +2 832 845 +2 837 845 +2 836 845 +2 841 845 +2 833 840 +2 840 845 +2 840 841 +2 834 840 +2 837 840 +2 834 843 +2 840 843 +2 841 843 +2 841 848 +2 834 848 +2 843 848 +2 844 846 +2 839 844 +2 835 846 +2 839 846 +2 836 851 +2 845 851 +2 840 850 +2 845 850 +2 837 850 +2 844 854 +2 838 854 +2 847 854 +2 846 852 +2 842 846 +2 842 852 +2 839 852 +2 841 849 +2 845 849 +2 840 849 +2 843 849 +2 840 848 +2 848 849 +2 849 850 +2 853 861 +2 841 853 +2 851 853 +2 841 861 +2 851 861 +2 849 861 +2 845 861 +2 848 853 +2 848 861 +2 847 853 +2 847 852 +2 851 852 +2 844 852 +2 844 855 +2 844 859 +2 855 859 +2 847 855 +2 847 859 +2 852 855 +2 846 855 +2 854 859 +2 850 861 +2 852 856 +2 855 856 +2 846 856 +2 859 867 +2 847 867 +2 862 867 +2 859 862 +2 847 862 +2 854 863 +2 859 863 +2 847 863 +2 862 863 +2 851 869 +2 847 869 +2 852 869 +2 853 869 +2 862 869 +2 853 862 +2 867 869 +2 852 867 +2 852 859 +2 849 858 +2 857 858 +2 848 858 +2 849 857 +2 848 857 +2 858 861 +2 853 858 +2 849 860 +2 860 861 +2 850 860 +2 849 865 +2 858 865 +2 857 865 +2 860 865 +2 858 860 +2 860 864 +2 861 864 +2 850 864 +2 861 869 +2 855 867 +2 856 867 +2 869 874 +2 853 874 +2 862 874 +2 861 874 +2 858 874 +2 853 870 +2 870 874 +2 858 870 +2 862 870 +2 863 868 +2 859 868 +2 854 868 +2 857 866 +2 865 866 +2 858 866 +2 870 871 +2 858 871 +2 865 871 +2 865 870 +2 861 865 +2 871 874 +2 866 870 +2 865 874 +2 867 868 +2 863 867 +2 859 872 +2 868 872 +2 867 872 +2 864 865 +2 860 871 +2 864 871 +2 864 874 +2 863 869 +2 862 883 +2 869 883 +2 863 883 +2 862 877 +2 874 877 +2 870 877 +2 863 873 +2 873 883 +2 862 873 +2 873 877 +2 877 883 +2 874 883 +2 863 876 +2 873 876 +2 868 876 +2 868 873 +2 868 879 +2 863 872 +2 863 879 +2 872 879 +2 876 883 +2 869 879 +2 879 883 +2 869 872 +2 876 879 +2 871 875 +2 874 875 +2 864 875 +2 866 871 +2 866 878 +2 870 878 +2 871 878 +2 867 879 +2 872 876 +2 869 886 +2 874 886 +2 883 886 +2 879 886 +2 882 887 +2 887 888 +2 870 887 +2 882 888 +2 870 882 +2 870 888 +2 877 888 +2 877 887 +2 870 883 +2 883 887 +2 874 887 +2 871 882 +2 874 882 +2 878 888 +2 878 882 +2 875 882 +2 876 881 +2 872 881 +2 879 881 +2 880 883 +2 873 880 +2 880 884 +2 883 884 +2 873 884 +2 876 884 +2 877 880 +2 875 887 +2 886 887 +2 881 884 +2 881 883 +2 888 891 +2 877 891 +2 883 891 +2 883 888 +2 880 891 +2 888 894 +2 882 894 +2 878 894 +2 879 885 +2 883 885 +2 885 886 +2 881 885 +2 884 893 +2 880 893 +2 883 893 +2 891 893 +2 892 893 +2 880 892 +2 891 892 +2 881 889 +2 885 889 +2 883 889 +2 884 889 +2 889 890 +2 885 890 +2 881 890 +2 887 894 +2 894 898 +2 887 898 +2 882 898 +2 891 900 +2 891 906 +2 900 906 +2 883 900 +2 883 906 +2 885 895 +2 883 895 +2 886 895 +2 888 897 +2 887 897 +2 883 897 +2 886 897 +2 895 897 +2 897 906 +2 891 897 +2 893 900 +2 889 895 +2 889 893 +2 893 895 +2 895 900 +2 895 906 +2 890 895 +2 894 897 +2 897 898 +2 888 910 +2 894 910 +2 909 910 +2 888 909 +2 894 909 +2 888 915 +2 897 910 +2 910 915 +2 897 915 +2 903 909 +2 909 915 +2 903 915 +2 888 903 +2 902 909 +2 888 902 +2 902 903 +2 891 915 +2 891 903 +2 894 902 +2 889 900 +2 900 901 +2 895 901 +2 889 901 +2 896 900 +2 889 896 +2 896 901 +2 895 896 +2 890 896 +2 904 906 +2 906 915 +2 891 904 +2 904 915 +2 893 904 +2 892 904 +2 899 904 +2 891 899 +2 892 899 +2 899 915 +2 899 903 +2 900 904 +2 898 909 +2 898 907 +2 907 909 +2 894 907 +2 898 910 +2 901 906 +2 900 905 +2 896 905 +2 901 905 +2 906 910 +2 907 910 +2 913 915 +2 912 915 +2 912 913 +2 899 913 +2 899 912 +2 899 908 +2 904 912 +2 908 912 +2 904 908 +2 903 913 +2 908 913 +2 900 914 +2 906 914 +2 905 914 +2 905 906 +2 912 914 +2 906 912 +2 900 912 +2 915 923 +2 909 923 +2 902 923 +2 902 915 +2 916 925 +2 902 916 +2 916 923 +2 902 925 +2 923 925 +2 916 922 +2 902 922 +2 922 925 +2 915 916 +2 903 916 +2 913 916 +2 914 917 +2 905 917 +2 906 917 +2 906 919 +2 917 919 +2 914 919 +2 914 915 +2 910 919 +2 915 919 +2 910 911 +2 907 911 +2 909 911 +2 912 924 +2 913 924 +2 908 924 +2 908 921 +2 913 921 +2 921 924 +2 909 918 +2 909 920 +2 918 920 +2 918 923 +2 920 923 +2 915 920 +2 910 920 +2 911 918 +2 911 920 +2 910 927 +2 919 927 +2 915 927 +2 920 927 +2 924 928 +2 915 924 +2 915 928 +2 912 928 +2 914 928 +2 915 933 +2 913 933 +2 924 933 +2 913 926 +2 916 933 +2 916 926 +2 926 933 +2 929 933 +2 913 929 +2 926 929 +2 924 929 +2 921 926 +2 921 929 +2 917 928 +2 919 928 +2 919 933 +2 928 933 +2 923 933 +2 923 930 +2 915 930 +2 930 933 +2 927 930 +2 927 933 +2 920 930 +2 922 935 +2 922 933 +2 933 935 +2 916 935 +2 925 933 +2 926 935 +2 919 932 +2 928 932 +2 917 932 +2 930 934 +2 920 934 +2 918 934 +2 918 930 +2 932 933 +2 933 941 +2 927 941 +2 919 941 +2 932 941 +2 927 932 +2 927 934 +2 926 931 +2 929 931 +2 921 931 +2 935 937 +2 935 936 +2 922 937 +2 936 937 +2 922 936 +2 925 936 +2 933 936 +2 925 937 +2 933 940 +2 923 940 +2 923 936 +2 936 940 +2 930 940 +2 929 938 +2 933 938 +2 924 938 +2 933 942 +2 928 942 +2 924 942 +2 938 942 +2 933 945 +2 926 945 +2 931 945 +2 931 933 +2 935 945 +2 941 946 +2 934 946 +2 927 946 +2 934 941 +2 933 946 +2 930 946 +2 941 942 +2 928 941 +2 928 944 +2 932 944 +2 932 942 +2 942 944 +2 931 939 +2 929 939 +2 938 939 +2 931 938 +2 934 943 +2 930 943 +2 940 943 +2 934 940 +2 940 946 +2 938 945 +2 939 945 +2 941 944 +2 938 958 +2 933 958 +2 942 958 +2 935 949 +2 933 949 +2 936 949 +2 933 955 +2 933 951 +2 933 957 +2 951 955 +2 955 957 +2 951 957 +2 946 955 +2 940 955 +2 957 958 +2 949 958 +2 949 957 +2 940 957 +2 951 958 +2 946 951 +2 941 951 +2 945 949 +2 945 958 +2 936 957 +2 942 951 +2 943 946 +2 937 949 +2 954 957 +2 950 954 +2 936 954 +2 950 957 +2 936 950 +2 949 954 +2 936 948 +2 948 950 +2 948 954 +2 940 950 +2 948 949 +2 937 948 +2 942 953 +2 938 953 +2 953 958 +2 938 947 +2 947 953 +2 945 947 +2 945 953 +2 939 947 +2 950 955 +2 950 952 +2 940 952 +2 952 955 +2 946 952 +2 943 952 +2 944 951 +2 944 956 +2 942 956 +2 951 956 +2 953 956 +2 956 958 +2 955 958 +3 1 36 13 +3 0 1 13 +3 0 36 1 +3 0 13 36 +3 0 2 36 +3 0 5 2 +3 2 5 36 +3 0 36 5 +3 1 13 6 +3 0 1 6 +3 0 6 13 +3 0 6 36 +3 6 13 36 +3 0 10 36 +3 0 36 7 +3 0 7 10 +3 7 36 10 +3 0 6 5 +3 5 6 36 +3 2 36 7 +3 0 2 7 +3 0 10 1 +3 1 10 36 +3 1 32 10 +3 1 10 20 +3 1 20 32 +3 10 32 20 +3 1 36 32 +3 1 32 13 +3 13 32 36 +3 10 36 32 +3 2 8 23 +3 2 3 8 +3 3 23 8 +3 2 23 3 +3 2 22 23 +3 2 36 22 +3 22 36 23 +3 2 23 36 +3 5 36 22 +3 2 5 22 +3 2 22 3 +3 3 22 23 +3 7 8 23 +3 2 8 7 +3 2 7 23 +3 7 23 36 +3 3 4 22 +3 2 22 4 +3 2 4 3 +3 4 5 22 +3 2 5 4 +3 4 5 18 +3 5 22 18 +3 4 18 22 +3 4 9 18 +3 5 18 9 +3 4 5 9 +3 5 40 18 +3 18 40 22 +3 5 22 40 +3 5 54 36 +3 5 6 54 +3 6 36 54 +3 5 40 19 +3 5 19 18 +3 18 19 40 +3 22 40 36 +3 5 36 40 +3 5 40 54 +3 19 54 40 +3 5 54 19 +3 6 54 19 +3 5 6 19 +3 9 19 18 +3 5 19 9 +3 36 40 54 +3 6 43 21 +3 21 43 54 +3 6 21 54 +3 6 54 43 +3 6 36 43 +3 36 54 43 +3 6 12 21 +3 12 43 21 +3 6 43 12 +3 13 36 43 +3 6 13 43 +3 6 21 19 +3 19 21 54 +3 6 13 12 +3 12 13 43 +3 8 23 31 +3 7 8 31 +3 7 31 23 +3 7 36 31 +3 11 31 36 +3 7 31 11 +3 7 11 36 +3 23 36 31 +3 7 11 10 +3 10 11 36 +3 7 8 11 +3 7 16 8 +3 8 16 11 +3 7 11 16 +3 8 31 16 +3 7 16 31 +3 11 16 31 +3 16 23 31 +3 8 23 16 +3 9 17 18 +3 17 30 18 +3 9 18 30 +3 9 30 17 +3 9 19 17 +3 9 30 19 +3 17 19 30 +3 18 30 19 +3 10 32 50 +3 10 50 20 +3 20 50 32 +3 10 50 29 +3 10 29 20 +3 20 29 50 +3 10 11 25 +3 11 36 25 +3 10 25 36 +3 29 36 50 +3 10 50 36 +3 10 36 29 +3 25 36 29 +3 10 25 29 +3 32 50 36 +3 11 16 15 +3 15 16 31 +3 11 15 31 +3 11 25 31 +3 11 15 25 +3 15 31 25 +3 14 16 15 +3 11 16 14 +3 11 14 15 +3 25 31 36 +3 12 38 26 +3 21 26 38 +3 12 26 21 +3 12 21 38 +3 12 43 38 +3 21 38 43 +3 13 32 43 +3 32 36 43 +3 14 28 24 +3 14 15 28 +3 15 24 28 +3 14 24 15 +3 14 31 28 +3 14 15 31 +3 15 28 31 +3 14 16 31 +3 28 31 47 +3 15 47 31 +3 15 28 47 +3 15 28 25 +3 25 28 47 +3 15 25 47 +3 24 28 25 +3 15 24 25 +3 25 47 31 +3 19 30 27 +3 17 19 27 +3 17 27 30 +3 19 40 30 +3 18 30 40 +3 19 54 42 +3 30 42 54 +3 19 42 30 +3 19 30 54 +3 27 33 30 +3 19 30 33 +3 19 33 27 +3 30 33 42 +3 19 42 33 +3 33 54 42 +3 19 54 33 +3 30 54 40 +3 19 21 33 +3 21 54 33 +3 20 29 51 +3 20 51 50 +3 29 50 51 +3 21 35 54 +3 21 38 35 +3 35 38 54 +3 21 54 38 +3 33 35 54 +3 21 35 33 +3 21 26 35 +3 26 38 35 +3 38 43 54 +3 22 41 23 +3 23 41 36 +3 22 36 41 +3 22 40 41 +3 36 41 40 +3 31 41 36 +3 23 41 31 +3 24 34 37 +3 24 28 34 +3 28 37 34 +3 24 37 28 +3 25 37 28 +3 24 37 25 +3 25 50 29 +3 25 36 50 +3 25 47 36 +3 31 36 47 +3 25 47 37 +3 25 48 47 +3 37 47 48 +3 25 37 48 +3 28 47 37 +3 25 50 47 +3 25 47 29 +3 29 47 50 +3 25 29 48 +3 25 37 29 +3 29 37 48 +3 29 48 47 +3 36 50 47 +3 26 39 35 +3 35 39 38 +3 26 38 39 +3 27 42 30 +3 27 33 42 +3 27 49 42 +3 33 42 49 +3 27 33 49 +3 27 45 49 +3 33 49 45 +3 27 33 45 +3 28 47 34 +3 34 47 37 +3 48 50 51 +3 29 50 48 +3 29 48 51 +3 47 50 48 +3 30 42 40 +3 40 42 54 +3 31 41 47 +3 36 47 41 +3 32 64 36 +3 36 64 50 +3 32 50 64 +3 32 64 43 +3 36 43 64 +3 35 54 46 +3 33 35 46 +3 33 46 54 +3 42 49 45 +3 33 42 45 +3 42 45 54 +3 33 54 45 +3 45 46 54 +3 33 46 45 +3 37 44 53 +3 34 53 44 +3 34 37 53 +3 34 44 37 +3 37 53 47 +3 34 47 53 +3 35 39 57 +3 35 57 38 +3 38 57 39 +3 35 46 57 +3 35 52 46 +3 46 52 57 +3 35 57 52 +3 46 57 54 +3 35 54 57 +3 38 54 57 +3 35 39 52 +3 39 57 52 +3 36 54 63 +3 36 64 54 +3 54 64 63 +3 36 63 64 +3 36 41 67 +3 36 63 41 +3 41 63 67 +3 36 67 63 +3 36 64 67 +3 36 67 50 +3 50 67 64 +3 41 67 47 +3 36 47 67 +3 40 54 63 +3 36 40 63 +3 47 67 50 +3 43 64 54 +3 63 64 67 +3 40 63 41 +3 47 61 53 +3 37 53 61 +3 37 61 47 +3 37 61 48 +3 47 48 61 +3 48 58 53 +3 37 53 58 +3 37 48 53 +3 37 58 48 +3 44 53 58 +3 37 44 58 +3 48 53 61 +3 43 54 57 +3 38 43 57 +3 39 55 52 +3 52 55 57 +3 39 57 55 +3 40 54 59 +3 40 59 72 +3 40 72 54 +3 54 72 59 +3 40 72 63 +3 54 63 72 +3 40 42 59 +3 42 54 59 +3 45 59 49 +3 42 59 45 +3 42 49 59 +3 45 54 59 +3 43 64 75 +3 43 75 54 +3 54 75 64 +3 43 75 57 +3 54 57 75 +3 45 62 56 +3 45 56 59 +3 45 59 62 +3 56 62 59 +3 45 56 49 +3 49 56 59 +3 46 54 59 +3 45 46 59 +3 46 59 62 +3 45 46 62 +3 46 52 65 +3 46 65 57 +3 52 57 65 +3 46 65 54 +3 54 65 57 +3 46 62 54 +3 46 65 62 +3 54 62 65 +3 54 59 62 +3 47 67 61 +3 47 61 50 +3 50 61 67 +3 48 61 50 +3 48 68 51 +3 48 51 69 +3 48 69 68 +3 51 68 69 +3 50 51 69 +3 48 50 69 +3 50 69 61 +3 48 61 69 +3 51 73 68 +3 48 68 73 +3 48 73 51 +3 53 61 58 +3 48 58 61 +3 61 69 68 +3 48 61 68 +3 48 58 68 +3 58 61 68 +3 49 56 66 +3 49 66 59 +3 56 59 66 +3 61 67 69 +3 50 69 67 +3 64 69 67 +3 50 69 64 +3 51 73 69 +3 68 69 73 +3 52 60 65 +3 52 57 60 +3 57 65 60 +3 52 55 60 +3 55 57 60 +3 58 74 61 +3 53 61 74 +3 53 74 58 +3 54 79 72 +3 54 75 79 +3 72 79 75 +3 54 72 75 +3 54 59 79 +3 54 66 59 +3 59 66 79 +3 54 79 66 +3 59 79 72 +3 63 75 64 +3 54 75 63 +3 62 65 79 +3 54 79 65 +3 54 62 79 +3 54 66 62 +3 59 62 66 +3 57 75 70 +3 54 57 70 +3 54 70 75 +3 65 75 79 +3 54 75 65 +3 63 72 75 +3 62 79 66 +3 54 70 65 +3 65 70 75 +3 57 70 65 +3 57 60 70 +3 55 70 60 +3 55 57 70 +3 56 62 66 +3 56 76 66 +3 56 62 76 +3 62 66 76 +3 60 70 65 +3 61 68 74 +3 58 74 68 +3 65 71 70 +3 60 71 65 +3 60 70 71 +3 61 68 88 +3 61 88 74 +3 68 74 88 +3 67 69 88 +3 61 88 69 +3 61 67 88 +3 67 88 77 +3 61 77 88 +3 61 67 77 +3 61 77 74 +3 74 77 88 +3 68 88 69 +3 62 78 79 +3 62 65 78 +3 65 79 78 +3 66 78 79 +3 62 78 66 +3 66 76 78 +3 62 78 76 +3 63 72 64 +3 64 72 75 +3 63 64 89 +3 64 84 89 +3 63 89 84 +3 63 84 64 +3 64 67 84 +3 63 84 67 +3 64 89 72 +3 63 72 89 +3 63 72 84 +3 72 89 84 +3 67 84 90 +3 64 67 90 +3 64 90 84 +3 67 90 69 +3 64 69 90 +3 72 75 89 +3 64 89 75 +3 84 89 90 +3 64 90 89 +3 65 78 70 +3 65 70 80 +3 65 80 78 +3 70 78 80 +3 65 79 70 +3 70 79 78 +3 70 75 79 +3 70 80 71 +3 65 71 80 +3 66 76 79 +3 76 78 79 +3 84 90 88 +3 67 84 88 +3 67 88 90 +3 67 92 88 +3 84 88 92 +3 67 84 92 +3 69 88 90 +3 77 92 88 +3 67 92 77 +3 68 81 88 +3 68 74 81 +3 74 88 81 +3 68 82 83 +3 68 88 82 +3 82 88 83 +3 68 83 88 +3 68 83 69 +3 69 83 88 +3 69 73 83 +3 68 83 73 +3 68 81 82 +3 81 88 82 +3 73 82 83 +3 68 82 73 +3 83 88 90 +3 69 83 90 +3 70 86 80 +3 70 78 86 +3 78 80 86 +3 70 79 86 +3 78 86 79 +3 70 75 86 +3 75 79 86 +3 71 86 80 +3 70 86 71 +3 72 79 95 +3 75 95 79 +3 72 95 75 +3 84 95 89 +3 72 95 84 +3 72 89 95 +3 75 89 95 +3 82 83 87 +3 73 82 87 +3 73 87 83 +3 74 77 85 +3 74 85 88 +3 77 88 85 +3 81 85 88 +3 74 85 81 +3 75 98 95 +3 75 89 98 +3 89 95 98 +3 79 86 95 +3 75 95 86 +3 75 98 86 +3 86 98 95 +3 76 78 100 +3 76 100 79 +3 78 79 100 +3 77 92 85 +3 85 92 88 +3 78 80 94 +3 80 86 94 +3 78 94 86 +3 79 100 94 +3 78 79 94 +3 78 94 100 +3 79 94 86 +3 94 95 100 +3 79 100 95 +3 79 95 94 +3 86 95 94 +3 86 94 103 +3 80 103 94 +3 80 86 103 +3 81 93 85 +3 81 91 93 +3 85 93 91 +3 81 85 91 +3 85 88 93 +3 81 93 88 +3 82 93 88 +3 81 93 82 +3 91 93 96 +3 81 96 93 +3 81 91 96 +3 82 83 101 +3 82 101 87 +3 83 87 101 +3 82 88 101 +3 83 101 88 +3 88 101 93 +3 82 93 101 +3 88 104 101 +3 83 101 104 +3 83 104 88 +3 88 90 104 +3 83 104 90 +3 83 101 97 +3 97 101 104 +3 83 97 104 +3 87 101 97 +3 83 87 97 +3 84 90 105 +3 84 105 88 +3 88 105 90 +3 84 115 95 +3 95 115 109 +3 84 95 109 +3 84 109 115 +3 84 112 105 +3 84 109 112 +3 105 112 109 +3 84 105 109 +3 105 109 115 +3 84 105 115 +3 88 92 105 +3 84 105 92 +3 84 105 89 +3 89 105 115 +3 84 89 115 +3 89 90 105 +3 89 115 95 +3 84 112 92 +3 92 112 105 +3 85 96 93 +3 88 93 96 +3 85 88 96 +3 91 99 96 +3 85 91 96 +3 85 99 91 +3 85 96 99 +3 85 99 88 +3 85 92 99 +3 88 99 92 +3 88 96 99 +3 86 98 103 +3 94 103 98 +3 86 94 98 +3 94 98 95 +3 93 106 113 +3 88 93 113 +3 88 106 93 +3 88 113 106 +3 88 99 93 +3 93 99 106 +3 88 106 99 +3 99 110 105 +3 88 105 110 +3 88 99 105 +3 88 110 99 +3 88 110 92 +3 92 110 99 +3 88 104 105 +3 88 113 104 +3 104 113 105 +3 88 105 113 +3 101 113 104 +3 88 113 101 +3 93 96 99 +3 88 113 99 +3 99 113 106 +3 93 113 101 +3 99 105 113 +3 90 104 105 +3 92 105 110 +3 89 107 105 +3 89 90 107 +3 90 105 107 +3 95 98 115 +3 89 115 98 +3 105 115 107 +3 89 107 115 +3 89 118 115 +3 89 107 118 +3 107 115 118 +3 89 118 98 +3 98 118 115 +3 90 116 105 +3 104 105 116 +3 90 104 116 +3 105 107 116 +3 90 116 107 +3 91 99 102 +3 91 102 96 +3 96 102 99 +3 105 110 112 +3 92 112 110 +3 93 96 106 +3 96 99 106 +3 94 98 114 +3 94 114 95 +3 95 114 98 +3 94 95 122 +3 94 122 100 +3 95 100 122 +3 98 114 103 +3 94 103 114 +3 95 122 114 +3 94 114 122 +3 95 139 115 +3 95 119 139 +3 115 139 119 +3 95 115 119 +3 95 139 109 +3 109 139 115 +3 95 114 115 +3 98 115 114 +3 95 119 122 +3 100 122 119 +3 95 100 119 +3 95 122 115 +3 114 115 122 +3 115 119 122 +3 99 106 102 +3 96 102 106 +3 97 108 104 +3 97 101 108 +3 101 104 108 +3 98 118 117 +3 115 117 118 +3 98 117 115 +3 98 117 114 +3 114 117 115 +3 103 117 114 +3 98 117 103 +3 99 113 110 +3 106 110 113 +3 99 110 106 +3 99 111 106 +3 99 110 111 +3 106 111 110 +3 105 113 110 +3 99 111 102 +3 102 111 106 +3 100 137 119 +3 100 122 137 +3 119 137 122 +3 101 113 108 +3 101 127 113 +3 108 113 127 +3 101 108 127 +3 101 104 127 +3 104 108 127 +3 104 127 113 +3 116 127 144 +3 104 127 116 +3 104 144 127 +3 104 116 144 +3 104 144 113 +3 113 144 127 +3 104 105 144 +3 105 116 144 +3 105 144 113 +3 105 148 162 +3 105 162 116 +3 105 116 148 +3 116 162 148 +3 105 113 145 +3 105 145 110 +3 110 145 113 +3 107 162 174 +3 105 174 162 +3 105 107 174 +3 105 162 107 +3 105 112 140 +3 109 140 112 +3 105 140 109 +3 105 140 115 +3 109 115 140 +3 105 175 115 +3 105 140 175 +3 115 175 140 +3 105 107 148 +3 107 116 148 +3 115 174 162 +3 105 115 162 +3 105 174 115 +3 107 148 162 +3 105 163 162 +3 105 175 163 +3 162 163 175 +3 105 162 175 +3 115 162 175 +3 105 140 163 +3 140 175 163 +3 116 144 162 +3 105 162 144 +3 112 163 145 +3 105 145 163 +3 105 112 145 +3 105 163 112 +3 105 145 144 +3 105 162 145 +3 144 145 162 +3 110 112 145 +3 107 174 115 +3 145 163 162 +3 112 140 163 +3 113 145 144 +3 110 120 111 +3 106 120 110 +3 106 111 120 +3 106 120 113 +3 110 113 120 +3 146 148 162 +3 107 146 162 +3 107 148 146 +3 107 174 146 +3 107 146 115 +3 115 146 174 +3 146 162 174 +3 107 146 118 +3 115 118 146 +3 115 156 139 +3 109 139 156 +3 109 156 115 +3 115 140 156 +3 109 156 140 +3 110 112 155 +3 112 145 155 +3 110 155 145 +3 110 145 120 +3 113 120 145 +3 110 131 145 +3 110 155 131 +3 131 155 145 +3 110 131 111 +3 110 120 131 +3 111 131 120 +3 120 131 145 +3 131 147 155 +3 110 155 147 +3 110 147 131 +3 112 155 147 +3 110 112 147 +3 145 155 163 +3 112 163 155 +3 147 163 155 +3 112 163 147 +3 112 140 147 +3 140 163 147 +3 114 167 117 +3 114 153 167 +3 117 167 153 +3 114 117 153 +3 114 167 122 +3 114 122 169 +3 114 169 167 +3 122 167 169 +3 114 169 117 +3 117 169 167 +3 114 115 169 +3 115 122 169 +3 115 169 117 +3 119 189 139 +3 115 189 119 +3 115 139 189 +3 115 139 194 +3 139 189 194 +3 115 194 189 +3 140 156 175 +3 115 175 156 +3 117 118 169 +3 115 169 118 +3 115 179 194 +3 139 194 179 +3 115 139 179 +3 115 122 192 +3 122 169 192 +3 115 192 169 +3 115 192 175 +3 174 175 192 +3 115 175 174 +3 115 174 192 +3 115 192 118 +3 118 192 169 +3 162 175 174 +3 139 179 156 +3 115 156 179 +3 115 175 194 +3 175 179 194 +3 115 179 175 +3 115 118 174 +3 118 146 174 +3 118 174 192 +3 115 192 194 +3 175 194 192 +3 115 189 122 +3 119 122 189 +3 115 122 194 +3 122 192 194 +3 156 179 175 +3 122 194 189 +3 116 144 152 +3 116 152 162 +3 144 162 152 +3 148 152 162 +3 116 152 148 +3 127 144 152 +3 116 127 152 +3 117 169 153 +3 153 169 167 +3 146 174 183 +3 118 183 174 +3 118 146 183 +3 118 183 192 +3 174 192 183 +3 169 183 192 +3 118 183 169 +3 122 189 185 +3 119 122 185 +3 119 185 189 +3 122 185 137 +3 119 137 185 +3 121 150 125 +3 121 125 126 +3 121 126 150 +3 125 150 126 +3 121 126 135 +3 121 135 150 +3 126 150 135 +3 122 166 169 +3 122 167 166 +3 166 167 169 +3 166 189 185 +3 122 166 185 +3 122 189 166 +3 166 169 192 +3 122 166 192 +3 166 194 189 +3 122 194 166 +3 166 192 194 +3 122 166 137 +3 137 166 185 +3 123 126 177 +3 123 176 126 +3 126 176 177 +3 123 177 176 +3 123 150 138 +3 123 132 150 +3 132 138 150 +3 123 138 132 +3 125 150 138 +3 123 150 125 +3 123 125 138 +3 123 124 128 +3 124 197 128 +3 123 128 197 +3 123 197 124 +3 123 177 150 +3 132 150 177 +3 123 132 177 +3 126 197 176 +3 123 197 126 +3 123 176 197 +3 126 128 197 +3 123 128 126 +3 123 177 197 +3 176 197 177 +3 124 132 197 +3 123 132 124 +3 123 197 132 +3 123 126 125 +3 123 150 126 +3 123 125 132 +3 125 138 132 +3 126 177 150 +3 132 177 197 +3 133 157 180 +3 124 157 133 +3 124 180 157 +3 124 133 180 +3 124 157 130 +3 130 157 133 +3 124 130 133 +3 124 161 136 +3 124 129 161 +3 129 136 161 +3 124 136 129 +3 124 180 161 +3 124 129 180 +3 129 161 180 +3 129 180 130 +3 124 130 180 +3 124 129 130 +3 130 180 157 +3 134 180 161 +3 124 180 134 +3 124 134 161 +3 134 197 180 +3 124 197 134 +3 124 180 197 +3 128 133 197 +3 124 133 128 +3 124 197 133 +3 134 161 136 +3 124 134 136 +3 132 197 134 +3 124 132 134 +3 133 180 197 +3 128 197 176 +3 126 128 176 +3 126 176 150 +3 150 176 177 +3 126 135 176 +3 126 176 142 +3 126 142 135 +3 135 142 176 +3 135 176 150 +3 126 128 142 +3 128 176 142 +3 126 142 143 +3 135 143 142 +3 126 143 135 +3 133 197 151 +3 128 133 151 +3 128 151 197 +3 128 142 197 +3 128 159 142 +3 142 159 197 +3 128 197 159 +3 142 197 176 +3 128 151 159 +3 151 197 159 +3 130 157 141 +3 130 141 133 +3 133 141 157 +3 138 150 177 +3 132 138 177 +3 134 149 219 +3 132 149 134 +3 132 219 149 +3 132 134 219 +3 132 164 149 +3 149 164 219 +3 132 219 164 +3 132 197 164 +3 164 197 219 +3 132 219 197 +3 134 219 197 +3 132 177 164 +3 164 177 197 +3 132 164 138 +3 138 164 149 +3 132 138 149 +3 138 177 164 +3 133 141 151 +3 141 157 151 +3 133 151 157 +3 133 157 197 +3 157 180 197 +3 151 157 197 +3 134 197 161 +3 161 197 180 +3 136 158 161 +3 134 161 158 +3 134 158 136 +3 149 219 182 +3 134 149 182 +3 134 182 219 +3 134 197 158 +3 158 197 161 +3 134 149 158 +3 134 158 182 +3 149 182 158 +3 134 158 219 +3 158 182 219 +3 158 219 197 +3 142 176 143 +3 135 143 176 +3 136 171 161 +3 158 161 171 +3 136 158 171 +3 166 185 168 +3 137 168 185 +3 137 166 168 +3 139 184 194 +3 139 189 184 +3 184 189 194 +3 139 179 184 +3 156 184 179 +3 139 184 156 +3 179 184 194 +3 156 175 173 +3 140 173 175 +3 140 156 173 +3 147 173 163 +3 140 173 147 +3 140 163 173 +3 140 156 165 +3 156 173 165 +3 140 165 173 +3 165 173 170 +3 140 165 170 +3 140 170 173 +3 163 173 175 +3 147 170 173 +3 140 170 147 +3 151 160 157 +3 141 160 151 +3 141 157 160 +3 154 159 176 +3 142 159 154 +3 142 176 159 +3 142 154 176 +3 142 154 143 +3 143 154 176 +3 159 197 176 +3 146 174 172 +3 172 174 183 +3 146 172 183 +3 146 162 172 +3 162 174 172 +3 146 148 172 +3 148 162 172 +3 163 170 173 +3 147 170 163 +3 149 182 164 +3 149 181 182 +3 164 182 181 +3 149 164 181 +3 164 219 182 +3 157 197 195 +3 151 157 195 +3 151 195 197 +3 151 160 195 +3 157 195 160 +3 190 195 197 +3 151 195 190 +3 151 190 197 +3 178 195 190 +3 151 178 190 +3 151 195 178 +3 151 190 159 +3 159 190 197 +3 151 160 178 +3 160 195 178 +3 167 188 169 +3 153 188 167 +3 153 169 188 +3 154 159 186 +3 154 186 191 +3 154 191 159 +3 159 191 186 +3 159 176 191 +3 154 191 176 +3 156 179 165 +3 165 179 173 +3 156 173 179 +3 173 179 175 +3 157 180 195 +3 180 197 195 +3 158 219 161 +3 161 219 197 +3 158 219 198 +3 158 205 219 +3 198 219 205 +3 158 198 205 +3 158 161 198 +3 161 171 198 +3 158 198 171 +3 158 161 205 +3 161 198 205 +3 158 193 171 +3 158 198 193 +3 171 193 198 +3 161 205 219 +3 158 182 187 +3 158 187 219 +3 182 219 187 +3 158 187 198 +3 187 219 198 +3 187 198 193 +3 158 187 193 +3 191 199 197 +3 159 191 197 +3 159 199 191 +3 159 197 199 +3 186 199 191 +3 159 199 186 +3 159 190 199 +3 190 197 199 +3 176 191 197 +3 160 200 178 +3 160 195 200 +3 178 200 195 +3 161 197 205 +3 161 205 180 +3 180 205 197 +3 197 205 219 +3 164 202 181 +3 164 182 202 +3 181 202 182 +3 164 202 219 +3 164 197 202 +3 197 219 202 +3 164 177 202 +3 177 197 202 +3 182 202 219 +3 185 196 207 +3 166 196 185 +3 166 207 196 +3 166 185 207 +3 166 185 214 +3 185 207 214 +3 166 214 207 +3 166 196 168 +3 168 196 185 +3 189 214 194 +3 166 214 189 +3 166 194 214 +3 185 214 189 +3 166 167 192 +3 167 169 192 +3 166 167 207 +3 166 214 167 +3 167 214 207 +3 167 192 214 +3 166 214 192 +3 192 194 214 +3 167 201 207 +3 167 214 201 +3 201 214 207 +3 167 188 201 +3 188 217 201 +3 167 201 217 +3 167 217 188 +3 201 217 214 +3 167 214 217 +3 167 169 214 +3 169 192 214 +3 167 188 214 +3 169 214 188 +3 188 214 217 +3 169 215 192 +3 183 192 215 +3 169 183 215 +3 169 217 188 +3 169 214 217 +3 169 215 217 +3 169 214 215 +3 214 217 215 +3 192 214 215 +3 176 212 197 +3 176 191 212 +3 191 197 212 +3 176 212 177 +3 177 212 197 +3 177 212 202 +3 197 202 212 +3 178 200 190 +3 190 200 195 +3 180 234 197 +3 197 234 205 +3 180 205 234 +3 180 234 195 +3 195 234 197 +3 181 221 182 +3 182 221 202 +3 181 202 221 +3 181 221 208 +3 181 208 182 +3 182 208 221 +3 187 210 219 +3 182 210 187 +3 182 219 210 +3 208 221 210 +3 182 210 221 +3 182 208 210 +3 202 219 221 +3 182 221 219 +3 210 221 219 +3 189 194 206 +3 184 206 194 +3 184 189 206 +3 207 214 223 +3 185 223 214 +3 185 207 223 +3 196 223 218 +3 185 196 218 +3 185 223 196 +3 185 218 223 +3 196 207 223 +3 189 223 214 +3 185 223 189 +3 191 213 199 +3 186 213 191 +3 186 199 213 +3 199 213 225 +3 186 225 213 +3 186 199 225 +3 193 209 198 +3 187 209 193 +3 187 198 209 +3 209 210 219 +3 187 209 219 +3 187 210 209 +3 198 209 219 +3 201 216 217 +3 188 216 201 +3 188 217 216 +3 188 203 201 +3 188 216 203 +3 201 203 216 +3 206 223 230 +3 189 230 223 +3 189 206 230 +3 189 223 206 +3 214 230 223 +3 189 230 214 +3 206 230 214 +3 189 206 214 +3 194 206 214 +3 190 195 229 +3 195 197 229 +3 190 229 197 +3 190 200 229 +3 195 229 200 +3 190 200 227 +3 190 227 229 +3 200 229 227 +3 190 229 199 +3 197 199 229 +3 190 227 199 +3 199 227 229 +3 197 233 199 +3 191 199 233 +3 191 233 197 +3 213 225 233 +3 191 225 213 +3 191 233 225 +3 191 213 233 +3 191 233 212 +3 197 212 233 +3 191 225 199 +3 199 233 225 +3 193 211 204 +3 198 204 211 +3 193 204 198 +3 193 198 211 +3 198 211 209 +3 193 209 211 +3 195 234 229 +3 197 229 234 +3 207 223 218 +3 196 207 218 +3 207 218 235 +3 196 235 218 +3 196 207 235 +3 197 259 233 +3 212 233 259 +3 197 212 259 +3 197 246 234 +3 197 229 246 +3 229 234 246 +3 197 225 199 +3 197 233 225 +3 197 219 212 +3 202 212 219 +3 246 274 259 +3 197 246 259 +3 197 274 246 +3 197 259 274 +3 197 233 246 +3 225 246 233 +3 197 246 225 +3 197 234 259 +3 197 259 219 +3 197 219 234 +3 219 259 234 +3 212 259 241 +3 197 212 241 +3 197 241 259 +3 197 234 274 +3 234 259 274 +3 205 219 234 +3 197 199 246 +3 199 229 246 +3 197 241 219 +3 219 241 259 +3 199 246 225 +3 234 274 246 +3 233 246 259 +3 212 241 219 +3 219 220 228 +3 198 228 220 +3 198 219 228 +3 198 220 219 +3 198 211 228 +3 198 228 209 +3 209 228 211 +3 198 220 236 +3 219 236 220 +3 198 236 219 +3 198 236 205 +3 205 236 219 +3 209 219 228 +3 198 211 220 +3 211 228 220 +3 204 211 220 +3 198 204 220 +3 199 227 246 +3 227 229 246 +3 201 217 251 +3 201 251 214 +3 214 251 217 +3 201 251 231 +3 207 231 251 +3 201 231 207 +3 201 207 251 +3 216 231 232 +3 201 232 231 +3 201 216 232 +3 201 231 216 +3 207 251 214 +3 201 216 251 +3 216 217 251 +3 201 203 231 +3 203 232 231 +3 201 232 203 +3 203 216 232 +3 216 251 231 +3 202 212 241 +3 202 241 219 +3 202 241 221 +3 219 221 241 +3 204 211 226 +3 204 226 220 +3 211 220 226 +3 205 256 234 +3 205 219 256 +3 219 234 256 +3 219 256 236 +3 205 236 256 +3 207 248 235 +3 207 218 248 +3 218 235 248 +3 207 251 248 +3 207 248 214 +3 214 248 251 +3 214 223 248 +3 207 248 223 +3 207 251 235 +3 235 251 248 +3 231 251 245 +3 207 245 251 +3 207 231 245 +3 207 245 235 +3 235 245 251 +3 218 248 223 +3 208 222 210 +3 210 222 221 +3 208 221 222 +3 208 224 222 +3 208 221 224 +3 221 222 224 +3 209 239 219 +3 209 210 239 +3 210 219 239 +3 219 228 239 +3 209 239 228 +3 210 219 238 +3 210 238 239 +3 219 239 238 +3 210 221 238 +3 219 238 221 +3 221 238 222 +3 210 222 238 +3 220 226 228 +3 211 228 226 +3 225 233 250 +3 213 225 250 +3 213 250 233 +3 215 251 217 +3 214 251 215 +3 214 230 248 +3 223 248 230 +3 215 251 258 +3 217 258 251 +3 215 258 217 +3 216 253 258 +3 216 258 217 +3 216 217 253 +3 217 258 253 +3 216 253 251 +3 216 251 258 +3 251 253 258 +3 216 253 232 +3 231 232 253 +3 216 231 253 +3 231 253 251 +3 218 255 248 +3 235 248 255 +3 218 235 255 +3 223 255 248 +3 218 255 223 +3 235 255 252 +3 218 252 255 +3 218 235 252 +3 219 242 228 +3 228 242 236 +3 219 228 236 +3 219 236 242 +3 238 260 239 +3 219 260 238 +3 219 239 260 +3 234 256 289 +3 219 234 289 +3 219 289 256 +3 260 277 270 +3 219 270 277 +3 219 260 270 +3 219 277 260 +3 221 244 238 +3 219 238 244 +3 219 244 221 +3 219 241 277 +3 219 277 259 +3 241 259 277 +3 219 244 260 +3 219 241 244 +3 241 260 244 +3 219 260 241 +3 238 244 260 +3 221 241 244 +3 234 289 259 +3 219 259 289 +3 219 239 270 +3 239 260 270 +3 219 270 242 +3 219 242 263 +3 219 263 270 +3 242 270 263 +3 236 263 256 +3 219 263 236 +3 219 256 263 +3 241 277 260 +3 220 228 236 +3 239 270 242 +3 219 239 242 +3 228 239 242 +3 219 256 270 +3 256 263 270 +3 236 242 263 +3 259 289 277 +3 219 277 289 +3 270 277 289 +3 219 270 289 +3 256 270 289 +3 220 226 237 +3 226 228 237 +3 220 237 228 +3 228 242 237 +3 220 237 242 +3 220 242 228 +3 220 242 236 +3 236 237 242 +3 220 237 236 +3 222 224 238 +3 221 238 224 +3 221 244 224 +3 224 244 238 +3 222 240 238 +3 224 238 240 +3 222 224 240 +3 223 255 243 +3 243 255 248 +3 223 243 248 +3 230 243 248 +3 223 243 230 +3 238 240 244 +3 224 244 240 +3 233 250 246 +3 225 246 250 +3 227 257 246 +3 227 229 257 +3 229 246 257 +3 246 257 274 +3 229 246 274 +3 229 274 257 +3 229 234 274 +3 232 253 249 +3 231 232 249 +3 231 249 253 +3 231 245 253 +3 231 249 245 +3 245 249 253 +3 245 253 251 +3 246 265 250 +3 233 250 265 +3 233 265 246 +3 233 265 259 +3 246 259 265 +3 256 289 281 +3 234 281 289 +3 234 256 281 +3 259 298 289 +3 234 289 298 +3 234 298 259 +3 259 274 298 +3 234 298 274 +3 274 281 298 +3 234 298 281 +3 234 281 274 +3 281 289 298 +3 235 245 248 +3 245 251 248 +3 235 280 248 +3 235 245 280 +3 245 248 280 +3 235 280 252 +3 235 255 280 +3 252 280 255 +3 248 255 280 +3 235 267 252 +3 235 280 267 +3 252 267 280 +3 252 266 267 +3 235 267 266 +3 235 266 252 +3 235 245 267 +3 245 280 267 +3 236 247 242 +3 236 237 247 +3 237 242 247 +3 256 261 263 +3 236 261 256 +3 236 263 261 +3 242 263 261 +3 236 242 261 +3 242 261 247 +3 236 247 261 +3 244 260 254 +3 238 244 254 +3 238 254 260 +3 238 240 254 +3 240 244 254 +3 241 277 244 +3 244 277 260 +3 241 271 277 +3 259 277 271 +3 241 259 271 +3 244 271 277 +3 241 271 244 +3 242 263 247 +3 247 263 261 +3 243 262 248 +3 243 255 262 +3 248 262 255 +3 254 277 260 +3 244 277 254 +3 244 271 264 +3 254 264 271 +3 244 264 254 +3 244 254 271 +3 254 271 277 +3 267 269 272 +3 245 267 272 +3 245 269 267 +3 245 272 269 +3 245 251 283 +3 245 280 251 +3 251 280 283 +3 245 283 280 +3 248 280 251 +3 245 253 283 +3 251 283 253 +3 245 267 283 +3 267 272 283 +3 245 283 272 +3 245 272 253 +3 249 253 272 +3 245 249 272 +3 249 272 269 +3 245 249 269 +3 267 283 280 +3 253 283 272 +3 246 275 274 +3 246 257 275 +3 257 274 275 +3 246 275 265 +3 246 298 275 +3 265 275 298 +3 246 265 298 +3 246 298 274 +3 274 298 275 +3 246 298 259 +3 259 265 298 +3 250 275 265 +3 246 275 250 +3 248 273 280 +3 255 280 273 +3 248 255 273 +3 255 273 262 +3 248 262 273 +3 250 275 268 +3 250 268 265 +3 265 268 275 +3 253 258 283 +3 251 283 258 +3 252 273 278 +3 252 255 273 +3 255 278 273 +3 252 278 255 +3 252 280 278 +3 273 278 280 +3 252 273 280 +3 266 267 276 +3 252 276 267 +3 252 266 276 +3 267 280 276 +3 252 276 280 +3 276 280 278 +3 252 276 278 +3 272 282 283 +3 253 282 272 +3 253 283 282 +3 253 258 282 +3 258 283 282 +3 254 264 260 +3 254 277 264 +3 260 264 277 +3 264 271 277 +3 255 278 262 +3 262 278 273 +3 270 289 279 +3 256 279 289 +3 256 270 279 +3 279 289 292 +3 256 292 289 +3 256 279 292 +3 279 292 281 +3 256 281 292 +3 256 279 281 +3 281 292 289 +3 263 270 279 +3 256 263 279 +3 261 263 279 +3 256 261 279 +3 257 274 294 +3 257 294 275 +3 274 275 294 +3 275 285 294 +3 257 285 275 +3 257 294 285 +3 259 290 295 +3 259 286 290 +3 286 295 290 +3 259 295 286 +3 265 295 284 +3 259 295 265 +3 259 284 295 +3 259 265 284 +3 289 295 298 +3 259 298 295 +3 259 295 289 +3 259 284 286 +3 284 295 286 +3 271 290 277 +3 259 277 290 +3 259 290 271 +3 259 290 289 +3 289 290 295 +3 277 290 289 +3 265 298 295 +3 271 286 290 +3 259 286 271 +3 265 305 284 +3 265 295 305 +3 284 305 295 +3 265 291 275 +3 268 275 291 +3 265 268 291 +3 265 305 298 +3 265 291 305 +3 291 298 305 +3 265 298 291 +3 265 275 317 +3 275 298 317 +3 265 317 298 +3 265 317 291 +3 291 317 298 +3 284 291 305 +3 265 291 284 +3 295 305 298 +3 275 317 291 +3 266 300 276 +3 266 267 300 +3 267 276 300 +3 276 297 300 +3 266 300 297 +3 266 297 276 +3 267 269 287 +3 269 283 287 +3 267 287 283 +3 267 283 269 +3 300 311 303 +3 267 303 311 +3 267 300 303 +3 267 311 300 +3 269 272 283 +3 267 310 287 +3 287 310 300 +3 267 287 300 +3 267 300 310 +3 267 303 276 +3 276 303 311 +3 267 276 311 +3 267 310 280 +3 280 310 283 +3 267 283 310 +3 276 311 280 +3 267 280 311 +3 283 310 287 +3 300 310 311 +3 267 311 310 +3 276 300 303 +3 280 311 310 +3 268 288 304 +3 288 301 304 +3 268 304 301 +3 268 301 288 +3 275 291 288 +3 268 275 288 +3 268 288 291 +3 288 291 301 +3 268 301 291 +3 272 283 287 +3 269 272 287 +3 272 306 293 +3 269 293 306 +3 269 272 293 +3 269 306 272 +3 287 293 306 +3 269 293 287 +3 269 287 306 +3 272 287 306 +3 272 306 283 +3 272 282 306 +3 282 283 306 +3 272 310 283 +3 272 306 310 +3 283 310 306 +3 272 287 310 +3 287 306 310 +3 274 299 298 +3 281 298 299 +3 274 281 299 +3 294 316 298 +3 274 294 298 +3 274 316 294 +3 274 298 316 +3 275 294 298 +3 274 298 308 +3 274 308 316 +3 298 316 308 +3 298 308 299 +3 274 299 308 +3 274 308 294 +3 294 308 316 +3 275 316 298 +3 275 294 316 +3 275 316 314 +3 275 317 316 +3 314 316 317 +3 275 314 317 +3 291 314 317 +3 275 314 291 +3 294 316 307 +3 275 294 307 +3 275 307 316 +3 285 294 307 +3 275 285 307 +3 275 307 314 +3 307 316 314 +3 298 317 316 +3 288 307 314 +3 275 307 288 +3 275 288 314 +3 288 314 291 +3 276 303 278 +3 278 303 311 +3 276 278 311 +3 297 300 303 +3 276 297 303 +3 278 311 280 +3 278 302 311 +3 278 303 302 +3 302 303 311 +3 281 292 299 +3 281 298 292 +3 292 298 299 +3 289 298 292 +3 283 306 313 +3 282 283 313 +3 282 313 306 +3 283 310 313 +3 306 313 310 +3 285 294 319 +3 285 319 307 +3 294 307 319 +3 285 319 296 +3 285 296 307 +3 296 319 307 +3 287 293 325 +3 293 306 325 +3 287 325 306 +3 287 331 310 +3 287 306 331 +3 306 310 331 +3 287 325 309 +3 309 325 321 +3 287 309 321 +3 287 321 325 +3 287 325 331 +3 306 331 325 +3 321 325 331 +3 287 321 331 +3 300 321 331 +3 287 321 300 +3 287 300 331 +3 287 293 309 +3 293 325 309 +3 300 331 310 +3 307 314 324 +3 288 307 324 +3 288 324 314 +3 288 324 304 +3 304 324 314 +3 288 304 314 +3 288 314 301 +3 291 301 314 +3 301 304 314 +3 291 318 322 +3 291 315 318 +3 315 322 318 +3 291 322 315 +3 291 318 317 +3 314 317 318 +3 291 314 318 +3 291 301 322 +3 291 318 301 +3 301 318 322 +3 301 314 318 +3 305 318 317 +3 291 318 305 +3 291 305 317 +3 305 315 318 +3 291 315 305 +3 298 305 317 +3 307 319 316 +3 294 316 319 +3 295 305 317 +3 295 317 298 +3 295 318 317 +3 295 305 318 +3 296 319 312 +3 307 312 319 +3 296 312 307 +3 297 300 320 +3 297 320 323 +3 297 323 300 +3 300 323 320 +3 300 303 323 +3 297 323 303 +3 300 321 339 +3 321 331 339 +3 300 339 331 +3 300 338 339 +3 300 332 338 +3 332 339 338 +3 300 339 332 +3 310 339 331 +3 300 339 310 +3 303 323 339 +3 300 339 323 +3 300 303 339 +3 303 339 311 +3 300 311 339 +3 300 338 323 +3 323 338 339 +3 300 321 332 +3 321 339 332 +3 320 332 338 +3 300 320 338 +3 300 332 320 +3 310 311 339 +3 320 338 323 +3 301 327 314 +3 301 304 327 +3 304 314 327 +3 314 322 327 +3 301 322 314 +3 301 327 322 +3 314 318 322 +3 302 303 326 +3 303 311 326 +3 302 326 311 +3 303 323 311 +3 311 323 339 +3 311 326 323 +3 303 323 326 +3 304 324 333 +3 304 333 314 +3 314 333 324 +3 304 333 327 +3 314 327 333 +3 304 328 333 +3 324 333 328 +3 304 324 328 +3 310 331 313 +3 306 313 331 +3 306 329 325 +3 325 329 331 +3 306 331 329 +3 306 313 329 +3 313 331 329 +3 307 314 334 +3 307 341 314 +3 314 341 334 +3 307 334 341 +3 307 342 319 +3 312 319 342 +3 307 312 342 +3 307 359 334 +3 334 359 342 +3 307 334 342 +3 307 342 359 +3 307 335 342 +3 312 342 335 +3 307 312 335 +3 307 335 359 +3 335 342 359 +3 307 319 334 +3 307 334 316 +3 316 334 319 +3 319 334 342 +3 324 359 341 +3 307 359 324 +3 307 341 359 +3 307 324 341 +3 314 334 316 +3 324 335 359 +3 307 335 324 +3 334 341 359 +3 314 324 341 +3 321 330 325 +3 309 330 321 +3 309 325 330 +3 323 339 326 +3 311 326 339 +3 314 336 327 +3 314 322 336 +3 322 327 336 +3 327 333 336 +3 314 336 333 +3 314 333 360 +3 314 360 324 +3 324 360 333 +3 316 317 334 +3 314 334 317 +3 324 341 360 +3 314 360 341 +3 314 341 318 +3 317 318 341 +3 314 317 341 +3 314 318 336 +3 318 322 336 +3 314 336 347 +3 333 347 336 +3 314 347 333 +3 314 347 360 +3 333 360 347 +3 318 336 341 +3 314 341 336 +3 317 341 334 +3 336 347 341 +3 314 341 347 +3 341 347 360 +3 319 346 342 +3 319 334 346 +3 334 342 346 +3 320 337 338 +3 320 332 337 +3 332 338 337 +3 321 348 365 +3 321 365 343 +3 321 343 348 +3 343 365 348 +3 321 340 366 +3 321 366 365 +3 321 365 340 +3 340 365 366 +3 325 343 330 +3 321 330 343 +3 321 343 325 +3 321 365 339 +3 321 331 365 +3 331 339 365 +3 321 366 339 +3 339 366 365 +3 321 331 343 +3 331 365 343 +3 325 331 343 +3 321 348 330 +3 321 330 351 +3 321 351 348 +3 330 348 351 +3 339 340 366 +3 321 340 339 +3 340 348 365 +3 321 348 340 +3 332 340 339 +3 321 340 332 +3 340 351 348 +3 321 351 340 +3 330 343 348 +3 326 353 339 +3 323 353 326 +3 323 339 353 +3 323 338 353 +3 338 339 353 +3 324 363 359 +3 335 359 363 +3 324 335 363 +3 324 360 328 +3 328 360 333 +3 324 345 328 +3 324 328 349 +3 324 349 345 +3 328 345 349 +3 324 345 363 +3 335 363 345 +3 324 335 345 +3 345 363 360 +3 324 360 363 +3 324 345 360 +3 359 360 363 +3 324 360 359 +3 324 349 360 +3 345 360 349 +3 328 349 360 +3 341 360 359 +3 325 329 343 +3 329 331 343 +3 325 343 348 +3 325 348 330 +3 327 333 347 +3 327 347 336 +3 328 349 333 +3 333 349 360 +3 328 356 349 +3 328 345 356 +3 345 349 356 +3 329 331 354 +3 331 343 354 +3 329 354 343 +3 330 348 350 +3 330 350 351 +3 348 351 350 +3 331 365 354 +3 343 354 365 +3 332 362 344 +3 332 355 362 +3 344 362 355 +3 332 344 355 +3 332 366 339 +3 332 340 366 +3 332 337 355 +3 337 344 355 +3 332 344 337 +3 332 366 367 +3 338 367 366 +3 332 367 338 +3 332 338 366 +3 332 386 366 +3 340 366 386 +3 332 340 386 +3 332 338 355 +3 337 355 338 +3 340 386 362 +3 332 340 362 +3 332 362 386 +3 366 367 386 +3 332 386 367 +3 338 366 339 +3 355 386 367 +3 332 386 355 +3 332 355 367 +3 355 362 386 +3 338 355 367 +3 347 357 360 +3 333 357 347 +3 333 360 357 +3 333 349 357 +3 349 360 357 +3 334 359 346 +3 342 346 359 +3 335 363 361 +3 335 361 345 +3 345 361 363 +3 335 358 342 +3 335 364 358 +3 342 358 364 +3 335 342 364 +3 335 352 364 +3 342 364 352 +3 335 342 352 +3 335 363 352 +3 352 363 361 +3 335 352 361 +3 342 359 363 +3 335 342 363 +3 335 358 363 +3 342 363 358 +3 352 364 363 +3 335 363 364 +3 358 363 364 +3 339 353 366 +3 338 366 353 +3 338 367 353 +3 353 367 366 +3 365 366 386 +3 340 365 386 +3 351 386 375 +3 340 375 386 +3 340 351 375 +3 340 386 351 +3 351 365 386 +3 340 365 351 +3 348 365 351 +3 340 375 362 +3 362 375 386 +3 342 368 358 +3 358 368 363 +3 342 363 368 +3 342 368 359 +3 342 346 368 +3 346 359 368 +3 342 346 358 +3 346 368 358 +3 359 363 368 +3 354 365 369 +3 343 354 369 +3 343 369 365 +3 343 369 348 +3 348 369 365 +3 344 362 372 +3 344 372 355 +3 355 372 362 +3 344 376 372 +3 344 362 376 +3 362 372 376 +3 345 425 385 +3 345 361 425 +3 361 385 425 +3 345 385 361 +3 345 356 371 +3 345 374 356 +3 356 374 371 +3 345 371 374 +3 345 349 371 +3 349 356 371 +3 361 363 385 +3 345 385 363 +3 345 370 415 +3 361 415 370 +3 345 415 361 +3 345 361 370 +3 345 385 360 +3 360 385 363 +3 345 415 374 +3 345 371 415 +3 371 374 415 +3 345 415 385 +3 345 425 415 +3 385 415 425 +3 356 370 374 +3 345 370 356 +3 345 374 370 +3 361 425 415 +3 345 385 349 +3 349 385 360 +3 349 371 385 +3 345 385 371 +3 370 415 374 +3 371 415 385 +3 348 369 386 +3 348 386 365 +3 365 386 369 +3 348 378 351 +3 348 369 378 +3 351 378 369 +3 348 351 369 +3 348 386 351 +3 348 378 350 +3 350 378 351 +3 351 369 386 +3 349 371 391 +3 371 385 391 +3 349 391 385 +3 349 373 391 +3 371 391 373 +3 349 371 373 +3 349 360 373 +3 357 373 360 +3 349 373 357 +3 349 391 360 +3 360 391 385 +3 360 373 391 +3 350 380 351 +3 351 380 378 +3 350 378 380 +3 369 386 378 +3 351 378 386 +3 375 378 386 +3 351 378 375 +3 375 380 378 +3 351 380 375 +3 363 409 364 +3 352 364 409 +3 352 409 363 +3 379 399 409 +3 352 379 409 +3 352 399 379 +3 352 409 399 +3 352 409 361 +3 361 409 363 +3 364 409 399 +3 352 364 399 +3 361 379 409 +3 352 379 361 +3 353 392 366 +3 353 367 392 +3 366 392 367 +3 365 369 382 +3 354 382 369 +3 354 365 382 +3 355 386 372 +3 355 372 367 +3 367 372 386 +3 362 386 372 +3 356 370 377 +3 370 374 377 +3 356 377 374 +3 363 387 368 +3 358 387 363 +3 358 368 387 +3 363 364 387 +3 358 387 364 +3 364 394 387 +3 358 387 394 +3 358 394 364 +3 359 363 397 +3 363 368 397 +3 359 397 368 +3 359 363 385 +3 363 397 385 +3 359 385 397 +3 359 360 385 +3 361 423 409 +3 361 379 423 +3 379 409 423 +3 361 428 425 +3 423 425 428 +3 361 425 423 +3 361 423 428 +3 363 423 409 +3 361 423 363 +3 379 428 400 +3 361 379 400 +3 361 428 379 +3 361 400 428 +3 370 425 415 +3 361 425 370 +3 379 423 428 +3 361 425 363 +3 363 425 423 +3 361 400 370 +3 370 400 428 +3 361 370 428 +3 370 428 425 +3 363 385 425 +3 362 375 381 +3 362 376 375 +3 375 376 381 +3 362 381 376 +3 362 412 386 +3 362 375 412 +3 375 386 412 +3 362 412 372 +3 372 412 386 +3 375 412 376 +3 362 376 412 +3 372 376 412 +3 363 387 397 +3 368 397 387 +3 363 423 416 +3 363 416 409 +3 409 416 423 +3 363 394 397 +3 387 397 394 +3 363 387 394 +3 385 425 397 +3 363 397 425 +3 363 394 364 +3 364 394 409 +3 363 409 394 +3 397 425 423 +3 363 397 423 +3 363 397 416 +3 397 423 416 +3 394 397 416 +3 363 394 416 +3 394 416 409 +3 365 410 382 +3 369 382 410 +3 365 369 410 +3 369 410 386 +3 365 386 410 +3 366 386 410 +3 365 366 410 +3 367 386 392 +3 366 392 386 +3 366 392 421 +3 366 421 386 +3 386 421 392 +3 366 421 410 +3 386 410 421 +3 367 372 401 +3 372 386 401 +3 367 401 386 +3 367 401 392 +3 386 392 401 +3 369 410 418 +3 369 418 386 +3 386 418 410 +3 369 410 411 +3 369 411 418 +3 410 418 411 +3 382 410 411 +3 369 382 411 +3 369 418 378 +3 378 418 386 +3 374 377 414 +3 370 374 414 +3 370 414 377 +3 370 414 417 +3 377 417 414 +3 370 417 377 +3 370 415 414 +3 374 414 415 +3 400 414 417 +3 370 414 400 +3 370 400 417 +3 414 428 425 +3 370 414 425 +3 370 428 414 +3 400 428 414 +3 414 425 415 +3 385 391 415 +3 371 415 391 +3 374 415 407 +3 371 407 415 +3 371 374 407 +3 371 407 391 +3 391 407 415 +3 386 401 412 +3 372 412 401 +3 374 414 407 +3 407 414 415 +3 375 380 441 +3 375 386 380 +3 380 386 441 +3 375 441 386 +3 375 424 376 +3 376 424 412 +3 375 412 424 +3 375 381 424 +3 375 424 441 +3 375 441 381 +3 381 441 424 +3 375 441 383 +3 375 383 381 +3 381 383 441 +3 386 412 441 +3 375 441 412 +3 375 380 383 +3 380 441 383 +3 378 386 380 +3 376 381 424 +3 412 424 441 +3 376 405 424 +3 381 424 405 +3 376 381 405 +3 378 380 430 +3 378 430 402 +3 378 402 380 +3 380 402 430 +3 378 418 430 +3 378 380 418 +3 380 430 418 +3 380 418 386 +3 379 413 428 +3 379 433 413 +3 413 433 428 +3 379 428 433 +3 400 404 428 +3 379 404 400 +3 379 428 404 +3 404 413 428 +3 379 413 404 +3 409 423 428 +3 379 409 428 +3 379 399 428 +3 399 409 428 +3 399 433 413 +3 379 433 399 +3 379 399 413 +3 399 428 433 +3 380 418 441 +3 386 441 418 +3 383 430 441 +3 380 441 430 +3 380 430 383 +3 384 420 430 +3 380 384 430 +3 380 420 384 +3 380 430 420 +3 380 402 384 +3 384 402 420 +3 380 420 402 +3 418 441 430 +3 402 430 420 +3 380 384 383 +3 383 384 430 +3 424 445 441 +3 381 441 445 +3 381 445 424 +3 383 441 445 +3 381 383 445 +3 381 405 383 +3 381 383 398 +3 381 398 405 +3 383 405 398 +3 381 405 445 +3 383 445 405 +3 405 445 424 +3 383 442 384 +3 384 442 393 +3 383 384 393 +3 383 393 442 +3 383 429 405 +3 405 429 445 +3 383 445 429 +3 383 442 429 +3 383 445 442 +3 429 442 445 +3 383 442 420 +3 383 420 384 +3 384 420 442 +3 388 429 398 +3 383 429 388 +3 383 398 429 +3 383 388 398 +3 383 441 442 +3 441 445 442 +3 383 442 388 +3 388 442 429 +3 388 393 442 +3 383 393 388 +3 383 441 420 +3 420 441 442 +3 420 430 441 +3 383 430 420 +3 398 429 405 +3 390 420 393 +3 384 393 420 +3 384 390 393 +3 384 420 390 +3 393 420 442 +3 386 435 418 +3 418 435 441 +3 386 441 435 +3 386 438 410 +3 386 410 435 +3 386 435 438 +3 410 438 435 +3 412 441 421 +3 386 421 441 +3 386 412 421 +3 386 421 401 +3 392 401 421 +3 435 438 441 +3 386 441 438 +3 386 438 421 +3 410 421 438 +3 410 435 418 +3 401 412 421 +3 421 441 438 +3 387 416 394 +3 387 397 416 +3 388 396 442 +3 393 442 396 +3 388 393 396 +3 388 429 389 +3 389 429 398 +3 388 389 398 +3 396 442 422 +3 388 396 422 +3 388 422 442 +3 388 396 389 +3 389 396 422 +3 388 389 422 +3 422 442 429 +3 388 422 429 +3 389 422 429 +3 389 396 395 +3 395 396 422 +3 389 395 422 +3 420 442 439 +3 390 442 420 +3 390 439 442 +3 390 420 439 +3 390 406 393 +3 390 439 406 +3 393 406 439 +3 390 393 439 +3 390 442 393 +3 393 439 442 +3 401 421 419 +3 392 401 419 +3 392 419 421 +3 393 404 442 +3 393 403 404 +3 403 442 404 +3 393 442 403 +3 403 406 439 +3 393 403 439 +3 393 406 403 +3 396 404 442 +3 393 404 396 +3 403 439 442 +3 396 422 408 +3 395 408 422 +3 395 396 408 +3 396 434 422 +3 396 442 434 +3 422 434 442 +3 396 422 404 +3 404 422 408 +3 396 404 408 +3 396 404 434 +3 404 442 434 +3 404 434 422 +3 428 433 432 +3 399 432 433 +3 399 428 432 +3 409 428 432 +3 399 409 432 +3 403 404 428 +3 400 403 428 +3 400 404 403 +3 414 417 428 +3 400 428 417 +3 403 428 417 +3 400 403 417 +3 412 421 419 +3 401 412 419 +3 406 439 417 +3 403 406 417 +3 403 417 439 +3 428 447 460 +3 403 447 428 +3 403 460 447 +3 403 428 460 +3 404 428 460 +3 403 404 460 +3 417 447 428 +3 403 447 417 +3 417 439 447 +3 403 447 439 +3 403 442 460 +3 404 460 442 +3 439 460 447 +3 403 460 439 +3 439 442 460 +3 404 428 434 +3 428 460 434 +3 404 434 460 +3 404 434 408 +3 408 434 422 +3 428 434 433 +3 404 428 433 +3 404 433 434 +3 434 460 442 +3 404 413 433 +3 413 433 434 +3 404 413 434 +3 404 413 408 +3 408 413 434 +3 407 426 415 +3 407 414 426 +3 414 415 426 +3 423 428 432 +3 409 423 432 +3 416 423 431 +3 409 431 423 +3 409 416 431 +3 423 432 431 +3 409 431 432 +3 410 427 411 +3 411 427 418 +3 410 418 427 +3 418 427 435 +3 410 435 427 +3 412 437 421 +3 421 437 441 +3 412 441 437 +3 412 424 437 +3 424 441 437 +3 419 437 421 +3 412 437 419 +3 414 428 443 +3 414 443 440 +3 414 440 428 +3 428 440 443 +3 414 447 428 +3 414 417 447 +3 414 443 426 +3 425 426 443 +3 414 426 425 +3 414 425 443 +3 414 440 425 +3 425 440 428 +3 415 426 425 +3 428 443 447 +3 414 447 443 +3 425 443 440 +3 415 426 443 +3 415 443 425 +3 418 435 448 +3 418 448 441 +3 435 441 448 +3 418 427 448 +3 427 435 448 +3 418 448 430 +3 430 448 441 +3 419 437 436 +3 419 436 421 +3 421 436 437 +3 420 452 441 +3 430 441 452 +3 420 430 452 +3 420 442 452 +3 420 452 439 +3 439 452 442 +3 441 442 452 +3 437 441 438 +3 421 437 438 +3 421 436 438 +3 436 437 438 +3 436 438 450 +3 421 450 438 +3 421 436 450 +3 429 459 442 +3 422 459 429 +3 422 442 459 +3 422 434 459 +3 434 442 459 +3 428 446 440 +3 423 446 428 +3 423 440 446 +3 423 428 440 +3 423 431 428 +3 428 431 446 +3 423 446 431 +3 428 432 431 +3 423 425 440 +3 437 445 441 +3 424 445 437 +3 427 435 444 +3 435 448 444 +3 427 444 448 +3 428 440 447 +3 440 443 447 +3 428 446 460 +3 440 460 446 +3 428 460 440 +3 428 433 454 +3 433 446 454 +3 428 454 446 +3 428 446 433 +3 428 454 460 +3 446 460 454 +3 440 447 460 +3 428 432 446 +3 431 446 432 +3 433 460 434 +3 428 460 433 +3 432 446 433 +3 433 454 460 +3 442 445 467 +3 429 467 445 +3 429 442 467 +3 442 467 459 +3 429 459 467 +3 430 441 473 +3 430 473 452 +3 441 452 473 +3 430 448 473 +3 441 473 448 +3 431 451 432 +3 431 446 451 +3 432 451 446 +3 432 454 433 +3 432 446 454 +3 432 451 454 +3 446 454 451 +3 433 460 463 +3 433 463 434 +3 434 463 460 +3 454 460 463 +3 433 454 463 +3 434 460 459 +3 442 459 460 +3 434 463 459 +3 459 463 460 +3 435 444 464 +3 435 464 453 +3 435 453 444 +3 444 453 464 +3 435 464 448 +3 435 441 464 +3 441 448 464 +3 435 438 458 +3 435 458 464 +3 435 464 438 +3 438 464 458 +3 435 458 453 +3 453 458 464 +3 438 441 464 +3 444 464 448 +3 437 438 457 +3 436 457 438 +3 436 437 457 +3 449 457 450 +3 436 449 450 +3 436 457 449 +3 436 450 457 +3 438 450 457 +3 437 457 441 +3 437 441 475 +3 437 475 457 +3 441 457 475 +3 441 475 445 +3 437 445 475 +3 438 457 441 +3 438 457 482 +3 441 482 457 +3 438 482 441 +3 450 457 482 +3 438 450 482 +3 458 482 464 +3 438 464 482 +3 438 482 458 +3 438 450 458 +3 450 482 458 +3 441 464 482 +3 439 468 470 +3 460 470 468 +3 439 470 460 +3 439 460 468 +3 442 460 468 +3 439 442 468 +3 439 470 447 +3 447 470 460 +3 442 468 452 +3 439 452 468 +3 440 460 456 +3 446 456 460 +3 440 456 446 +3 440 443 456 +3 443 460 456 +3 440 460 443 +3 443 447 460 +3 441 452 475 +3 452 473 475 +3 441 475 473 +3 457 471 482 +3 441 471 457 +3 441 482 471 +3 473 482 475 +3 441 475 482 +3 441 482 473 +3 445 467 475 +3 441 467 445 +3 441 475 467 +3 448 482 473 +3 441 482 448 +3 457 475 471 +3 441 471 475 +3 471 475 482 +3 441 452 467 +3 452 475 467 +3 441 452 445 +3 445 452 467 +3 448 464 482 +3 442 452 445 +3 459 460 468 +3 442 459 468 +3 467 468 483 +3 442 467 483 +3 442 468 467 +3 442 483 468 +3 442 483 452 +3 452 483 468 +3 452 467 483 +3 442 467 452 +3 459 468 467 +3 443 447 462 +3 443 462 460 +3 447 460 462 +3 456 462 460 +3 443 462 456 +3 446 461 451 +3 451 461 454 +3 446 454 461 +3 454 461 456 +3 446 454 456 +3 446 456 461 +3 454 456 460 +3 447 470 462 +3 460 462 470 +3 464 482 473 +3 448 464 473 +3 450 455 457 +3 449 455 450 +3 449 457 455 +3 450 471 482 +3 450 457 471 +3 450 466 457 +3 455 457 466 +3 450 455 466 +3 450 482 466 +3 450 466 458 +3 458 466 482 +3 457 471 466 +3 450 466 471 +3 466 471 482 +3 451 479 454 +3 454 479 461 +3 451 461 479 +3 467 483 475 +3 452 475 483 +3 473 475 483 +3 452 473 483 +3 453 458 472 +3 458 465 472 +3 453 472 465 +3 453 465 458 +3 458 464 465 +3 453 465 464 +3 454 456 479 +3 454 479 460 +3 456 460 479 +3 456 479 461 +3 454 479 463 +3 460 463 479 +3 455 457 471 +3 455 471 466 +3 466 480 471 +3 455 471 480 +3 455 480 466 +3 460 484 462 +3 456 462 484 +3 456 484 460 +3 456 479 469 +3 456 476 479 +3 469 479 476 +3 456 469 476 +3 462 484 469 +3 456 462 469 +3 456 469 484 +3 456 476 461 +3 461 476 479 +3 456 460 469 +3 460 479 469 +3 460 469 484 +3 466 482 472 +3 458 472 482 +3 458 466 472 +3 464 472 482 +3 458 472 464 +3 464 465 472 +3 459 496 467 +3 467 496 468 +3 459 468 496 +3 459 491 496 +3 459 468 491 +3 468 496 491 +3 459 460 491 +3 460 468 491 +3 459 463 491 +3 460 491 463 +3 479 502 491 +3 460 502 479 +3 460 491 502 +3 460 479 491 +3 460 468 516 +3 468 491 516 +3 460 516 491 +3 460 479 484 +3 469 484 479 +3 463 479 491 +3 460 567 470 +3 460 484 567 +3 470 567 484 +3 460 470 484 +3 470 516 567 +3 460 567 516 +3 460 516 470 +3 460 502 484 +3 479 484 502 +3 468 516 470 +3 462 470 484 +3 484 567 491 +3 460 484 491 +3 460 491 567 +3 491 567 516 +3 484 491 502 +3 461 476 474 +3 461 474 479 +3 474 476 479 +3 469 478 484 +3 462 478 469 +3 462 484 478 +3 465 472 482 +3 464 465 482 +3 465 482 481 +3 464 481 482 +3 464 465 481 +3 481 482 490 +3 464 481 490 +3 464 490 482 +3 473 490 482 +3 464 490 473 +3 472 482 481 +3 465 472 481 +3 465 472 477 +3 465 477 481 +3 472 481 477 +3 472 486 482 +3 466 482 486 +3 466 486 472 +3 480 482 486 +3 466 480 486 +3 466 482 480 +3 471 482 480 +3 467 483 496 +3 467 496 475 +3 475 496 483 +3 468 483 496 +3 468 496 516 +3 491 516 496 +3 468 483 516 +3 483 496 516 +3 476 559 484 +3 469 476 484 +3 469 559 476 +3 469 484 559 +3 469 559 492 +3 469 492 488 +3 469 488 559 +3 488 492 559 +3 476 488 559 +3 469 488 476 +3 478 484 492 +3 469 478 492 +3 469 492 484 +3 484 559 492 +3 478 492 489 +3 469 478 489 +3 469 489 492 +3 476 484 479 +3 488 489 492 +3 469 489 488 +3 484 516 567 +3 470 516 484 +3 471 475 494 +3 471 494 482 +3 475 482 494 +3 480 494 482 +3 471 494 480 +3 472 485 477 +3 477 485 481 +3 472 481 485 +3 472 482 485 +3 481 485 482 +3 472 486 485 +3 482 485 486 +3 473 482 544 +3 482 509 544 +3 473 544 509 +3 473 509 482 +3 473 509 475 +3 475 509 482 +3 482 544 490 +3 473 490 544 +3 475 483 509 +3 473 509 483 +3 474 487 479 +3 476 479 487 +3 474 476 487 +3 475 509 494 +3 482 494 509 +3 475 539 494 +3 475 509 539 +3 494 539 509 +3 475 496 509 +3 483 509 496 +3 475 496 539 +3 496 509 539 +3 476 488 487 +3 476 502 488 +3 487 488 502 +3 476 487 502 +3 488 559 502 +3 476 502 559 +3 476 502 479 +3 476 484 502 +3 479 487 502 +3 484 502 559 +3 482 549 494 +3 480 549 482 +3 480 494 549 +3 480 549 486 +3 482 486 549 +3 486 511 549 +3 480 511 486 +3 480 549 511 +3 481 485 555 +3 481 490 485 +3 485 490 555 +3 481 555 490 +3 485 555 523 +3 481 485 523 +3 481 523 555 +3 482 490 485 +3 494 509 544 +3 482 494 544 +3 494 544 549 +3 482 549 544 +3 482 555 490 +3 482 544 555 +3 490 555 544 +3 482 490 486 +3 485 486 490 +3 482 555 486 +3 486 555 490 +3 486 549 555 +3 482 555 549 +3 544 555 549 +3 496 575 509 +3 483 509 575 +3 483 575 496 +3 496 516 575 +3 483 575 516 +3 484 502 567 +3 502 559 567 +3 484 567 559 +3 484 533 559 +3 533 567 559 +3 484 567 533 +3 492 533 559 +3 484 533 492 +3 491 502 567 +3 516 567 533 +3 484 516 533 +3 485 555 522 +3 485 522 523 +3 522 555 523 +3 485 555 486 +3 485 486 522 +3 486 555 522 +3 486 537 522 +3 486 522 511 +3 486 511 537 +3 511 522 537 +3 511 549 522 +3 486 522 549 +3 522 549 555 +3 487 488 505 +3 488 553 505 +3 487 505 553 +3 487 553 488 +3 487 553 502 +3 488 502 553 +3 488 489 521 +3 489 492 521 +3 488 521 492 +3 488 521 559 +3 492 559 521 +3 521 559 546 +3 488 546 559 +3 488 521 546 +3 488 559 553 +3 502 553 559 +3 505 546 553 +3 488 546 505 +3 488 553 546 +3 546 559 553 +3 489 492 530 +3 489 530 521 +3 492 521 530 +3 491 565 596 +3 491 567 565 +3 565 567 596 +3 491 596 567 +3 491 567 496 +3 496 567 516 +3 502 567 565 +3 491 502 565 +3 491 596 496 +3 496 596 567 +3 492 559 561 +3 492 561 521 +3 521 561 559 +3 521 530 561 +3 492 561 530 +3 492 533 561 +3 533 559 561 +3 493 504 499 +3 499 504 560 +3 493 499 560 +3 493 560 504 +3 493 570 513 +3 493 513 515 +3 493 515 570 +3 513 570 515 +3 508 513 515 +3 493 508 515 +3 493 513 508 +3 499 570 593 +3 493 499 593 +3 493 570 499 +3 493 593 570 +3 493 513 593 +3 493 497 513 +3 497 593 513 +3 493 593 497 +3 493 515 520 +3 515 570 520 +3 493 520 570 +3 493 499 497 +3 497 499 593 +3 504 520 560 +3 493 560 520 +3 493 520 504 +3 513 593 570 +3 499 560 570 +3 493 570 560 +3 520 570 560 +3 493 520 503 +3 493 503 504 +3 503 520 504 +3 494 606 544 +3 494 539 606 +3 539 544 606 +3 494 544 539 +3 494 606 549 +3 544 549 606 +3 509 544 539 +3 495 507 545 +3 495 545 498 +3 495 498 507 +3 498 545 507 +3 495 529 593 +3 495 593 499 +3 495 499 529 +3 499 593 529 +3 497 507 545 +3 495 497 545 +3 495 507 497 +3 495 593 545 +3 495 497 593 +3 497 545 593 +3 495 514 498 +3 495 545 514 +3 498 514 545 +3 495 529 500 +3 500 529 514 +3 495 500 514 +3 495 514 529 +3 495 501 529 +3 495 499 501 +3 499 529 501 +3 514 529 545 +3 495 545 529 +3 500 501 529 +3 495 501 500 +3 529 593 545 +3 495 497 499 +3 497 498 507 +3 495 498 497 +3 496 575 596 +3 539 596 575 +3 496 596 539 +3 496 539 575 +3 496 567 575 +3 516 575 567 +3 567 575 596 +3 509 539 575 +3 497 507 593 +3 507 545 593 +3 513 519 593 +3 497 593 519 +3 497 519 513 +3 497 507 519 +3 507 593 519 +3 498 545 517 +3 498 517 507 +3 507 517 545 +3 498 514 517 +3 514 545 517 +3 501 609 584 +3 499 501 584 +3 499 609 501 +3 499 584 609 +3 499 584 593 +3 499 593 609 +3 584 609 593 +3 501 584 529 +3 499 529 584 +3 499 609 510 +3 501 510 609 +3 499 510 501 +3 499 560 593 +3 560 570 593 +3 499 560 609 +3 560 593 609 +3 529 584 593 +3 504 609 510 +3 499 504 510 +3 499 609 504 +3 504 560 609 +3 500 501 512 +3 500 512 529 +3 501 529 512 +3 501 609 547 +3 501 547 584 +3 547 609 584 +3 501 512 547 +3 501 506 512 +3 506 547 512 +3 501 547 506 +3 501 510 506 +3 506 510 547 +3 501 547 510 +3 501 547 529 +3 529 547 584 +3 510 609 547 +3 512 547 529 +3 502 553 565 +3 553 559 565 +3 502 565 559 +3 559 567 565 +3 504 526 560 +3 503 526 504 +3 503 560 526 +3 503 504 560 +3 503 520 560 +3 525 560 526 +3 503 525 526 +3 503 560 525 +3 503 524 526 +3 524 525 526 +3 503 525 524 +3 503 520 525 +3 520 560 525 +3 504 526 510 +3 504 609 526 +3 510 526 609 +3 526 560 609 +3 541 546 553 +3 505 546 541 +3 505 541 553 +3 506 527 547 +3 506 510 527 +3 510 547 527 +3 527 547 531 +3 506 527 531 +3 506 531 547 +3 512 531 547 +3 506 531 512 +3 507 518 554 +3 507 554 545 +3 507 545 518 +3 518 545 554 +3 507 517 518 +3 517 545 518 +3 507 593 518 +3 507 518 519 +3 518 593 519 +3 507 593 554 +3 518 554 593 +3 545 593 554 +3 508 570 574 +3 508 574 528 +3 508 528 570 +3 528 574 570 +3 508 513 570 +3 508 570 515 +3 513 570 574 +3 508 513 574 +3 508 513 528 +3 513 574 528 +3 509 539 629 +3 539 575 629 +3 509 629 575 +3 539 629 544 +3 509 544 629 +3 510 609 527 +3 527 609 547 +3 526 609 534 +3 510 534 609 +3 510 526 534 +3 510 534 527 +3 527 534 609 +3 511 537 600 +3 511 600 543 +3 511 543 537 +3 537 543 600 +3 511 537 549 +3 511 549 600 +3 537 600 549 +3 522 537 549 +3 513 532 528 +3 528 532 574 +3 513 574 532 +3 532 538 574 +3 513 574 538 +3 513 538 532 +3 513 519 538 +3 513 538 593 +3 519 593 538 +3 513 574 593 +3 538 593 574 +3 570 574 593 +3 567 604 640 +3 516 604 567 +3 516 640 604 +3 516 567 640 +3 516 604 533 +3 533 604 567 +3 516 575 640 +3 567 640 575 +3 517 545 554 +3 517 554 518 +3 518 554 536 +3 518 536 593 +3 536 554 593 +3 518 536 519 +3 519 536 593 +3 519 562 538 +3 519 593 562 +3 538 562 593 +3 519 536 562 +3 536 593 562 +3 521 561 572 +3 559 572 561 +3 521 572 559 +3 521 572 546 +3 546 572 559 +3 521 530 572 +3 530 561 572 +3 522 622 663 +3 622 659 663 +3 522 663 659 +3 522 659 622 +3 537 663 659 +3 522 537 659 +3 522 663 537 +3 522 566 523 +3 523 566 555 +3 522 555 566 +3 537 659 647 +3 522 647 659 +3 522 537 647 +3 522 542 647 +3 522 537 542 +3 537 647 542 +3 522 566 542 +3 523 542 566 +3 522 542 523 +3 522 549 663 +3 522 663 555 +3 549 555 663 +3 522 622 566 +3 555 566 622 +3 522 555 622 +3 555 622 663 +3 522 647 566 +3 566 647 659 +3 522 566 659 +3 542 647 566 +3 566 659 622 +3 537 549 663 +3 524 535 526 +3 524 576 535 +3 526 535 576 +3 524 526 576 +3 524 525 560 +3 524 560 526 +3 524 560 576 +3 526 576 560 +3 524 525 576 +3 525 560 576 +3 526 576 548 +3 526 548 550 +3 526 550 576 +3 548 576 550 +3 534 550 609 +3 526 550 534 +3 526 609 550 +3 526 609 576 +3 550 576 609 +3 535 576 548 +3 526 535 548 +3 560 609 576 +3 531 540 583 +3 527 540 531 +3 527 583 540 +3 527 531 583 +3 527 557 583 +3 527 534 557 +3 534 583 557 +3 527 583 534 +3 527 547 583 +3 531 583 547 +3 527 609 583 +3 547 583 609 +3 540 557 583 +3 527 557 540 +3 534 609 583 +3 532 574 552 +3 528 552 574 +3 528 532 552 +3 529 584 545 +3 545 584 593 +3 561 572 601 +3 530 601 572 +3 530 561 601 +3 532 538 564 +3 532 564 574 +3 538 574 564 +3 552 564 574 +3 532 564 552 +3 533 559 603 +3 533 603 561 +3 559 561 603 +3 533 604 603 +3 533 603 567 +3 567 603 604 +3 559 603 567 +3 534 550 595 +3 534 595 609 +3 550 609 595 +3 534 609 557 +3 557 609 583 +3 534 595 557 +3 557 595 609 +3 535 576 577 +3 535 577 548 +3 548 577 576 +3 536 569 614 +3 536 554 569 +3 554 614 569 +3 536 614 554 +3 536 554 562 +3 554 593 562 +3 536 614 562 +3 554 562 614 +3 562 569 614 +3 536 569 562 +3 647 663 659 +3 537 663 647 +3 558 605 563 +3 537 605 558 +3 537 563 605 +3 537 558 563 +3 537 651 556 +3 537 556 647 +3 537 647 651 +3 556 651 647 +3 537 649 605 +3 563 605 649 +3 537 563 649 +3 537 649 651 +3 647 651 649 +3 537 647 649 +3 537 558 543 +3 537 543 563 +3 543 558 563 +3 600 663 649 +3 537 649 663 +3 537 600 649 +3 537 663 600 +3 647 649 663 +3 543 605 558 +3 537 605 543 +3 549 663 600 +3 537 651 563 +3 537 563 556 +3 556 563 651 +3 543 600 605 +3 537 605 600 +3 600 649 605 +3 563 649 651 +3 542 556 647 +3 537 556 542 +3 538 615 593 +3 538 562 615 +3 562 593 615 +3 538 581 615 +3 538 562 581 +3 562 615 581 +3 564 581 615 +3 538 564 615 +3 538 581 564 +3 564 615 574 +3 538 574 615 +3 574 615 593 +3 539 596 653 +3 539 653 575 +3 575 653 596 +3 539 653 629 +3 575 629 653 +3 539 653 606 +3 539 606 629 +3 606 653 629 +3 544 606 629 +3 540 557 571 +3 557 583 571 +3 540 571 583 +3 541 546 568 +3 546 553 568 +3 541 568 553 +3 553 592 568 +3 541 568 592 +3 541 592 553 +3 542 647 611 +3 542 611 566 +3 566 611 647 +3 542 582 566 +3 566 582 611 +3 542 611 582 +3 551 556 582 +3 542 551 582 +3 542 556 551 +3 542 582 556 +3 542 647 582 +3 582 647 611 +3 556 647 582 +3 549 648 555 +3 544 648 549 +3 544 555 648 +3 606 629 648 +3 544 648 629 +3 544 606 648 +3 549 606 648 +3 545 618 593 +3 545 584 618 +3 584 593 618 +3 545 618 554 +3 554 618 593 +3 546 592 568 +3 546 553 592 +3 559 602 608 +3 546 608 602 +3 546 559 608 +3 546 602 559 +3 559 608 572 +3 546 572 608 +3 546 602 592 +3 553 592 602 +3 546 553 602 +3 553 602 559 +3 546 602 568 +3 568 602 592 +3 583 609 628 +3 547 583 628 +3 547 628 609 +3 547 628 584 +3 584 628 609 +3 576 594 577 +3 548 577 594 +3 548 594 576 +3 548 594 550 +3 550 594 576 +3 549 638 663 +3 549 555 638 +3 555 663 638 +3 600 638 663 +3 549 638 600 +3 555 638 648 +3 549 648 638 +3 549 606 638 +3 606 648 638 +3 594 609 595 +3 550 609 594 +3 550 594 595 +3 576 609 594 +3 551 617 556 +3 551 556 573 +3 551 573 617 +3 556 617 573 +3 551 582 617 +3 551 573 582 +3 573 617 582 +3 556 582 617 +3 552 589 598 +3 552 598 564 +3 552 564 589 +3 564 598 589 +3 552 598 574 +3 564 574 598 +3 553 639 592 +3 553 627 639 +3 592 639 627 +3 553 592 627 +3 559 592 602 +3 553 592 559 +3 553 625 559 +3 559 625 639 +3 553 559 639 +3 553 639 625 +3 625 627 639 +3 553 627 625 +3 559 639 592 +3 559 565 625 +3 553 625 565 +3 562 614 593 +3 554 593 614 +3 554 618 614 +3 593 614 618 +3 555 622 648 +3 622 663 648 +3 555 648 663 +3 638 648 663 +3 556 651 578 +3 578 651 664 +3 556 578 664 +3 556 664 651 +3 651 652 664 +3 556 664 652 +3 556 652 651 +3 582 617 652 +3 556 652 617 +3 556 582 652 +3 556 652 647 +3 647 652 651 +3 578 664 591 +3 556 591 664 +3 556 578 591 +3 556 664 617 +3 617 664 652 +3 582 652 647 +3 556 591 573 +3 556 617 591 +3 573 591 617 +3 556 660 563 +3 563 660 578 +3 556 563 578 +3 556 578 660 +3 563 651 660 +3 556 660 651 +3 591 664 617 +3 578 660 651 +3 557 597 583 +3 557 609 597 +3 583 597 609 +3 557 583 612 +3 557 612 571 +3 571 612 583 +3 557 612 597 +3 557 597 571 +3 571 597 612 +3 583 612 597 +3 557 595 597 +3 595 609 597 +3 558 579 563 +3 558 605 579 +3 563 579 605 +3 567 643 603 +3 559 603 643 +3 559 643 567 +3 559 643 639 +3 559 665 643 +3 639 643 665 +3 559 639 665 +3 559 625 665 +3 625 639 665 +3 559 639 636 +3 608 636 639 +3 559 636 608 +3 559 608 639 +3 636 643 639 +3 559 643 636 +3 559 665 565 +3 559 567 665 +3 565 665 567 +3 603 643 636 +3 559 603 636 +3 559 565 634 +3 559 634 625 +3 565 625 634 +3 572 607 608 +3 559 607 572 +3 559 608 607 +3 559 634 665 +3 625 665 634 +3 602 608 639 +3 559 602 639 +3 559 636 607 +3 607 636 608 +3 559 607 561 +3 561 607 572 +3 561 603 636 +3 559 561 636 +3 592 602 639 +3 561 636 607 +3 567 665 643 +3 565 634 665 +3 560 613 576 +3 576 613 609 +3 560 609 613 +3 560 570 613 +3 560 609 570 +3 570 609 613 +3 570 593 609 +3 603 636 637 +3 561 603 637 +3 561 637 636 +3 601 603 637 +3 561 601 637 +3 561 603 601 +3 572 601 607 +3 561 607 601 +3 561 601 636 +3 601 637 636 +3 601 636 607 +3 562 581 610 +3 581 585 610 +3 562 610 585 +3 562 585 581 +3 581 673 615 +3 562 615 673 +3 562 673 581 +3 562 610 673 +3 562 614 610 +3 610 614 673 +3 562 673 614 +3 569 614 610 +3 562 569 610 +3 581 610 673 +3 562 615 614 +3 614 615 673 +3 593 615 614 +3 569 610 585 +3 562 569 585 +3 563 660 580 +3 563 580 578 +3 578 580 660 +3 563 579 580 +3 579 623 580 +3 563 580 623 +3 563 623 579 +3 563 649 623 +3 563 623 660 +3 563 660 649 +3 623 649 660 +3 563 605 623 +3 605 649 623 +3 649 651 660 +3 580 623 660 +3 579 605 623 +3 581 615 598 +3 564 598 615 +3 564 581 598 +3 574 598 615 +3 564 581 589 +3 581 598 589 +3 565 634 620 +3 565 620 665 +3 620 634 665 +3 565 620 596 +3 567 596 620 +3 565 567 620 +3 567 620 665 +3 611 647 659 +3 566 611 659 +3 611 659 622 +3 566 611 622 +3 567 665 680 +3 567 680 691 +3 567 691 665 +3 665 691 680 +3 567 665 675 +3 567 675 643 +3 643 675 665 +3 567 640 691 +3 567 691 657 +3 567 657 640 +3 640 657 691 +3 596 620 657 +3 567 596 657 +3 567 657 620 +3 567 657 680 +3 567 680 620 +3 620 680 657 +3 567 640 675 +3 567 675 691 +3 640 691 675 +3 567 603 675 +3 603 604 675 +3 567 675 604 +3 620 665 680 +3 575 596 640 +3 567 640 596 +3 665 675 691 +3 596 657 640 +3 657 680 691 +3 604 640 675 +3 603 675 643 +3 568 602 621 +3 568 621 592 +3 592 621 602 +3 570 609 655 +3 570 655 613 +3 609 613 655 +3 570 655 593 +3 570 593 635 +3 570 635 655 +3 593 655 635 +3 570 574 635 +3 574 593 635 +3 593 609 655 +3 598 615 635 +3 574 598 635 +3 574 635 615 +3 593 635 615 +3 575 690 596 +3 596 690 653 +3 575 653 690 +3 596 640 690 +3 575 690 640 +3 640 699 690 +3 575 690 699 +3 575 699 640 +3 653 690 699 +3 575 653 699 +3 575 629 699 +3 629 653 699 +3 594 632 609 +3 576 632 594 +3 576 609 632 +3 576 632 577 +3 577 632 594 +3 576 613 632 +3 609 632 613 +3 577 632 619 +3 577 619 594 +3 594 619 632 +3 578 669 660 +3 578 580 669 +3 580 660 669 +3 651 664 660 +3 578 660 664 +3 578 580 590 +3 580 669 590 +3 578 590 669 +3 578 672 588 +3 588 672 631 +3 578 588 631 +3 578 631 672 +3 660 664 669 +3 578 669 664 +3 578 672 669 +3 590 669 672 +3 578 590 672 +3 588 631 591 +3 578 588 591 +3 578 591 631 +3 588 590 672 +3 578 590 588 +3 664 672 669 +3 578 672 664 +3 591 631 664 +3 578 664 631 +3 631 672 664 +3 580 626 623 +3 579 626 580 +3 579 623 626 +3 590 670 669 +3 580 670 590 +3 580 669 670 +3 660 669 670 +3 580 660 670 +3 580 670 626 +3 590 626 670 +3 580 626 590 +3 580 599 590 +3 580 626 599 +3 590 599 626 +3 626 660 670 +3 580 660 626 +3 623 660 626 +3 589 616 646 +3 581 616 589 +3 581 646 616 +3 581 589 646 +3 581 598 646 +3 589 646 598 +3 581 689 586 +3 581 668 689 +3 586 689 668 +3 581 586 668 +3 615 646 689 +3 581 615 689 +3 581 646 615 +3 581 689 646 +3 581 587 616 +3 586 616 587 +3 581 616 586 +3 581 586 587 +3 581 646 668 +3 616 668 646 +3 581 668 616 +3 587 616 589 +3 581 587 589 +3 598 646 615 +3 585 673 689 +3 581 689 673 +3 581 585 689 +3 581 673 585 +3 586 668 616 +3 615 689 673 +3 585 689 586 +3 581 585 586 +3 585 610 673 +3 646 668 689 +3 611 652 647 +3 582 652 611 +3 582 617 611 +3 611 617 652 +3 609 628 656 +3 583 656 628 +3 583 609 656 +3 597 609 612 +3 583 612 609 +3 609 656 612 +3 583 612 656 +3 593 618 628 +3 584 628 618 +3 584 593 628 +3 593 628 609 +3 610 673 689 +3 585 610 689 +3 585 588 679 +3 585 679 650 +3 585 650 588 +3 588 650 679 +3 585 679 689 +3 585 610 679 +3 610 689 679 +3 586 679 689 +3 585 679 586 +3 588 610 650 +3 585 650 610 +3 585 610 588 +3 585 590 679 +3 585 588 590 +3 588 679 590 +3 610 679 650 +3 585 590 586 +3 586 590 679 +3 586 641 678 +3 586 590 641 +3 590 678 641 +3 586 678 590 +3 616 682 668 +3 586 668 682 +3 586 682 616 +3 586 689 682 +3 668 682 689 +3 678 679 689 +3 586 678 689 +3 586 679 678 +3 616 678 682 +3 586 682 678 +3 586 678 616 +3 678 689 682 +3 586 616 641 +3 587 641 616 +3 586 641 587 +3 590 679 678 +3 587 590 641 +3 586 590 587 +3 616 641 678 +3 587 641 599 +3 599 641 616 +3 587 599 616 +3 590 641 599 +3 587 590 599 +3 588 650 631 +3 588 672 650 +3 631 650 672 +3 590 672 679 +3 588 679 672 +3 650 679 672 +3 590 679 669 +3 590 669 678 +3 669 679 678 +3 590 670 641 +3 641 670 678 +3 590 678 670 +3 669 672 679 +3 626 670 641 +3 590 626 641 +3 599 626 641 +3 669 678 670 +3 592 621 627 +3 592 633 621 +3 621 633 627 +3 592 627 633 +3 602 633 621 +3 592 633 602 +3 592 639 633 +3 627 633 639 +3 602 639 633 +3 593 609 618 +3 593 687 609 +3 609 687 618 +3 593 618 687 +3 615 671 686 +3 593 671 615 +3 593 686 671 +3 593 615 686 +3 593 686 687 +3 593 618 686 +3 618 687 686 +3 614 618 671 +3 593 614 671 +3 593 671 618 +3 609 655 686 +3 593 609 686 +3 593 686 655 +3 593 635 686 +3 615 686 635 +3 609 618 628 +3 618 686 671 +3 614 671 615 +3 635 686 655 +3 609 686 687 +3 609 619 632 +3 594 619 609 +3 595 619 609 +3 594 619 595 +3 595 597 656 +3 595 656 642 +3 595 642 597 +3 597 642 656 +3 597 656 609 +3 595 609 656 +3 595 642 609 +3 609 642 619 +3 595 619 642 +3 609 656 642 +3 640 690 657 +3 596 657 690 +3 612 666 656 +3 597 666 612 +3 597 656 666 +3 597 612 656 +3 642 656 666 +3 597 642 666 +3 612 624 666 +3 597 666 624 +3 597 624 612 +3 624 642 666 +3 597 642 624 +3 598 646 635 +3 615 635 646 +3 601 637 607 +3 607 637 636 +3 601 630 607 +3 607 630 637 +3 601 637 630 +3 608 639 633 +3 602 608 633 +3 603 643 637 +3 636 637 643 +3 603 675 644 +3 603 644 643 +3 643 644 675 +3 603 644 637 +3 637 644 643 +3 603 604 674 +3 603 674 675 +3 604 675 674 +3 603 674 644 +3 644 674 675 +3 604 701 674 +3 674 701 675 +3 604 675 701 +3 604 640 701 +3 640 675 701 +3 629 677 653 +3 606 653 677 +3 606 677 629 +3 638 677 648 +3 606 677 638 +3 606 648 677 +3 629 648 677 +3 607 630 636 +3 630 637 636 +3 632 684 642 +3 609 632 642 +3 609 684 632 +3 609 642 684 +3 613 684 632 +3 609 684 613 +3 609 709 655 +3 613 655 709 +3 609 613 709 +3 609 687 628 +3 618 628 687 +3 609 717 642 +3 642 717 656 +3 609 656 717 +3 609 687 656 +3 628 656 687 +3 686 687 717 +3 609 717 687 +3 609 686 717 +3 642 684 717 +3 609 717 684 +3 619 632 642 +3 655 686 717 +3 609 655 717 +3 609 717 709 +3 609 709 684 +3 684 709 717 +3 656 717 687 +3 655 717 709 +3 613 709 684 +3 610 685 650 +3 650 685 679 +3 610 679 685 +3 610 685 689 +3 610 673 685 +3 673 689 685 +3 679 685 689 +3 611 652 645 +3 611 645 647 +3 645 652 647 +3 611 617 645 +3 617 652 645 +3 645 647 659 +3 611 645 659 +3 624 656 654 +3 612 624 654 +3 612 656 624 +3 612 654 656 +3 624 666 656 +3 614 686 615 +3 614 671 686 +3 671 686 673 +3 614 673 686 +3 614 671 673 +3 615 673 686 +3 615 686 708 +3 615 708 646 +3 615 646 686 +3 646 708 686 +3 615 686 689 +3 615 689 708 +3 686 708 689 +3 646 689 708 +3 615 635 695 +3 615 695 646 +3 635 646 695 +3 673 686 689 +3 635 695 686 +3 615 686 695 +3 646 686 695 +3 616 641 668 +3 616 682 641 +3 641 682 668 +3 641 678 682 +3 671 687 686 +3 618 687 671 +3 632 642 658 +3 619 632 658 +3 619 658 642 +3 620 634 661 +3 634 665 661 +3 620 661 665 +3 657 667 680 +3 620 667 657 +3 620 680 667 +3 634 661 680 +3 620 634 680 +3 620 680 661 +3 661 665 680 +3 634 680 667 +3 620 634 667 +3 659 663 703 +3 622 659 703 +3 622 703 663 +3 622 703 648 +3 648 703 663 +3 648 681 703 +3 622 681 648 +3 622 703 681 +3 659 703 681 +3 622 659 681 +3 623 662 660 +3 649 660 662 +3 623 649 662 +3 623 662 626 +3 626 662 660 +3 654 666 656 +3 624 666 654 +3 625 665 661 +3 625 661 634 +3 639 665 661 +3 625 639 661 +3 660 670 662 +3 626 662 670 +3 629 711 677 +3 629 677 714 +3 629 714 711 +3 677 711 714 +3 629 711 733 +3 629 733 653 +3 629 653 711 +3 653 733 711 +3 653 711 721 +3 629 721 711 +3 629 653 721 +3 629 711 699 +3 629 699 733 +3 699 711 733 +3 648 677 714 +3 629 648 714 +3 653 699 733 +3 677 721 711 +3 629 721 677 +3 653 721 677 +3 632 684 658 +3 642 658 684 +3 634 661 667 +3 661 680 667 +3 635 695 704 +3 635 704 686 +3 686 704 695 +3 635 704 655 +3 655 704 686 +3 638 663 703 +3 638 703 716 +3 638 716 663 +3 663 716 703 +3 677 716 710 +3 638 716 677 +3 638 710 716 +3 638 677 710 +3 677 703 716 +3 638 703 677 +3 638 648 703 +3 648 703 677 +3 638 710 663 +3 663 710 716 +3 640 700 691 +3 657 691 700 +3 640 657 700 +3 675 701 691 +3 640 691 701 +3 640 690 727 +3 640 700 690 +3 690 700 727 +3 640 727 700 +3 657 700 690 +3 699 727 738 +3 640 699 738 +3 640 727 699 +3 640 738 727 +3 640 691 707 +3 640 727 691 +3 691 727 707 +3 640 707 727 +3 640 727 701 +3 691 701 727 +3 640 707 700 +3 700 707 727 +3 701 738 727 +3 640 738 701 +3 690 727 699 +3 691 707 700 +3 676 678 682 +3 641 676 682 +3 641 678 676 +3 670 678 676 +3 641 670 676 +3 668 676 682 +3 641 676 668 +3 642 694 666 +3 642 656 694 +3 656 666 694 +3 642 684 694 +3 642 694 717 +3 684 717 694 +3 642 658 694 +3 658 684 694 +3 656 694 717 +3 668 689 693 +3 646 668 693 +3 646 693 689 +3 646 708 693 +3 646 693 695 +3 646 695 708 +3 693 708 695 +3 689 708 693 +3 686 695 708 +3 648 703 714 +3 677 714 703 +3 703 714 720 +3 648 720 714 +3 648 703 720 +3 681 703 720 +3 648 681 720 +3 690 699 733 +3 653 690 733 +3 711 721 729 +3 653 729 721 +3 653 711 729 +3 653 729 733 +3 653 690 729 +3 690 733 729 +3 711 729 733 +3 654 666 683 +3 666 692 683 +3 654 683 692 +3 654 692 666 +3 656 692 666 +3 654 692 656 +3 655 704 717 +3 686 717 704 +3 655 704 709 +3 704 717 709 +3 656 717 702 +3 687 702 717 +3 656 702 687 +3 666 702 692 +3 656 702 666 +3 656 692 702 +3 656 694 702 +3 694 717 702 +3 666 694 702 +3 657 697 700 +3 657 707 697 +3 697 707 700 +3 657 700 707 +3 657 707 680 +3 680 707 697 +3 657 680 697 +3 657 691 707 +3 657 688 697 +3 680 697 688 +3 657 680 688 +3 657 667 688 +3 667 680 688 +3 680 691 707 +3 658 684 698 +3 658 698 694 +3 684 694 698 +3 666 706 683 +3 666 692 706 +3 683 706 692 +3 692 694 702 +3 666 694 692 +3 666 694 706 +3 692 706 694 +3 668 682 693 +3 682 689 693 +3 673 705 686 +3 671 705 673 +3 671 686 705 +3 671 712 705 +3 686 705 712 +3 671 686 712 +3 686 712 687 +3 671 687 712 +3 673 713 696 +3 673 705 713 +3 696 713 705 +3 673 696 705 +3 686 696 705 +3 673 696 686 +3 686 689 696 +3 673 696 689 +3 673 696 685 +3 685 696 689 +3 677 725 754 +3 714 754 725 +3 677 754 714 +3 677 714 725 +3 677 725 716 +3 716 725 754 +3 677 716 754 +3 677 725 710 +3 710 725 716 +3 703 716 754 +3 677 703 754 +3 677 721 714 +3 711 714 721 +3 714 725 721 +3 677 721 725 +3 703 754 714 +3 688 707 697 +3 680 707 688 +3 682 689 708 +3 682 708 693 +3 692 723 706 +3 683 723 692 +3 683 706 723 +3 684 718 698 +3 694 698 718 +3 684 694 718 +3 684 718 736 +3 718 730 736 +3 684 736 730 +3 684 730 718 +3 694 718 717 +3 684 717 718 +3 709 717 736 +3 684 736 717 +3 684 709 736 +3 698 730 718 +3 684 730 698 +3 717 718 736 +3 735 785 764 +3 686 764 785 +3 686 735 764 +3 686 785 735 +3 686 745 705 +3 686 705 743 +3 686 743 745 +3 705 745 743 +3 686 744 735 +3 735 744 785 +3 686 785 744 +3 696 705 722 +3 686 696 722 +3 686 722 705 +3 686 744 695 +3 695 744 735 +3 686 695 735 +3 745 759 771 +3 686 771 759 +3 686 745 771 +3 686 759 745 +3 695 708 744 +3 686 744 708 +3 686 794 717 +3 717 794 759 +3 686 717 759 +3 686 759 794 +3 687 717 712 +3 686 712 717 +3 686 759 712 +3 686 712 745 +3 712 759 745 +3 686 785 794 +3 686 771 785 +3 771 794 785 +3 686 794 771 +3 686 764 755 +3 755 764 785 +3 686 755 785 +3 704 764 755 +3 686 764 704 +3 686 704 755 +3 686 755 794 +3 755 785 794 +3 686 722 689 +3 689 722 708 +3 686 708 722 +3 712 717 759 +3 744 771 785 +3 686 771 744 +3 686 717 755 +3 704 755 717 +3 686 704 735 +3 695 735 704 +3 705 712 745 +3 704 735 764 +3 686 743 744 +3 743 771 744 +3 686 771 743 +3 686 722 744 +3 686 743 722 +3 722 743 744 +3 743 745 771 +3 689 696 722 +3 708 722 744 +3 717 755 794 +3 705 743 722 +3 759 794 771 +3 717 752 737 +3 687 737 752 +3 687 717 737 +3 687 752 717 +3 712 752 717 +3 687 752 712 +3 687 702 737 +3 702 717 737 +3 690 742 732 +3 732 742 733 +3 690 732 733 +3 690 733 742 +3 690 732 751 +3 732 733 751 +3 690 751 733 +3 690 751 729 +3 729 751 733 +3 700 742 732 +3 690 700 732 +3 690 742 700 +3 700 727 733 +3 690 700 733 +3 690 733 727 +3 699 733 727 +3 700 733 742 +3 706 724 723 +3 692 723 724 +3 692 724 706 +3 692 706 702 +3 694 702 706 +3 702 724 706 +3 692 724 702 +3 693 715 695 +3 693 708 715 +3 695 715 708 +3 694 702 728 +3 702 706 728 +3 694 728 706 +3 717 728 718 +3 694 728 717 +3 694 718 728 +3 702 728 717 +3 731 744 735 +3 695 744 731 +3 695 731 735 +3 695 734 744 +3 708 744 734 +3 695 708 734 +3 708 734 731 +3 695 708 731 +3 695 731 734 +3 731 734 744 +3 708 731 715 +3 695 715 731 +3 696 713 722 +3 705 722 713 +3 700 719 707 +3 697 719 700 +3 697 707 719 +3 699 733 738 +3 727 738 733 +3 711 733 757 +3 699 757 733 +3 699 711 757 +3 699 733 763 +3 699 763 738 +3 733 738 763 +3 699 757 763 +3 733 763 757 +3 700 742 727 +3 700 707 742 +3 707 727 742 +3 727 733 742 +3 700 719 732 +3 700 742 719 +3 719 742 732 +3 707 742 719 +3 706 728 724 +3 702 724 728 +3 702 717 724 +3 717 737 724 +3 702 724 737 +3 717 724 728 +3 703 754 739 +3 714 739 754 +3 703 739 714 +3 703 739 720 +3 714 720 739 +3 703 716 739 +3 716 754 739 +3 704 755 709 +3 709 755 717 +3 705 726 743 +3 705 745 726 +3 726 745 743 +3 705 726 713 +3 713 726 722 +3 705 722 726 +3 722 726 743 +3 724 741 728 +3 706 728 741 +3 706 741 724 +3 723 741 724 +3 706 741 723 +3 715 734 731 +3 708 734 715 +3 709 755 747 +3 717 747 755 +3 709 747 717 +3 709 747 736 +3 717 736 747 +3 710 725 749 +3 710 749 716 +3 716 749 725 +3 711 762 729 +3 711 721 762 +3 721 729 762 +3 711 776 762 +3 711 768 776 +3 762 776 768 +3 711 762 768 +3 711 757 762 +3 711 776 757 +3 757 776 762 +3 711 733 762 +3 733 757 762 +3 714 721 762 +3 711 714 762 +3 729 733 762 +3 711 714 768 +3 714 762 768 +3 717 759 752 +3 712 752 759 +3 713 743 722 +3 713 726 743 +3 714 739 760 +3 739 775 760 +3 714 760 775 +3 714 775 739 +3 714 762 754 +3 714 775 762 +3 754 762 775 +3 714 754 775 +3 714 720 760 +3 720 739 760 +3 739 754 775 +3 762 768 775 +3 714 775 768 +3 714 725 762 +3 721 762 725 +3 714 760 768 +3 760 775 768 +3 725 762 754 +3 725 754 749 +3 716 749 754 +3 717 756 766 +3 756 783 766 +3 717 766 783 +3 717 783 756 +3 717 724 741 +3 717 741 728 +3 717 777 747 +3 717 747 798 +3 717 798 777 +3 747 777 798 +3 737 793 752 +3 717 793 737 +3 717 752 793 +3 755 794 807 +3 717 755 807 +3 717 807 794 +3 717 759 804 +3 717 804 752 +3 752 804 759 +3 737 766 793 +3 717 766 737 +3 717 793 766 +3 717 761 736 +3 717 746 761 +3 736 761 746 +3 717 736 746 +3 717 807 752 +3 717 804 807 +3 752 807 804 +3 752 793 805 +3 717 805 793 +3 717 752 805 +3 717 741 737 +3 737 741 766 +3 717 766 741 +3 717 807 759 +3 759 807 794 +3 717 718 746 +3 718 736 746 +3 717 755 798 +3 755 807 798 +3 717 798 807 +3 717 777 755 +3 747 755 777 +3 717 736 783 +3 736 747 783 +3 717 783 747 +3 717 718 756 +3 718 746 756 +3 717 756 746 +3 717 761 783 +3 736 783 761 +3 717 798 783 +3 717 793 798 +3 783 798 793 +3 717 783 793 +3 717 756 728 +3 728 756 766 +3 717 728 766 +3 717 756 761 +3 746 761 756 +3 718 756 728 +3 766 783 793 +3 793 807 805 +3 717 807 793 +3 717 805 807 +3 752 805 807 +3 793 798 807 +3 728 766 741 +3 747 798 783 +3 756 761 783 +3 759 804 807 +3 724 741 737 +3 755 798 777 +3 728 746 756 +3 718 746 728 +3 730 736 746 +3 718 730 746 +3 725 773 762 +3 721 762 773 +3 721 773 725 +3 721 729 773 +3 729 762 773 +3 724 740 741 +3 723 741 740 +3 723 740 724 +3 724 753 741 +3 740 741 753 +3 724 740 753 +3 724 766 741 +3 741 766 753 +3 724 753 766 +3 724 766 737 +3 737 753 766 +3 724 753 737 +3 725 765 754 +3 754 765 762 +3 725 762 765 +3 762 765 773 +3 725 773 765 +3 725 765 749 +3 749 765 754 +3 743 748 745 +3 726 748 743 +3 726 745 748 +3 733 779 770 +3 727 770 779 +3 727 733 770 +3 727 779 733 +3 733 770 738 +3 727 738 770 +3 727 779 742 +3 733 742 779 +3 728 756 741 +3 741 756 766 +3 762 773 791 +3 729 791 773 +3 729 762 791 +3 729 751 767 +3 729 767 733 +3 733 767 751 +3 729 767 762 +3 733 762 767 +3 762 791 767 +3 729 767 791 +3 736 746 750 +3 730 736 750 +3 730 750 746 +3 734 744 735 +3 731 734 735 +3 735 758 769 +3 731 735 769 +3 731 758 735 +3 731 769 758 +3 734 735 769 +3 731 734 769 +3 731 734 758 +3 734 769 758 +3 751 774 779 +3 732 751 779 +3 732 774 751 +3 732 779 774 +3 742 751 779 +3 732 751 742 +3 732 742 779 +3 733 751 742 +3 742 779 774 +3 732 742 774 +3 733 751 779 +3 733 788 770 +3 770 788 779 +3 733 779 788 +3 733 788 820 +3 763 820 788 +3 733 820 763 +3 733 763 788 +3 779 788 784 +3 733 784 788 +3 733 779 784 +3 762 784 829 +3 733 784 762 +3 733 829 784 +3 733 762 829 +3 751 779 784 +3 733 751 784 +3 733 824 762 +3 733 757 824 +3 757 762 824 +3 733 784 824 +3 784 820 824 +3 733 824 820 +3 733 820 784 +3 762 767 784 +3 733 784 767 +3 784 824 829 +3 733 829 824 +3 763 788 770 +3 733 763 770 +3 784 788 820 +3 751 784 767 +3 757 824 763 +3 733 763 824 +3 762 829 824 +3 738 763 770 +3 763 824 820 +3 735 769 744 +3 734 744 769 +3 735 780 764 +3 735 785 780 +3 764 780 785 +3 735 769 785 +3 744 785 769 +3 735 780 769 +3 758 769 780 +3 735 758 780 +3 769 785 780 +3 736 761 750 +3 746 750 761 +3 736 761 747 +3 736 747 778 +3 736 778 761 +3 747 761 778 +3 736 747 781 +3 736 781 778 +3 747 778 781 +3 750 778 761 +3 736 778 750 +3 747 783 761 +3 752 795 793 +3 737 795 752 +3 737 793 795 +3 753 766 782 +3 737 782 766 +3 737 753 782 +3 737 782 793 +3 766 793 782 +3 737 782 795 +3 782 793 795 +3 743 745 772 +3 743 772 771 +3 745 771 772 +3 745 772 748 +3 743 748 772 +3 744 771 769 +3 769 771 785 +3 745 771 787 +3 771 772 787 +3 745 787 772 +3 745 759 787 +3 759 771 787 +3 781 798 783 +3 747 781 783 +3 747 798 781 +3 777 798 781 +3 747 777 781 +3 778 781 783 +3 747 778 783 +3 761 778 783 +3 749 765 797 +3 754 797 765 +3 749 797 754 +3 751 774 784 +3 774 779 784 +3 751 774 786 +3 751 786 784 +3 774 784 786 +3 751 792 767 +3 767 792 784 +3 751 784 792 +3 751 786 792 +3 784 792 786 +3 752 804 789 +3 759 789 804 +3 752 789 759 +3 752 805 789 +3 752 804 805 +3 789 805 804 +3 793 805 795 +3 752 795 805 +3 752 795 789 +3 789 795 805 +3 804 805 807 +3 762 775 809 +3 754 762 809 +3 754 809 775 +3 765 809 797 +3 754 797 809 +3 754 809 765 +3 762 809 765 +3 755 764 807 +3 764 785 807 +3 755 807 785 +3 785 794 807 +3 755 806 777 +3 777 806 807 +3 755 777 807 +3 755 807 806 +3 755 799 806 +3 799 807 806 +3 755 807 799 +3 755 764 799 +3 764 807 799 +3 777 807 798 +3 757 828 824 +3 762 824 828 +3 757 762 828 +3 776 828 824 +3 757 776 824 +3 757 828 776 +3 757 824 815 +3 813 815 824 +3 757 815 813 +3 757 813 824 +3 762 828 776 +3 757 776 815 +3 776 824 815 +3 763 813 824 +3 757 813 763 +3 759 789 800 +3 789 804 800 +3 759 800 804 +3 787 804 794 +3 759 787 794 +3 759 804 787 +3 759 794 804 +3 794 804 807 +3 771 787 794 +3 759 800 787 +3 787 800 804 +3 775 802 801 +3 760 802 775 +3 760 801 802 +3 760 775 801 +3 768 802 775 +3 760 802 768 +3 762 826 768 +3 762 776 826 +3 768 826 776 +3 762 836 809 +3 762 775 836 +3 775 809 836 +3 775 836 826 +3 762 775 826 +3 762 826 836 +3 762 814 827 +3 791 827 814 +3 762 827 791 +3 762 791 814 +3 767 784 829 +3 762 767 829 +3 762 836 773 +3 773 836 809 +3 762 773 809 +3 762 829 836 +3 762 828 829 +3 828 836 829 +3 762 836 828 +3 762 767 803 +3 767 829 803 +3 762 803 829 +3 762 836 827 +3 762 814 836 +3 814 827 836 +3 762 826 828 +3 826 836 828 +3 762 829 827 +3 827 829 836 +3 773 791 814 +3 762 773 814 +3 768 775 826 +3 773 814 836 +3 762 803 791 +3 791 803 829 +3 762 791 829 +3 776 826 828 +3 767 803 791 +3 791 829 827 +3 765 773 809 +3 824 828 829 +3 770 811 788 +3 763 811 770 +3 763 788 811 +3 763 820 811 +3 788 811 820 +3 811 813 820 +3 763 813 811 +3 763 820 813 +3 813 824 820 +3 764 785 799 +3 785 807 799 +3 764 780 799 +3 780 785 799 +3 797 808 809 +3 765 808 797 +3 765 809 808 +3 765 773 808 +3 773 809 808 +3 784 803 792 +3 767 803 784 +3 767 792 803 +3 784 829 803 +3 802 826 812 +3 768 802 812 +3 768 826 802 +3 768 812 826 +3 776 812 826 +3 768 812 776 +3 775 826 802 +3 773 832 836 +3 814 836 832 +3 773 814 832 +3 808 836 809 +3 773 836 808 +3 808 814 832 +3 773 808 832 +3 773 814 808 +3 808 832 836 +3 774 779 796 +3 774 796 784 +3 779 784 796 +3 774 810 786 +3 774 786 796 +3 774 796 810 +3 786 810 796 +3 784 786 796 +3 775 801 826 +3 775 826 831 +3 775 831 801 +3 801 831 826 +3 809 836 831 +3 775 831 836 +3 775 809 831 +3 826 831 836 +3 801 826 802 +3 812 826 828 +3 776 812 828 +3 776 815 828 +3 812 828 815 +3 776 812 815 +3 815 828 824 +3 777 806 798 +3 798 806 807 +3 777 806 790 +3 790 806 798 +3 777 790 798 +3 777 790 781 +3 781 790 798 +3 779 817 784 +3 779 788 817 +3 784 817 788 +3 784 796 817 +3 779 817 796 +3 784 820 823 +3 820 824 823 +3 784 823 824 +3 784 792 821 +3 786 821 792 +3 784 821 786 +3 784 818 796 +3 796 818 821 +3 784 796 821 +3 784 821 818 +3 786 796 821 +3 788 820 817 +3 784 817 820 +3 792 825 803 +3 784 803 825 +3 784 825 792 +3 803 825 829 +3 784 829 825 +3 784 823 829 +3 823 824 829 +3 784 825 821 +3 792 821 825 +3 817 821 818 +3 784 817 818 +3 784 821 817 +3 796 817 818 +3 784 821 823 +3 817 823 821 +3 784 823 817 +3 821 823 825 +3 784 825 823 +3 817 820 823 +3 823 829 825 +3 785 794 799 +3 794 807 799 +3 786 819 821 +3 818 821 819 +3 786 821 818 +3 786 818 819 +3 810 818 819 +3 786 818 810 +3 786 810 819 +3 786 818 796 +3 796 818 810 +3 792 819 821 +3 786 819 792 +3 791 803 827 +3 803 829 827 +3 791 803 830 +3 803 827 830 +3 791 830 827 +3 792 822 821 +3 819 821 822 +3 792 819 822 +3 792 822 825 +3 821 825 822 +3 816 822 825 +3 792 822 816 +3 792 816 825 +3 803 816 825 +3 792 816 803 +3 797 834 809 +3 797 808 834 +3 808 809 834 +3 801 838 835 +3 801 831 838 +3 831 835 838 +3 801 835 831 +3 802 838 835 +3 801 838 802 +3 801 802 835 +3 801 802 831 +3 802 835 831 +3 802 831 826 +3 802 826 835 +3 812 835 826 +3 802 835 812 +3 826 835 831 +3 825 829 827 +3 803 825 827 +3 803 825 830 +3 825 827 830 +3 816 825 830 +3 803 816 830 +3 808 836 833 +3 808 833 809 +3 809 833 836 +3 808 833 834 +3 809 834 833 +3 814 832 833 +3 808 833 832 +3 808 814 833 +3 832 836 833 +3 809 841 833 +3 833 841 834 +3 809 834 841 +3 833 836 841 +3 809 841 836 +3 831 841 836 +3 809 841 831 +3 815 826 828 +3 812 826 815 +3 826 839 835 +3 812 839 826 +3 812 835 839 +3 832 833 837 +3 814 832 837 +3 814 837 833 +3 827 836 832 +3 814 827 832 +3 826 831 842 +3 826 842 836 +3 831 836 842 +3 835 842 839 +3 826 842 835 +3 826 839 842 +3 831 842 835 +3 831 844 838 +3 831 835 844 +3 835 838 844 +3 831 842 841 +3 831 851 842 +3 841 842 851 +3 831 841 851 +3 831 842 844 +3 835 844 842 +3 842 847 851 +3 831 847 842 +3 831 851 847 +3 842 844 847 +3 831 847 844 +3 841 851 847 +3 831 841 847 +3 836 842 841 +3 838 847 844 +3 831 847 838 +3 832 845 837 +3 833 837 845 +3 832 833 845 +3 833 845 836 +3 832 836 845 +3 836 841 845 +3 833 845 841 +3 840 845 841 +3 833 840 841 +3 833 845 840 +3 834 840 841 +3 833 840 834 +3 837 845 840 +3 833 837 840 +3 840 841 843 +3 834 843 841 +3 834 840 843 +3 834 843 848 +3 841 848 843 +3 834 848 841 +3 835 846 839 +3 839 846 844 +3 835 839 844 +3 835 844 846 +3 839 844 842 +3 836 851 841 +3 836 842 851 +3 841 845 851 +3 836 851 845 +3 837 845 850 +3 837 850 840 +3 840 850 845 +3 838 847 854 +3 844 854 847 +3 838 854 844 +3 839 852 842 +3 839 842 846 +3 839 846 852 +3 842 852 846 +3 842 846 844 +3 840 845 849 +3 840 849 841 +3 841 849 845 +3 840 848 849 +3 843 849 848 +3 840 849 843 +3 840 843 848 +3 840 841 848 +3 841 848 849 +3 840 850 849 +3 845 849 850 +3 841 851 861 +3 841 853 851 +3 851 853 861 +3 841 861 853 +3 845 861 849 +3 841 861 845 +3 841 849 861 +3 845 851 861 +3 841 861 848 +3 848 861 853 +3 841 848 853 +3 848 849 861 +3 847 853 851 +3 841 853 847 +3 847 851 852 +3 842 852 851 +3 842 847 852 +3 842 844 852 +3 844 847 852 +3 844 852 846 +3 847 855 859 +3 844 847 859 +3 844 855 847 +3 844 859 855 +3 844 855 852 +3 847 852 855 +3 846 855 852 +3 844 855 846 +3 847 859 854 +3 844 854 859 +3 849 850 861 +3 845 861 850 +3 846 855 856 +3 846 856 852 +3 852 856 855 +3 847 862 859 +3 847 867 862 +3 859 862 867 +3 847 859 867 +3 847 859 863 +3 847 863 854 +3 854 863 859 +3 847 862 863 +3 859 863 862 +3 847 869 852 +3 851 852 869 +3 847 851 869 +3 851 869 853 +3 847 853 869 +3 847 853 862 +3 847 862 869 +3 853 869 862 +3 852 867 869 +3 847 867 852 +3 847 869 867 +3 862 869 867 +3 852 855 859 +3 847 852 859 +3 852 859 867 +3 848 849 857 +3 848 857 858 +3 848 858 849 +3 849 858 857 +3 848 858 861 +3 849 861 858 +3 848 858 853 +3 853 858 861 +3 850 861 860 +3 849 850 860 +3 849 860 861 +3 857 865 858 +3 849 865 857 +3 849 858 865 +3 849 858 860 +3 858 865 860 +3 849 860 865 +3 858 860 861 +3 850 861 864 +3 850 864 860 +3 860 864 861 +3 853 861 869 +3 851 869 861 +3 852 856 867 +3 855 867 856 +3 852 867 855 +3 855 859 867 +3 853 874 862 +3 862 874 869 +3 853 869 874 +3 858 861 874 +3 853 858 874 +3 853 874 861 +3 858 874 870 +3 853 858 870 +3 853 870 874 +3 862 870 874 +3 853 870 862 +3 861 869 874 +3 854 868 859 +3 854 863 868 +3 859 868 863 +3 858 866 865 +3 857 866 858 +3 857 865 866 +3 858 865 870 +3 858 871 865 +3 865 871 870 +3 858 870 871 +3 858 865 861 +3 860 861 865 +3 858 874 871 +3 870 871 874 +3 858 866 870 +3 865 870 866 +3 865 874 871 +3 858 874 865 +3 861 874 865 +3 863 867 868 +3 859 867 863 +3 859 868 867 +3 867 872 868 +3 859 872 867 +3 859 868 872 +3 862 867 863 +3 861 865 864 +3 860 864 865 +3 864 865 871 +3 860 864 871 +3 860 871 865 +3 864 874 865 +3 861 874 864 +3 862 869 863 +3 863 869 867 +3 863 883 869 +3 862 883 863 +3 862 869 883 +3 870 874 877 +3 862 870 877 +3 862 877 874 +3 862 883 873 +3 862 873 863 +3 863 873 883 +3 873 877 883 +3 862 883 877 +3 862 877 873 +3 874 883 877 +3 862 883 874 +3 869 883 874 +3 863 873 868 +3 868 873 876 +3 863 868 876 +3 863 876 873 +3 863 872 879 +3 868 879 872 +3 863 879 868 +3 863 868 872 +3 873 883 876 +3 863 876 883 +3 863 883 879 +3 863 879 869 +3 869 879 883 +3 867 872 869 +3 863 872 867 +3 863 869 872 +3 876 883 879 +3 863 876 879 +3 869 872 879 +3 868 876 879 +3 864 874 871 +3 864 874 875 +3 864 875 871 +3 871 875 874 +3 865 871 866 +3 866 871 870 +3 870 878 871 +3 866 871 878 +3 866 878 870 +3 867 872 879 +3 867 879 869 +3 872 876 879 +3 868 876 872 +3 874 886 883 +3 869 883 886 +3 869 886 874 +3 879 883 886 +3 869 879 886 +3 870 882 888 +3 870 888 887 +3 870 887 882 +3 882 887 888 +3 870 877 887 +3 877 888 887 +3 870 888 877 +3 870 874 887 +3 874 883 887 +3 870 887 883 +3 870 883 874 +3 870 882 874 +3 870 871 882 +3 871 874 882 +3 874 887 882 +3 870 882 878 +3 870 878 888 +3 878 882 888 +3 870 883 877 +3 877 887 883 +3 871 882 878 +3 871 875 882 +3 874 882 875 +3 872 881 879 +3 876 879 881 +3 872 876 881 +3 873 884 883 +3 873 880 884 +3 880 883 884 +3 873 883 880 +3 873 884 876 +3 876 884 883 +3 873 877 880 +3 877 883 880 +3 875 887 882 +3 874 887 875 +3 883 887 886 +3 874 886 887 +3 881 884 883 +3 876 881 883 +3 876 884 881 +3 879 881 883 +3 877 883 888 +3 877 891 883 +3 883 891 888 +3 877 888 891 +3 883 888 887 +3 880 891 883 +3 877 891 880 +3 878 882 894 +3 878 894 888 +3 882 888 894 +3 883 886 885 +3 879 885 886 +3 879 883 885 +3 879 881 885 +3 881 883 885 +3 880 883 893 +3 883 884 893 +3 880 893 884 +3 880 891 892 +3 891 893 892 +3 880 892 893 +3 880 893 891 +3 883 893 891 +3 883 885 889 +3 881 883 889 +3 881 889 885 +3 881 884 889 +3 883 889 884 +3 881 890 885 +3 881 889 890 +3 885 890 889 +3 882 887 894 +3 887 888 894 +3 882 887 898 +3 882 898 894 +3 887 894 898 +3 883 900 906 +3 883 906 891 +3 883 891 900 +3 891 906 900 +3 883 886 895 +3 885 895 886 +3 883 895 885 +3 883 897 887 +3 883 888 897 +3 887 897 888 +3 883 897 895 +3 886 895 897 +3 883 886 897 +3 883 897 891 +3 883 906 897 +3 891 897 906 +3 883 893 900 +3 891 900 893 +3 888 897 891 +3 883 895 889 +3 885 889 895 +3 884 893 889 +3 883 889 893 +3 889 893 895 +3 883 895 893 +3 886 897 887 +3 893 900 895 +3 883 895 900 +3 883 895 906 +3 895 900 906 +3 895 906 897 +3 889 895 890 +3 885 890 895 +3 887 897 898 +3 887 894 897 +3 894 898 897 +3 888 894 897 +3 888 894 909 +3 894 910 909 +3 888 909 910 +3 888 910 894 +3 897 915 910 +3 888 915 897 +3 888 910 915 +3 888 897 910 +3 888 903 915 +3 888 915 909 +3 888 909 903 +3 903 909 915 +3 888 902 903 +3 902 909 903 +3 888 909 902 +3 891 903 915 +3 888 903 891 +3 888 891 915 +3 894 897 910 +3 891 915 897 +3 894 909 902 +3 888 894 902 +3 909 910 915 +3 889 901 895 +3 889 900 901 +3 895 901 900 +3 889 895 900 +3 889 893 900 +3 889 896 901 +3 896 900 901 +3 889 900 896 +3 895 896 901 +3 889 896 895 +3 890 896 895 +3 889 896 890 +3 891 915 904 +3 891 906 915 +3 904 915 906 +3 891 904 906 +3 891 904 892 +3 892 904 893 +3 891 893 904 +3 891 899 892 +3 892 899 904 +3 891 904 899 +3 899 915 904 +3 891 915 899 +3 899 903 915 +3 891 903 899 +3 897 906 915 +3 891 904 900 +3 900 904 906 +3 893 904 900 +3 894 907 909 +3 894 898 907 +3 898 909 907 +3 894 909 898 +3 894 898 910 +3 897 910 898 +3 898 910 909 +3 895 901 906 +3 900 906 901 +3 896 905 901 +3 900 901 905 +3 896 900 905 +3 906 915 910 +3 897 906 910 +3 898 910 907 +3 907 910 909 +3 899 913 912 +3 899 912 915 +3 899 915 913 +3 912 913 915 +3 904 908 912 +3 899 908 904 +3 899 912 908 +3 899 904 912 +3 904 912 915 +3 899 903 913 +3 903 915 913 +3 899 913 908 +3 908 913 912 +3 905 914 906 +3 900 905 906 +3 900 914 905 +3 900 906 914 +3 900 906 912 +3 900 912 914 +3 906 914 912 +3 901 905 906 +3 900 904 912 +3 904 906 912 +3 902 915 909 +3 902 909 923 +3 902 923 915 +3 909 915 923 +3 902 923 925 +3 902 916 923 +3 916 925 923 +3 902 925 916 +3 902 925 922 +3 916 922 925 +3 902 922 916 +3 903 916 915 +3 902 903 915 +3 902 916 903 +3 902 915 916 +3 915 916 923 +3 903 916 913 +3 913 916 915 +3 906 912 915 +3 905 917 906 +3 906 917 914 +3 905 914 917 +3 914 919 917 +3 906 919 914 +3 906 917 919 +3 906 914 915 +3 912 915 914 +3 906 915 919 +3 906 919 910 +3 910 919 915 +3 914 915 919 +3 907 911 909 +3 909 911 910 +3 907 910 911 +3 908 913 924 +3 908 924 912 +3 912 924 913 +3 913 924 921 +3 908 921 924 +3 908 913 921 +3 918 920 923 +3 909 923 920 +3 909 918 923 +3 909 920 918 +3 915 923 920 +3 909 915 920 +3 909 910 920 +3 910 915 920 +3 909 920 911 +3 909 911 918 +3 911 920 918 +3 910 920 911 +3 915 927 919 +3 910 927 915 +3 910 919 927 +3 910 927 920 +3 915 920 927 +3 912 928 915 +3 912 915 924 +3 912 924 928 +3 915 928 924 +3 913 915 924 +3 914 928 915 +3 912 928 914 +3 913 933 924 +3 915 924 933 +3 913 915 933 +3 916 933 926 +3 913 926 933 +3 913 916 926 +3 913 933 916 +3 915 933 916 +3 913 926 929 +3 926 933 929 +3 913 929 933 +3 924 929 933 +3 913 929 924 +3 921 926 929 +3 913 921 929 +3 913 926 921 +3 921 929 924 +3 914 919 928 +3 914 928 917 +3 917 928 919 +3 915 919 928 +3 915 933 928 +3 919 928 933 +3 915 919 933 +3 916 923 933 +3 915 933 923 +3 915 933 930 +3 923 930 933 +3 915 930 923 +3 924 933 928 +3 915 933 927 +3 927 933 930 +3 915 927 930 +3 919 933 927 +3 915 920 930 +3 920 927 930 +3 920 930 923 +3 916 935 933 +3 916 933 922 +3 916 922 935 +3 922 933 935 +3 916 925 933 +3 923 933 925 +3 916 935 926 +3 926 935 933 +3 922 925 933 +3 917 928 932 +3 917 932 919 +3 919 932 928 +3 918 930 920 +3 918 920 934 +3 918 934 930 +3 920 930 934 +3 918 930 923 +3 928 933 932 +3 919 932 933 +3 919 941 927 +3 919 933 941 +3 927 941 933 +3 919 932 941 +3 932 933 941 +3 919 932 927 +3 927 932 941 +3 927 930 934 +3 920 927 934 +3 921 931 929 +3 921 926 931 +3 926 929 931 +3 922 936 937 +3 922 935 936 +3 935 937 936 +3 922 937 935 +3 922 936 933 +3 925 933 936 +3 922 925 936 +3 933 935 936 +3 925 936 937 +3 922 925 937 +3 923 940 936 +3 933 936 940 +3 923 936 933 +3 923 933 940 +3 930 933 940 +3 923 930 940 +3 923 936 925 +3 924 938 933 +3 924 929 938 +3 929 933 938 +3 924 942 928 +3 924 933 942 +3 928 942 933 +3 933 942 938 +3 924 938 942 +3 926 931 933 +3 926 945 931 +3 931 945 933 +3 926 933 945 +3 926 935 945 +3 933 945 935 +3 929 931 933 +3 927 941 934 +3 927 934 946 +3 927 946 941 +3 934 941 946 +3 927 946 930 +3 930 946 933 +3 927 933 946 +3 933 946 941 +3 930 934 946 +3 928 941 933 +3 928 942 941 +3 933 941 942 +3 932 944 942 +3 928 942 944 +3 928 932 942 +3 928 944 932 +3 932 942 941 +3 928 932 941 +3 929 938 931 +3 929 939 938 +3 931 938 939 +3 929 931 939 +3 931 933 938 +3 930 940 934 +3 930 943 940 +3 934 940 943 +3 930 934 943 +3 934 946 940 +3 930 940 946 +3 933 940 946 +3 931 945 938 +3 933 938 945 +3 931 945 939 +3 938 939 945 +3 932 944 941 +3 941 944 942 +3 933 942 958 +3 938 958 942 +3 933 958 938 +3 933 949 936 +3 935 936 949 +3 933 935 949 +3 951 957 955 +3 933 957 951 +3 933 955 957 +3 933 951 955 +3 933 940 955 +3 933 955 946 +3 940 946 955 +3 933 957 949 +3 933 949 958 +3 933 958 957 +3 949 957 958 +3 940 955 957 +3 933 940 957 +3 951 958 957 +3 933 958 951 +3 941 951 946 +3 933 951 941 +3 933 946 951 +3 935 949 945 +3 933 945 949 +3 945 949 958 +3 933 945 958 +3 946 951 955 +3 936 940 957 +3 933 936 957 +3 936 957 949 +3 933 951 942 +3 941 942 951 +3 942 958 951 +3 938 945 958 +3 940 943 946 +3 934 946 943 +3 936 949 937 +3 935 937 949 +3 936 957 950 +3 936 950 954 +3 936 954 957 +3 950 957 954 +3 936 954 949 +3 949 954 957 +3 948 950 954 +3 936 948 954 +3 936 950 948 +3 940 957 950 +3 936 940 950 +3 936 948 937 +3 937 948 949 +3 936 949 948 +3 948 954 949 +3 938 958 953 +3 942 953 958 +3 938 953 942 +3 938 953 945 +3 945 953 947 +3 938 945 947 +3 938 947 953 +3 938 939 947 +3 939 945 947 +3 945 958 953 +3 940 955 952 +3 950 952 955 +3 940 952 950 +3 940 950 955 +3 940 946 952 +3 946 955 952 +3 950 955 957 +3 940 943 952 +3 943 946 952 +3 942 951 944 +3 941 944 951 +3 942 951 956 +3 944 956 951 +3 942 956 944 +3 953 958 956 +3 942 956 958 +3 942 953 956 +3 951 956 958 +3 951 958 955 +3 955 958 957 +4 0 36 13 1 +4 5 36 0 2 +4 6 0 13 1 +4 6 36 13 0 +4 7 10 36 0 +4 36 6 5 0 +4 7 0 36 2 +4 36 10 1 0 +4 20 32 10 1 +4 13 36 32 1 +4 10 32 36 1 +4 3 23 2 8 +4 36 23 2 22 +4 22 5 2 36 +4 23 3 2 22 +4 2 23 7 8 +4 36 23 7 2 +4 2 3 4 22 +4 4 2 22 5 +4 22 4 5 18 +4 9 5 4 18 +4 40 22 5 18 +4 6 54 36 5 +4 19 18 40 5 +4 5 40 36 22 +4 19 54 5 40 +4 5 6 54 19 +4 9 19 5 18 +4 5 54 36 40 +4 54 6 43 21 +4 54 43 6 36 +4 12 43 6 21 +4 6 36 43 13 +4 21 54 6 19 +4 43 6 13 12 +4 7 23 31 8 +4 11 7 36 31 +4 36 7 23 31 +4 10 36 11 7 +4 16 11 7 8 +4 7 8 31 16 +4 31 11 7 16 +4 8 23 31 16 +4 30 9 17 18 +4 30 19 17 9 +4 30 19 9 18 +4 50 20 32 10 +4 20 50 29 10 +4 36 25 10 11 +4 36 10 29 50 +4 25 10 29 36 +4 50 32 36 10 +4 31 15 11 16 +4 15 25 31 11 +4 11 15 14 16 +4 36 31 25 11 +4 21 12 38 26 +4 21 12 43 38 +4 43 36 32 13 +4 15 24 14 28 +4 15 28 14 31 +4 14 15 31 16 +4 15 47 28 31 +4 47 25 15 28 +4 24 15 25 28 +4 25 47 15 31 +4 17 30 27 19 +4 18 30 19 40 +4 30 19 54 42 +4 19 27 33 30 +4 42 19 33 30 +4 33 54 19 42 +4 40 19 54 30 +4 54 21 33 19 +4 50 29 51 20 +4 38 54 21 35 +4 21 54 33 35 +4 35 38 26 21 +4 43 54 21 38 +4 41 36 22 23 +4 36 40 41 22 +4 23 41 36 31 +4 28 37 24 34 +4 25 37 24 28 +4 36 29 25 50 +4 31 25 47 36 +4 48 37 25 47 +4 47 37 25 28 +4 29 50 47 25 +4 37 29 48 25 +4 29 47 48 25 +4 36 47 50 25 +4 39 38 26 35 +4 42 33 27 30 +4 49 33 27 42 +4 33 27 45 49 +4 47 34 37 28 +4 48 29 51 50 +4 50 47 48 29 +4 54 40 30 42 +4 36 41 47 31 +4 50 32 64 36 +4 43 36 64 32 +4 46 33 54 35 +4 45 33 49 42 +4 33 45 54 42 +4 33 54 45 46 +4 34 37 44 53 +4 34 47 37 53 +4 57 38 39 35 +4 52 57 35 46 +4 35 57 54 46 +4 38 54 35 57 +4 39 57 35 52 +4 64 63 36 54 +4 63 67 36 41 +4 67 50 64 36 +4 36 41 67 47 +4 63 36 54 40 +4 36 67 50 47 +4 36 54 43 64 +4 63 67 64 36 +4 63 41 36 40 +4 37 47 61 53 +4 48 47 61 37 +4 37 48 58 53 +4 37 44 53 58 +4 61 48 37 53 +4 38 43 54 57 +4 57 39 55 52 +4 72 54 59 40 +4 54 72 63 40 +4 42 54 40 59 +4 42 49 45 59 +4 59 54 45 42 +4 75 54 64 43 +4 75 54 43 57 +4 59 62 56 45 +4 49 59 56 45 +4 46 45 59 54 +4 45 59 62 46 +4 65 57 52 46 +4 65 54 57 46 +4 65 54 46 62 +4 46 59 62 54 +4 61 50 67 47 +4 50 48 47 61 +4 69 68 51 48 +4 48 51 69 50 +4 61 48 69 50 +4 73 48 51 68 +4 58 48 61 53 +4 61 48 68 69 +4 61 58 68 48 +4 66 59 56 49 +4 50 69 61 67 +4 69 50 64 67 +4 68 69 51 73 +4 57 60 65 52 +4 57 55 60 52 +4 74 53 58 61 +4 75 72 54 79 +4 66 79 54 59 +4 54 79 72 59 +4 54 64 63 75 +4 54 79 62 65 +4 66 59 54 62 +4 54 75 70 57 +4 54 75 79 65 +4 54 75 63 72 +4 54 79 66 62 +4 75 70 65 54 +4 70 54 57 65 +4 55 70 57 60 +4 62 66 59 56 +4 62 66 56 76 +4 60 70 57 65 +4 58 61 68 74 +4 60 71 70 65 +4 88 74 68 61 +4 61 88 67 69 +4 61 77 67 88 +4 74 88 77 61 +4 68 69 88 61 +4 65 78 79 62 +4 62 78 79 66 +4 62 76 78 66 +4 75 64 63 72 +4 84 63 64 89 +4 67 63 64 84 +4 89 63 64 72 +4 72 84 89 63 +4 64 84 90 67 +4 90 64 67 69 +4 64 89 72 75 +4 64 84 89 90 +4 80 78 70 65 +4 78 79 70 65 +4 79 70 65 75 +4 65 71 70 80 +4 78 76 79 66 +4 67 90 88 84 +4 92 84 67 88 +4 69 67 90 88 +4 67 92 88 77 +4 74 88 68 81 +4 88 83 68 82 +4 83 69 88 68 +4 68 83 69 73 +4 81 88 68 82 +4 68 83 73 82 +4 69 88 90 83 +4 78 86 80 70 +4 79 86 78 70 +4 79 86 70 75 +4 70 71 86 80 +4 75 95 72 79 +4 72 95 89 84 +4 72 95 75 89 +4 87 73 83 82 +4 85 88 77 74 +4 74 85 88 81 +4 89 95 75 98 +4 86 95 75 79 +4 98 95 75 86 +4 100 79 78 76 +4 88 85 77 92 +4 86 94 78 80 +4 94 78 100 79 +4 86 78 94 79 +4 95 79 94 100 +4 95 86 94 79 +4 80 86 94 103 +4 91 85 81 93 +4 81 85 88 93 +4 82 81 88 93 +4 81 91 93 96 +4 87 83 101 82 +4 101 83 88 82 +4 82 88 101 93 +4 104 83 88 101 +4 90 104 83 88 +4 104 83 101 97 +4 97 83 101 87 +4 88 90 105 84 +4 109 84 115 95 +4 109 105 84 112 +4 84 115 105 109 +4 84 105 88 92 +4 115 89 84 105 +4 84 90 105 89 +4 84 95 89 115 +4 112 105 84 92 +4 96 88 85 93 +4 85 99 96 91 +4 92 88 85 99 +4 99 88 85 96 +4 96 85 91 93 +4 98 94 86 103 +4 95 98 94 86 +4 88 106 113 93 +4 99 106 88 93 +4 88 99 110 105 +4 99 92 88 110 +4 113 105 88 104 +4 88 113 104 101 +4 96 99 88 93 +4 106 99 88 113 +4 101 88 113 93 +4 105 88 99 113 +4 88 90 104 105 +4 110 92 88 105 +4 90 105 89 107 +4 98 89 95 115 +4 115 107 89 105 +4 107 115 89 118 +4 115 98 89 118 +4 104 90 116 105 +4 90 107 116 105 +4 102 96 99 91 +4 92 105 110 112 +4 106 99 96 93 +4 95 98 114 94 +4 100 95 122 94 +4 94 98 114 103 +4 94 95 122 114 +4 119 115 95 139 +4 115 109 95 139 +4 98 115 95 114 +4 100 95 119 122 +4 122 115 114 95 +4 95 115 119 122 +4 96 99 106 102 +4 101 104 97 108 +4 115 98 118 117 +4 117 115 98 114 +4 98 117 114 103 +4 106 110 99 113 +4 110 106 99 111 +4 105 99 110 113 +4 111 106 99 102 +4 122 119 100 137 +4 127 108 101 113 +4 108 101 104 127 +4 113 104 101 127 +4 104 144 116 127 +4 144 127 104 113 +4 105 144 116 104 +4 113 144 105 104 +4 116 148 162 105 +4 110 113 145 105 +4 105 107 162 174 +4 109 105 112 140 +4 109 115 105 140 +4 140 115 105 175 +4 107 148 116 105 +4 105 115 174 162 +4 148 107 162 105 +4 175 162 105 163 +4 175 115 105 162 +4 140 175 105 163 +4 105 144 162 116 +4 105 112 163 145 +4 162 144 105 145 +4 110 105 145 112 +4 107 115 174 105 +4 162 105 163 145 +4 112 105 163 140 +4 144 105 145 113 +4 106 111 110 120 +4 120 113 110 106 +4 107 146 148 162 +4 146 115 174 107 +4 162 107 146 174 +4 118 115 146 107 +4 156 109 115 139 +4 140 109 115 156 +4 145 110 112 155 +4 113 145 120 110 +4 155 145 110 131 +4 120 111 110 131 +4 120 110 145 131 +4 147 110 131 155 +4 112 110 147 155 +4 155 163 112 145 +4 163 112 147 155 +4 163 112 140 147 +4 153 117 114 167 +4 169 167 122 114 +4 167 169 117 114 +4 115 169 122 114 +4 117 169 115 114 +4 115 139 119 189 +4 189 115 139 194 +4 115 140 156 175 +4 118 169 115 117 +4 139 115 179 194 +4 169 192 115 122 +4 174 115 192 175 +4 169 118 115 192 +4 175 174 115 162 +4 115 156 139 179 +4 179 115 175 194 +4 146 115 118 174 +4 174 115 118 192 +4 175 115 192 194 +4 119 115 189 122 +4 122 192 115 194 +4 156 115 175 179 +4 115 194 189 122 +4 162 144 152 116 +4 152 116 148 162 +4 116 144 152 127 +4 169 167 117 153 +4 118 146 174 183 +4 174 118 183 192 +4 169 183 118 192 +4 185 119 189 122 +4 137 119 185 122 +4 126 150 125 121 +4 150 126 135 121 +4 167 169 122 166 +4 122 189 185 166 +4 122 169 192 166 +4 122 194 189 166 +4 166 194 192 122 +4 185 137 122 166 +4 176 177 123 126 +4 132 138 123 150 +4 123 138 125 150 +4 197 123 124 128 +4 132 123 177 150 +4 123 197 176 126 +4 126 123 197 128 +4 177 197 176 123 +4 123 132 197 124 +4 123 150 125 126 +4 138 132 123 125 +4 123 150 126 177 +4 132 197 177 123 +4 124 180 133 157 +4 133 130 124 157 +4 129 136 124 161 +4 129 161 124 180 +4 124 129 180 130 +4 180 124 130 157 +4 124 161 134 180 +4 124 197 180 134 +4 124 197 128 133 +4 124 136 134 161 +4 124 132 197 134 +4 197 124 180 133 +4 126 197 176 128 +4 177 150 126 176 +4 142 135 176 126 +4 126 150 135 176 +4 176 126 128 142 +4 135 143 126 142 +4 128 197 151 133 +4 159 197 128 142 +4 128 197 176 142 +4 197 128 151 159 +4 141 133 157 130 +4 138 132 177 150 +4 132 219 134 149 +4 164 219 132 149 +4 197 219 132 164 +4 219 134 197 132 +4 164 197 177 132 +4 149 138 132 164 +4 132 164 138 177 +4 157 151 133 141 +4 157 197 180 133 +4 151 197 157 133 +4 161 180 197 134 +4 158 134 136 161 +4 134 219 182 149 +4 161 197 158 134 +4 158 182 149 134 +4 158 219 182 134 +4 197 219 158 134 +4 135 176 143 142 +4 158 136 171 161 +4 137 166 185 168 +4 189 184 194 139 +4 156 139 179 184 +4 139 194 179 184 +4 140 156 175 173 +4 140 163 147 173 +4 173 140 156 165 +4 140 173 170 165 +4 163 140 175 173 +4 170 140 147 173 +4 141 157 151 160 +4 142 176 154 159 +4 143 176 154 142 +4 176 197 159 142 +4 183 146 174 172 +4 162 174 146 172 +4 148 162 146 172 +4 170 147 163 173 +4 181 164 149 182 +4 164 182 219 149 +4 195 151 197 157 +4 157 195 151 160 +4 151 197 190 195 +4 151 195 190 178 +4 197 190 159 151 +4 195 178 151 160 +4 153 169 167 188 +4 191 159 186 154 +4 154 176 191 159 +4 173 156 179 165 +4 156 175 173 179 +4 197 195 157 180 +4 197 219 161 158 +4 205 198 158 219 +4 171 158 161 198 +4 198 158 161 205 +4 198 171 158 193 +4 219 205 161 158 +4 219 182 187 158 +4 219 198 158 187 +4 158 198 193 187 +4 159 199 197 191 +4 199 159 186 191 +4 190 199 197 159 +4 176 197 191 159 +4 195 178 160 200 +4 205 180 197 161 +4 197 205 161 219 +4 182 181 164 202 +4 197 202 219 164 +4 202 197 177 164 +4 202 182 219 164 +4 166 207 185 196 +4 207 214 166 185 +4 185 166 196 168 +4 166 194 189 214 +4 166 189 185 214 +4 167 192 169 166 +4 214 207 166 167 +4 166 192 214 167 +4 194 192 214 166 +4 214 201 207 167 +4 217 167 188 201 +4 214 167 217 201 +4 192 169 214 167 +4 169 214 167 188 +4 167 214 217 188 +4 183 169 215 192 +4 217 214 169 188 +4 214 215 217 169 +4 192 215 214 169 +4 191 212 197 176 +4 212 197 176 177 +4 197 212 202 177 +4 190 195 200 178 +4 234 205 180 197 +4 197 234 195 180 +4 202 181 221 182 +4 182 221 208 181 +4 182 210 219 187 +4 182 208 221 210 +4 182 219 221 202 +4 210 219 221 182 +4 184 189 194 206 +4 185 207 214 223 +4 185 223 218 196 +4 196 207 185 223 +4 185 189 223 214 +4 186 199 191 213 +4 186 225 199 213 +4 187 209 198 193 +4 187 210 219 209 +4 219 209 198 187 +4 188 217 201 216 +4 216 201 188 203 +4 189 206 223 230 +4 214 189 223 230 +4 214 206 189 230 +4 206 194 214 189 +4 197 229 190 195 +4 195 229 190 200 +4 229 200 227 190 +4 229 199 197 190 +4 227 229 190 199 +4 191 197 233 199 +4 191 233 213 225 +4 197 233 212 191 +4 191 199 225 213 +4 225 191 233 199 +4 198 193 211 204 +4 193 209 198 211 +4 229 197 234 195 +4 196 223 218 207 +4 196 235 207 218 +4 259 212 197 233 +4 229 234 197 246 +4 197 225 233 199 +4 202 197 219 212 +4 197 274 259 246 +4 225 197 233 246 +4 219 234 259 197 +4 241 197 259 212 +4 234 274 259 197 +4 197 234 205 219 +4 199 246 229 197 +4 241 219 259 197 +4 225 246 199 197 +4 234 274 197 246 +4 259 197 246 233 +4 241 219 197 212 +4 198 219 220 228 +4 228 209 211 198 +4 219 236 198 220 +4 205 219 236 198 +4 209 228 219 198 +4 211 228 198 220 +4 220 204 198 211 +4 246 229 227 199 +4 251 214 217 201 +4 207 201 251 231 +4 201 216 231 232 +4 207 214 251 201 +4 217 251 201 216 +4 232 201 203 231 +4 201 216 232 203 +4 201 216 251 231 +4 202 219 241 212 +4 221 219 241 202 +4 220 211 226 204 +4 219 234 205 256 +4 205 219 256 236 +4 218 235 207 248 +4 248 214 251 207 +4 207 248 214 223 +4 251 248 207 235 +4 207 231 251 245 +4 251 207 245 235 +4 223 248 218 207 +4 222 221 208 210 +4 221 224 222 208 +4 210 239 219 209 +4 228 239 209 219 +4 239 219 238 210 +4 238 219 221 210 +4 210 222 221 238 +4 211 228 220 226 +4 213 233 250 225 +4 251 214 215 217 +4 223 248 214 230 +4 217 215 251 258 +4 217 253 258 216 +4 251 258 253 216 +4 231 216 253 232 +4 231 251 253 216 +4 217 258 251 216 +4 235 218 255 248 +4 223 218 248 255 +4 218 252 235 255 +4 236 219 242 228 +4 219 260 239 238 +4 219 256 289 234 +4 219 260 277 270 +4 244 219 221 238 +4 277 259 241 219 +4 241 260 219 244 +4 244 260 219 238 +4 219 241 244 221 +4 289 219 234 259 +4 239 260 219 270 +4 263 270 242 219 +4 219 263 256 236 +4 277 260 219 241 +4 236 220 219 228 +4 242 239 219 270 +4 242 219 239 228 +4 270 263 256 219 +4 242 263 219 236 +4 219 277 259 289 +4 219 277 289 270 +4 219 270 289 256 +4 228 220 226 237 +4 220 228 242 237 +4 236 228 242 220 +4 220 242 236 237 +4 221 222 224 238 +4 238 244 224 221 +4 224 222 240 238 +4 248 223 255 243 +4 230 223 248 243 +4 240 244 224 238 +4 225 233 250 246 +4 229 246 227 257 +4 274 229 257 246 +4 274 234 229 246 +4 231 253 249 232 +4 249 245 253 231 +4 245 251 253 231 +4 265 233 246 250 +4 246 233 265 259 +4 234 281 256 289 +4 298 234 259 289 +4 274 298 234 259 +4 234 274 281 298 +4 289 234 281 298 +4 248 251 245 235 +4 245 280 248 235 +4 255 252 235 280 +4 255 248 280 235 +4 280 252 235 267 +4 235 252 266 267 +4 245 280 235 267 +4 237 242 236 247 +4 236 263 256 261 +4 236 242 263 261 +4 261 236 242 247 +4 238 260 254 244 +4 240 254 244 238 +4 277 244 260 241 +4 259 241 271 277 +4 241 244 271 277 +4 261 242 263 247 +4 255 248 243 262 +4 244 260 254 277 +4 254 244 271 264 +4 277 244 271 254 +4 245 269 272 267 +4 280 283 245 251 +4 280 251 245 248 +4 251 283 245 253 +4 272 245 267 283 +4 249 245 272 253 +4 245 272 269 249 +4 283 245 267 280 +4 283 272 245 253 +4 257 275 274 246 +4 298 265 246 275 +4 275 298 274 246 +4 259 274 298 246 +4 246 265 298 259 +4 246 265 250 275 +4 255 248 273 280 +4 273 248 255 262 +4 268 265 275 250 +4 283 251 258 253 +4 255 278 252 273 +4 273 252 280 278 +4 252 276 266 267 +4 255 252 280 273 +4 280 252 267 276 +4 278 252 280 276 +4 253 283 272 282 +4 283 258 282 253 +4 277 260 254 264 +4 277 254 271 264 +4 273 255 278 262 +4 256 270 289 279 +4 256 279 289 292 +4 256 281 279 292 +4 289 281 256 292 +4 279 256 270 263 +4 279 256 263 261 +4 275 274 294 257 +4 257 294 275 285 +4 286 295 259 290 +4 259 284 265 295 +4 259 289 295 298 +4 295 259 284 286 +4 259 271 290 277 +4 290 295 259 289 +4 290 259 277 289 +4 259 265 298 295 +4 271 286 259 290 +4 295 284 265 305 +4 291 268 265 275 +4 291 298 265 305 +4 298 265 275 317 +4 298 291 265 317 +4 291 265 284 305 +4 295 265 298 305 +4 275 265 291 317 +4 267 276 266 300 +4 297 266 276 300 +4 283 267 269 287 +4 267 300 311 303 +4 267 269 272 283 +4 300 267 310 287 +4 311 276 267 303 +4 310 283 267 280 +4 267 280 276 311 +4 287 283 267 310 +4 267 310 311 300 +4 303 276 267 300 +4 311 267 280 310 +4 301 268 288 304 +4 268 291 288 275 +4 291 301 268 288 +4 272 269 287 283 +4 269 272 306 293 +4 269 306 287 293 +4 269 272 287 306 +4 282 283 272 306 +4 306 283 272 310 +4 306 272 287 310 +4 287 272 283 310 +4 299 281 274 298 +4 274 316 298 294 +4 298 274 294 275 +4 308 316 298 274 +4 308 274 298 299 +4 308 316 274 294 +4 294 316 298 275 +4 317 314 275 316 +4 275 291 314 317 +4 275 316 307 294 +4 307 275 294 285 +4 316 314 275 307 +4 316 317 298 275 +4 275 314 288 307 +4 288 291 314 275 +4 311 278 276 303 +4 297 276 303 300 +4 280 278 276 311 +4 303 302 311 278 +4 298 299 281 292 +4 292 289 281 298 +4 282 306 313 283 +4 310 306 283 313 +4 307 294 319 285 +4 296 307 319 285 +4 306 325 287 293 +4 306 331 310 287 +4 321 287 325 309 +4 325 331 306 287 +4 287 331 321 325 +4 300 287 331 321 +4 293 325 287 309 +4 287 310 300 331 +4 324 288 314 307 +4 314 288 324 304 +4 301 291 314 288 +4 301 288 314 304 +4 315 322 291 318 +4 314 291 318 317 +4 318 322 291 301 +4 291 318 301 314 +4 291 317 305 318 +4 291 318 305 315 +4 298 317 305 291 +4 294 319 316 307 +4 317 295 298 305 +4 305 317 295 318 +4 307 312 296 319 +4 323 300 320 297 +4 303 323 297 300 +4 331 339 300 321 +4 332 339 300 338 +4 339 300 310 331 +4 300 339 303 323 +4 300 339 311 303 +4 338 339 300 323 +4 321 339 300 332 +4 300 332 338 320 +4 300 310 311 339 +4 338 300 320 323 +4 304 327 314 301 +4 301 327 314 322 +4 322 314 301 318 +4 311 326 302 303 +4 339 311 303 323 +4 303 311 326 323 +4 314 324 333 304 +4 333 314 304 327 +4 328 324 304 333 +4 313 306 331 310 +4 329 331 306 325 +4 313 331 306 329 +4 341 334 307 314 +4 342 312 307 319 +4 342 307 359 334 +4 312 307 335 342 +4 342 307 335 359 +4 316 319 334 307 +4 334 342 307 319 +4 307 341 324 359 +4 307 334 316 314 +4 335 307 324 359 +4 341 359 307 334 +4 341 324 314 307 +4 309 325 321 330 +4 339 326 311 323 +4 322 327 314 336 +4 314 333 336 327 +4 324 333 360 314 +4 314 334 316 317 +4 314 324 341 360 +4 341 317 314 318 +4 322 336 314 318 +4 333 347 314 336 +4 347 360 333 314 +4 336 341 314 318 +4 341 334 314 317 +4 347 341 314 336 +4 341 314 360 347 +4 334 346 342 319 +4 332 337 338 320 +4 343 348 365 321 +4 365 340 366 321 +4 321 325 343 330 +4 331 365 339 321 +4 365 366 339 321 +4 343 365 331 321 +4 325 343 331 321 +4 351 348 330 321 +4 321 340 366 339 +4 321 348 365 340 +4 332 340 321 339 +4 321 351 348 340 +4 330 348 343 321 +4 323 353 339 326 +4 338 339 323 353 +4 335 324 363 359 +4 333 324 360 328 +4 349 345 328 324 +4 335 324 345 363 +4 324 360 345 363 +4 360 324 359 363 +4 360 345 349 324 +4 328 360 349 324 +4 359 341 324 360 +4 329 343 331 325 +4 330 325 343 348 +4 336 333 347 327 +4 360 328 349 333 +4 345 349 328 356 +4 343 354 329 331 +4 351 348 350 330 +4 365 354 343 331 +4 355 344 332 362 +4 366 340 332 339 +4 344 332 337 355 +4 338 332 366 367 +4 340 332 386 366 +4 337 332 338 355 +4 362 332 386 340 +4 386 332 367 366 +4 332 366 339 338 +4 332 367 355 386 +4 332 355 362 386 +4 367 338 332 355 +4 333 360 347 357 +4 349 360 333 357 +4 346 342 359 334 +4 345 363 361 335 +4 364 342 335 358 +4 352 342 335 364 +4 361 335 363 352 +4 363 335 359 342 +4 342 363 335 358 +4 364 363 335 352 +4 358 363 335 364 +4 338 366 339 353 +4 366 367 353 338 +4 386 340 366 365 +4 340 351 386 375 +4 340 365 386 351 +4 365 340 348 351 +4 362 386 375 340 +4 368 363 342 358 +4 346 359 342 368 +4 368 342 346 358 +4 359 363 342 368 +4 343 365 369 354 +4 348 365 369 343 +4 372 355 362 344 +4 362 372 344 376 +4 361 385 345 425 +4 374 371 345 356 +4 356 349 371 345 +4 345 361 363 385 +4 361 345 370 415 +4 363 345 385 360 +4 371 415 374 345 +4 425 385 345 415 +4 345 370 374 356 +4 361 425 345 415 +4 360 349 345 385 +4 345 349 371 385 +4 370 374 415 345 +4 385 345 415 371 +4 386 365 369 348 +4 369 351 348 378 +4 348 386 365 351 +4 378 351 348 350 +4 351 369 348 386 +4 385 349 371 391 +4 371 349 373 391 +4 357 349 360 373 +4 385 360 349 391 +4 373 349 360 391 +4 380 378 350 351 +4 386 351 369 378 +4 378 351 375 386 +4 351 378 375 380 +4 352 363 409 364 +4 352 399 409 379 +4 409 363 352 361 +4 399 364 352 409 +4 352 379 409 361 +4 367 392 366 353 +4 354 365 369 382 +4 367 386 372 355 +4 386 355 362 372 +4 374 377 356 370 +4 358 368 363 387 +4 364 358 363 387 +4 358 364 394 387 +4 368 359 363 397 +4 397 359 363 385 +4 363 359 360 385 +4 379 423 409 361 +4 423 361 428 425 +4 361 423 409 363 +4 361 428 400 379 +4 361 425 415 370 +4 361 379 423 428 +4 425 423 361 363 +4 428 361 400 370 +4 425 361 428 370 +4 361 425 363 385 +4 376 381 362 375 +4 375 412 386 362 +4 372 386 412 362 +4 362 375 412 376 +4 412 372 362 376 +4 387 368 363 397 +4 409 423 416 363 +4 387 363 394 397 +4 363 425 397 385 +4 409 363 394 364 +4 363 425 423 397 +4 423 363 397 416 +4 416 363 397 394 +4 409 363 416 394 +4 363 364 387 394 +4 369 365 410 382 +4 386 365 410 369 +4 365 410 366 386 +4 366 386 392 367 +4 386 392 421 366 +4 421 386 366 410 +4 386 401 367 372 +4 401 392 386 367 +4 386 410 418 369 +4 411 418 410 369 +4 411 369 410 382 +4 418 386 369 378 +4 414 370 377 374 +4 377 370 414 417 +4 374 414 370 415 +4 400 370 417 414 +4 370 428 425 414 +4 400 428 370 414 +4 425 370 414 415 +4 391 415 371 385 +4 371 374 415 407 +4 415 371 407 391 +4 372 386 401 412 +4 415 374 414 407 +4 386 441 375 380 +4 424 412 375 376 +4 441 381 424 375 +4 383 381 441 375 +4 412 441 375 386 +4 380 383 441 375 +4 386 380 375 378 +4 424 381 376 375 +4 424 441 375 412 +4 405 381 376 424 +4 402 380 430 378 +4 380 418 430 378 +4 386 418 380 378 +4 433 428 379 413 +4 379 404 428 400 +4 404 413 379 428 +4 428 379 423 409 +4 409 428 379 399 +4 379 413 399 433 +4 399 428 379 433 +4 418 441 386 380 +4 380 383 430 441 +4 380 420 430 384 +4 402 420 380 384 +4 430 441 418 380 +4 420 430 402 380 +4 430 380 384 383 +4 381 424 445 441 +4 445 381 441 383 +4 398 405 383 381 +4 405 445 383 381 +4 445 381 405 424 +4 393 383 442 384 +4 429 445 383 405 +4 445 442 429 383 +4 384 442 420 383 +4 383 398 388 429 +4 442 445 441 383 +4 442 429 383 388 +4 383 442 388 393 +4 420 442 441 383 +4 383 420 430 441 +4 429 405 383 398 +4 384 420 430 383 +4 384 390 420 393 +4 442 393 384 420 +4 435 441 386 418 +4 435 438 410 386 +4 386 412 441 421 +4 392 386 421 401 +4 438 441 386 435 +4 410 421 386 438 +4 410 435 386 418 +4 401 386 421 412 +4 441 386 421 438 +4 416 397 387 394 +4 393 388 396 442 +4 398 388 429 389 +4 422 388 442 396 +4 422 389 388 396 +4 388 442 429 422 +4 389 422 388 429 +4 422 395 389 396 +4 390 439 420 442 +4 439 393 390 406 +4 393 390 420 442 +4 442 393 390 439 +4 392 421 419 401 +4 403 442 393 404 +4 393 406 439 403 +4 396 393 442 404 +4 439 442 393 403 +4 395 396 422 408 +4 442 422 396 434 +4 408 396 422 404 +4 442 396 404 434 +4 404 396 422 434 +4 399 432 428 433 +4 399 409 428 432 +4 400 404 428 403 +4 428 400 417 414 +4 400 428 417 403 +4 401 412 421 419 +4 417 403 439 406 +4 403 460 428 447 +4 460 404 403 428 +4 403 428 417 447 +4 403 439 447 417 +4 404 442 460 403 +4 439 460 403 447 +4 460 442 439 403 +4 460 434 404 428 +4 422 408 404 434 +4 404 434 433 428 +4 434 442 460 404 +4 433 413 404 428 +4 434 413 404 433 +4 434 404 413 408 +4 414 415 407 426 +4 409 432 423 428 +4 409 431 416 423 +4 432 431 409 423 +4 418 410 427 411 +4 410 435 418 427 +4 437 441 412 421 +4 441 424 437 412 +4 412 437 421 419 +4 440 428 443 414 +4 417 447 428 414 +4 425 414 443 426 +4 428 440 425 414 +4 414 425 415 426 +4 414 447 428 443 +4 414 440 425 443 +4 443 415 425 426 +4 448 441 435 418 +4 427 435 418 448 +4 441 448 430 418 +4 421 437 436 419 +4 452 430 420 441 +4 452 439 442 420 +4 420 442 452 441 +4 421 437 441 438 +4 437 436 438 421 +4 421 450 436 438 +4 422 442 429 459 +4 434 442 422 459 +4 423 440 428 446 +4 446 423 431 428 +4 423 432 431 428 +4 440 425 423 428 +4 424 445 441 437 +4 448 427 435 444 +4 443 447 428 440 +4 440 460 428 446 +4 446 428 433 454 +4 446 460 428 454 +4 428 447 460 440 +4 446 431 432 428 +4 428 460 434 433 +4 428 432 446 433 +4 433 428 460 454 +4 429 442 445 467 +4 467 429 442 459 +4 473 452 441 430 +4 473 441 448 430 +4 446 432 431 451 +4 454 446 432 433 +4 451 446 432 454 +4 434 460 463 433 +4 433 460 463 454 +4 459 442 460 434 +4 459 460 463 434 +4 453 444 464 435 +4 441 464 448 435 +4 464 438 458 435 +4 453 464 458 435 +4 464 441 438 435 +4 444 448 464 435 +4 436 457 437 438 +4 436 457 450 449 +4 438 457 450 436 +4 475 457 441 437 +4 437 445 441 475 +4 438 437 441 457 +4 441 438 457 482 +4 482 438 457 450 +4 438 458 482 464 +4 458 482 450 438 +4 482 441 438 464 +4 460 439 468 470 +4 439 468 442 460 +4 470 460 439 447 +4 439 468 452 442 +4 446 440 460 456 +4 460 440 443 456 +4 443 460 447 440 +4 473 475 441 452 +4 441 471 482 457 +4 482 441 473 475 +4 441 467 475 445 +4 441 473 448 482 +4 475 471 441 457 +4 471 482 475 441 +4 452 467 475 441 +4 452 467 441 445 +4 441 448 464 482 +4 445 441 452 442 +4 442 459 460 468 +4 442 468 483 467 +4 468 483 452 442 +4 442 483 452 467 +4 452 467 445 442 +4 459 467 468 442 +4 460 447 462 443 +4 443 460 456 462 +4 454 446 461 451 +4 456 446 461 454 +4 456 460 446 454 +4 460 447 470 462 +4 464 448 473 482 +4 449 457 450 455 +4 450 457 482 471 +4 466 455 450 457 +4 466 458 482 450 +4 450 471 466 457 +4 471 466 482 450 +4 479 461 451 454 +4 475 452 483 467 +4 473 452 483 475 +4 465 453 458 472 +4 464 453 458 465 +4 479 460 456 454 +4 461 479 456 454 +4 463 460 479 454 +4 471 455 466 457 +4 455 466 480 471 +4 456 460 484 462 +4 476 469 456 479 +4 456 484 469 462 +4 476 479 456 461 +4 460 479 456 469 +4 460 484 469 456 +4 458 472 466 482 +4 464 472 458 482 +4 465 472 458 464 +4 468 459 496 467 +4 468 491 496 459 +4 491 468 460 459 +4 460 491 459 463 +4 460 491 479 502 +4 491 516 460 468 +4 469 479 484 460 +4 463 491 479 460 +4 484 470 460 567 +4 516 460 470 567 +4 479 460 502 484 +4 468 516 460 470 +4 484 460 470 462 +4 460 567 491 484 +4 516 567 491 460 +4 460 484 491 502 +4 479 476 474 461 +4 462 484 469 478 +4 464 465 472 482 +4 464 481 465 482 +4 490 464 482 481 +4 490 464 473 482 +4 465 481 472 482 +4 477 481 472 465 +4 466 472 486 482 +4 466 482 486 480 +4 480 466 482 471 +4 475 483 496 467 +4 483 468 496 467 +4 491 496 516 468 +4 496 483 516 468 +4 469 559 484 476 +4 488 559 492 469 +4 469 488 559 476 +4 469 484 492 478 +4 559 484 492 469 +4 489 469 492 478 +4 469 476 484 479 +4 469 488 489 492 +4 470 516 567 484 +4 494 482 475 471 +4 494 471 480 482 +4 481 472 485 477 +4 482 481 472 485 +4 486 485 482 472 +4 509 473 482 544 +4 482 473 509 475 +4 473 544 490 482 +4 483 509 473 475 +4 476 474 487 479 +4 494 482 509 475 +4 509 539 494 475 +4 496 509 483 475 +4 509 496 539 475 +4 502 487 476 488 +4 476 488 559 502 +4 476 502 484 479 +4 487 479 502 476 +4 484 559 502 476 +4 480 494 482 549 +4 486 482 549 480 +4 480 511 549 486 +4 490 555 481 485 +4 523 481 555 485 +4 482 490 481 485 +4 482 509 544 494 +4 482 544 549 494 +4 544 555 490 482 +4 485 482 490 486 +4 490 482 555 486 +4 482 549 555 486 +4 555 544 549 482 +4 575 483 496 509 +4 516 483 496 575 +4 559 567 484 502 +4 533 567 484 559 +4 492 484 559 533 +4 484 567 491 502 +4 484 516 567 533 +4 523 555 522 485 +4 486 522 555 485 +4 485 490 555 486 +4 511 537 522 486 +4 549 522 486 511 +4 522 555 549 486 +4 553 487 488 505 +4 488 502 487 553 +4 492 521 488 489 +4 521 559 492 488 +4 488 546 521 559 +4 559 502 488 553 +4 488 553 505 546 +4 559 553 488 546 +4 521 492 530 489 +4 567 596 491 565 +4 496 516 567 491 +4 491 565 502 567 +4 567 596 496 491 +4 521 559 561 492 +4 492 530 561 521 +4 533 559 492 561 +4 560 493 504 499 +4 515 570 513 493 +4 493 508 513 515 +4 493 570 593 499 +4 497 593 493 513 +4 570 520 493 515 +4 593 493 499 497 +4 520 493 504 560 +4 513 570 593 493 +4 570 493 560 499 +4 520 493 560 570 +4 504 520 503 493 +4 539 544 494 606 +4 544 606 549 494 +4 539 544 509 494 +4 498 507 545 495 +4 499 529 593 495 +4 495 507 545 497 +4 497 593 545 495 +4 545 498 495 514 +4 514 495 529 500 +4 499 501 529 495 +4 495 545 514 529 +4 495 529 500 501 +4 495 593 545 529 +4 499 495 593 497 +4 495 507 497 498 +4 539 496 575 596 +4 516 496 567 575 +4 575 596 496 567 +4 496 575 509 539 +4 593 545 507 497 +4 519 497 513 593 +4 507 519 593 497 +4 517 507 545 498 +4 545 517 498 514 +4 499 609 584 501 +4 609 584 593 499 +4 584 529 499 501 +4 501 499 609 510 +4 560 593 570 499 +4 560 609 593 499 +4 529 593 584 499 +4 499 504 609 510 +4 504 609 560 499 +4 512 529 501 500 +4 547 584 609 501 +4 506 547 501 512 +4 547 501 510 506 +4 529 584 547 501 +4 609 547 501 510 +4 512 529 547 501 +4 559 565 502 553 +4 565 502 567 559 +4 503 560 504 526 +4 520 560 504 503 +4 503 525 560 526 +4 524 525 503 526 +4 520 525 560 503 +4 609 510 504 526 +4 504 560 609 526 +4 541 505 553 546 +4 510 547 506 527 +4 531 506 547 527 +4 512 506 547 531 +4 545 518 554 507 +4 517 545 507 518 +4 518 519 593 507 +4 518 593 554 507 +4 545 554 593 507 +4 528 570 574 508 +4 570 515 513 508 +4 574 513 508 570 +4 513 574 508 528 +4 575 629 509 539 +4 509 629 544 539 +4 609 547 510 527 +4 510 526 609 534 +4 609 510 534 527 +4 543 537 600 511 +4 549 600 537 511 +4 537 549 511 522 +4 574 513 532 528 +4 513 532 538 574 +4 538 593 519 513 +4 593 538 574 513 +4 570 593 574 513 +4 516 640 567 604 +4 567 516 604 533 +4 575 640 567 516 +4 517 518 554 545 +4 536 593 554 518 +4 519 593 536 518 +4 593 562 538 519 +4 562 593 536 519 +4 559 572 521 561 +4 572 546 559 521 +4 530 561 521 572 +4 659 522 622 663 +4 522 537 663 659 +4 555 522 566 523 +4 522 647 537 659 +4 537 647 522 542 +4 523 522 566 542 +4 663 555 549 522 +4 622 555 522 566 +4 663 622 555 522 +4 659 566 522 647 +4 542 566 647 522 +4 522 622 566 659 +4 537 663 549 522 +4 576 526 524 535 +4 560 526 525 524 +4 560 576 526 524 +4 576 560 525 524 +4 550 576 548 526 +4 526 609 534 550 +4 550 609 576 526 +4 526 576 548 535 +4 576 609 560 526 +4 527 583 531 540 +4 534 583 527 557 +4 583 531 547 527 +4 609 583 547 527 +4 540 527 583 557 +4 583 609 534 527 +4 528 532 574 552 +4 593 584 545 529 +4 530 601 561 572 +4 574 538 564 532 +4 552 532 574 564 +4 603 561 559 533 +4 567 604 603 533 +4 603 567 533 559 +4 609 550 595 534 +4 583 534 609 557 +4 609 534 595 557 +4 577 548 576 535 +4 554 614 536 569 +4 593 554 562 536 +4 614 562 554 536 +4 536 614 562 569 +4 647 663 537 659 +4 537 563 558 605 +4 647 651 556 537 +4 649 563 537 605 +4 649 647 537 651 +4 543 563 558 537 +4 537 600 663 649 +4 663 537 649 647 +4 543 537 558 605 +4 663 600 537 549 +4 563 556 651 537 +4 600 605 537 543 +4 605 600 537 649 +4 651 563 537 649 +4 537 647 542 556 +4 562 615 593 538 +4 562 581 615 538 +4 538 581 615 564 +4 538 615 574 564 +4 615 593 538 574 +4 653 575 596 539 +4 575 653 629 539 +4 629 653 606 539 +4 544 629 606 539 +4 583 571 540 557 +4 553 541 546 568 +4 541 553 592 568 +4 611 566 647 542 +4 611 542 582 566 +4 542 556 582 551 +4 647 582 611 542 +4 556 542 582 647 +4 544 648 555 549 +4 544 648 606 629 +4 606 648 544 549 +4 584 618 593 545 +4 554 593 618 545 +4 592 553 546 568 +4 546 559 602 608 +4 608 546 559 572 +4 602 553 546 592 +4 559 553 546 602 +4 602 592 546 568 +4 547 609 628 583 +4 584 609 628 547 +4 548 576 594 577 +4 550 576 594 548 +4 555 638 663 549 +4 549 638 663 600 +4 638 648 549 555 +4 648 606 638 549 +4 594 550 595 609 +4 609 576 594 550 +4 573 617 556 551 +4 573 582 617 551 +4 617 582 556 551 +4 564 589 598 552 +4 574 564 598 552 +4 627 592 553 639 +4 592 553 559 602 +4 639 553 625 559 +4 553 625 627 639 +4 639 553 559 592 +4 565 625 553 559 +4 554 614 593 562 +4 614 593 618 554 +4 663 648 555 622 +4 648 638 663 555 +4 664 556 651 578 +4 652 556 651 664 +4 556 652 582 617 +4 651 647 556 652 +4 556 591 578 664 +4 617 652 664 556 +4 652 647 556 582 +4 617 591 573 556 +4 578 556 660 563 +4 660 556 651 563 +4 664 591 617 556 +4 578 556 651 660 +4 609 583 557 597 +4 612 571 583 557 +4 597 571 612 557 +4 597 612 583 557 +4 595 609 557 597 +4 605 563 558 579 +4 559 567 643 603 +4 665 639 559 643 +4 639 559 625 665 +4 608 559 639 636 +4 636 559 639 643 +4 567 565 559 665 +4 603 559 636 643 +4 625 565 634 559 +4 559 608 572 607 +4 625 559 634 665 +4 602 559 639 608 +4 636 608 559 607 +4 572 559 607 561 +4 561 559 636 603 +4 559 639 592 602 +4 559 636 607 561 +4 643 665 567 559 +4 559 565 634 665 +4 613 609 560 576 +4 609 613 560 570 +4 560 609 570 593 +4 561 636 637 603 +4 561 601 603 637 +4 607 561 601 572 +4 601 636 637 561 +4 561 636 607 601 +4 585 562 581 610 +4 673 562 581 615 +4 614 673 562 610 +4 562 569 614 610 +4 610 562 581 673 +4 673 562 615 614 +4 614 615 593 562 +4 569 562 585 610 +4 578 660 580 563 +4 623 563 579 580 +4 660 649 623 563 +4 623 649 605 563 +4 649 660 651 563 +4 660 563 623 580 +4 563 623 579 605 +4 564 581 615 598 +4 564 615 574 598 +4 581 598 564 589 +4 620 665 634 565 +4 567 565 620 596 +4 565 620 665 567 +4 566 659 611 647 +4 611 566 622 659 +4 691 665 680 567 +4 675 643 665 567 +4 657 640 691 567 +4 567 620 657 596 +4 620 657 680 567 +4 675 691 640 567 +4 604 675 567 603 +4 665 567 620 680 +4 640 567 596 575 +4 567 691 665 675 +4 640 596 567 657 +4 657 691 680 567 +4 640 675 567 604 +4 603 675 567 643 +4 621 592 602 568 +4 613 609 655 570 +4 635 655 593 570 +4 593 635 570 574 +4 593 570 655 609 +4 635 574 615 598 +4 574 615 593 635 +4 653 575 690 596 +4 690 575 640 596 +4 575 640 699 690 +4 575 699 653 690 +4 653 629 699 575 +4 576 632 609 594 +4 594 576 632 577 +4 613 632 609 576 +4 594 632 619 577 +4 580 660 578 669 +4 664 578 651 660 +4 669 590 578 580 +4 631 578 672 588 +4 578 669 660 664 +4 590 578 672 669 +4 591 578 631 588 +4 588 578 672 590 +4 578 664 672 669 +4 578 591 631 664 +4 664 631 578 672 +4 579 623 580 626 +4 580 669 590 670 +4 670 660 580 669 +4 590 580 670 626 +4 626 590 580 599 +4 626 580 670 660 +4 623 660 580 626 +4 581 646 589 616 +4 589 581 598 646 +4 668 586 581 689 +4 581 646 689 615 +4 586 581 587 616 +4 616 668 581 646 +4 589 587 581 616 +4 598 581 615 646 +4 581 585 673 689 +4 616 586 581 668 +4 689 581 615 673 +4 581 586 585 689 +4 585 610 581 673 +4 668 689 581 646 +4 582 652 647 611 +4 617 652 582 611 +4 583 609 628 656 +4 583 612 597 609 +4 656 612 583 609 +4 584 593 618 628 +4 593 609 628 584 +4 689 585 673 610 +4 650 588 679 585 +4 610 689 585 679 +4 585 586 679 689 +4 610 585 588 650 +4 588 590 679 585 +4 585 610 679 650 +4 586 679 590 585 +4 590 678 586 641 +4 682 586 616 668 +4 668 682 586 689 +4 586 678 679 689 +4 586 616 678 682 +4 678 586 682 689 +4 587 586 616 641 +4 586 678 590 679 +4 587 590 586 641 +4 616 586 678 641 +4 616 587 641 599 +4 599 587 641 590 +4 672 631 588 650 +4 588 672 679 590 +4 672 650 588 679 +4 669 678 679 590 +4 678 590 670 641 +4 590 672 679 669 +4 641 626 590 670 +4 599 626 590 641 +4 590 669 678 670 +4 633 627 592 621 +4 633 592 602 621 +4 627 592 639 633 +4 639 592 602 633 +4 687 618 593 609 +4 593 686 615 671 +4 618 686 687 593 +4 593 618 671 614 +4 686 593 655 609 +4 686 615 635 593 +4 628 593 618 609 +4 618 686 593 671 +4 615 593 671 614 +4 635 686 593 655 +4 609 687 686 593 +4 619 594 609 632 +4 594 595 619 609 +4 642 597 656 595 +4 595 597 656 609 +4 619 595 642 609 +4 656 642 595 609 +4 690 657 596 640 +4 597 656 612 666 +4 612 656 597 609 +4 666 597 656 642 +4 597 612 624 666 +4 597 624 642 666 +4 615 635 598 646 +4 607 636 637 601 +4 630 637 601 607 +4 602 639 633 608 +4 636 643 637 603 +4 644 643 675 603 +4 644 643 603 637 +4 674 675 604 603 +4 675 603 674 644 +4 701 675 604 674 +4 640 675 604 701 +4 606 629 677 653 +4 606 677 648 638 +4 629 648 606 677 +4 630 636 637 607 +4 609 684 642 632 +4 609 632 613 684 +4 613 609 709 655 +4 628 618 687 609 +4 656 609 717 642 +4 628 609 687 656 +4 609 717 686 687 +4 609 684 717 642 +4 632 619 642 609 +4 609 655 686 717 +4 684 717 709 609 +4 687 609 717 656 +4 609 717 709 655 +4 613 609 684 709 +4 679 610 685 650 +4 673 689 610 685 +4 689 610 685 679 +4 645 647 652 611 +4 617 645 652 611 +4 659 611 647 645 +4 612 656 654 624 +4 612 656 624 666 +4 671 686 615 614 +4 614 671 686 673 +4 614 686 615 673 +4 646 686 708 615 +4 689 708 686 615 +4 689 646 708 615 +4 646 635 695 615 +4 686 689 615 673 +4 615 695 686 635 +4 695 686 646 615 +4 682 641 668 616 +4 678 682 616 641 +4 671 618 686 687 +4 619 642 658 632 +4 665 661 620 634 +4 620 667 680 657 +4 620 661 680 634 +4 661 680 665 620 +4 620 634 680 667 +4 622 663 703 659 +4 663 703 648 622 +4 622 703 648 681 +4 622 659 703 681 +4 662 649 623 660 +4 662 660 623 626 +4 624 656 654 666 +4 625 634 661 665 +4 625 661 639 665 +4 626 662 660 670 +4 714 711 677 629 +4 653 711 733 629 +4 629 653 711 721 +4 733 711 699 629 +4 629 677 714 648 +4 653 733 699 629 +4 677 629 711 721 +4 721 677 629 653 +4 684 642 632 658 +4 680 634 661 667 +4 686 695 704 635 +4 686 635 704 655 +4 716 663 703 638 +4 638 710 677 716 +4 638 677 703 716 +4 638 703 648 663 +4 677 703 648 638 +4 716 663 638 710 +4 657 640 700 691 +4 691 640 701 675 +4 700 727 640 690 +4 690 700 657 640 +4 640 727 738 699 +4 727 707 640 691 +4 691 727 701 640 +4 727 707 700 640 +4 701 640 727 738 +4 640 727 699 690 +4 640 707 700 691 +4 641 676 678 682 +4 641 676 670 678 +4 668 676 641 682 +4 656 666 642 694 +4 694 717 684 642 +4 684 694 642 658 +4 656 717 694 642 +4 693 646 689 668 +4 695 708 693 646 +4 646 693 689 708 +4 686 708 695 646 +4 703 677 648 714 +4 648 703 714 720 +4 648 703 720 681 +4 690 653 733 699 +4 653 729 711 721 +4 690 733 653 729 +4 729 733 653 711 +4 692 654 666 683 +4 692 654 656 666 +4 704 686 655 717 +4 704 717 655 709 +4 687 656 717 702 +4 656 702 692 666 +4 702 717 694 656 +4 666 656 702 694 +4 707 700 657 697 +4 697 680 657 707 +4 657 700 707 691 +4 680 657 688 697 +4 688 680 667 657 +4 691 707 657 680 +4 698 694 684 658 +4 692 706 683 666 +4 666 702 692 694 +4 692 694 706 666 +4 682 693 689 668 +4 671 705 686 673 +4 712 686 671 705 +4 712 671 686 687 +4 705 696 673 713 +4 673 705 686 696 +4 673 686 689 696 +4 689 696 685 673 +4 714 677 725 754 +4 754 716 677 725 +4 725 716 677 710 +4 677 703 716 754 +4 721 711 677 714 +4 725 721 677 714 +4 703 677 714 754 +4 688 680 697 707 +4 693 708 682 689 +4 683 706 692 723 +4 718 694 684 698 +4 730 684 718 736 +4 718 717 684 694 +4 684 709 717 736 +4 684 718 698 730 +4 717 684 736 718 +4 686 735 785 764 +4 743 745 705 686 +4 744 785 686 735 +4 722 686 705 696 +4 735 695 686 744 +4 686 745 759 771 +4 708 686 695 744 +4 759 686 794 717 +4 686 712 687 717 +4 745 759 712 686 +4 771 794 686 785 +4 785 755 686 764 +4 686 755 704 764 +4 785 794 686 755 +4 722 708 686 689 +4 759 712 686 717 +4 744 771 686 785 +4 717 755 704 686 +4 704 695 686 735 +4 712 705 745 686 +4 704 735 686 764 +4 771 686 743 744 +4 743 744 686 722 +4 686 743 745 771 +4 686 722 689 696 +4 708 744 722 686 +4 686 794 717 755 +4 686 722 705 743 +4 794 686 759 771 +4 687 717 752 737 +4 712 752 687 717 +4 702 717 687 737 +4 733 690 742 732 +4 733 751 690 732 +4 733 751 729 690 +4 690 742 732 700 +4 733 690 727 700 +4 699 733 690 727 +4 690 733 742 700 +4 692 706 724 723 +4 694 702 692 706 +4 724 692 702 706 +4 708 715 695 693 +4 706 728 694 702 +4 694 718 717 728 +4 717 694 728 702 +4 731 695 735 744 +4 708 695 734 744 +4 731 695 734 708 +4 734 695 731 744 +4 695 731 715 708 +4 705 722 696 713 +4 697 707 700 719 +4 738 727 733 699 +4 699 711 733 757 +4 738 733 763 699 +4 733 699 757 763 +4 707 742 727 700 +4 742 733 727 700 +4 742 719 732 700 +4 707 742 700 719 +4 724 702 728 706 +4 737 702 717 724 +4 728 717 702 724 +4 714 703 754 739 +4 739 714 703 720 +4 754 703 716 739 +4 755 717 704 709 +4 745 726 743 705 +4 726 722 705 713 +4 743 722 705 726 +4 741 706 724 728 +4 706 724 723 741 +4 734 708 715 731 +4 717 709 755 747 +4 717 709 747 736 +4 749 716 725 710 +4 721 729 711 762 +4 768 762 711 776 +4 776 762 711 757 +4 757 762 711 733 +4 762 711 721 714 +4 711 729 733 762 +4 714 762 711 768 +4 712 759 752 717 +4 726 713 743 722 +4 775 714 739 760 +4 775 754 714 762 +4 720 739 714 760 +4 754 714 739 775 +4 714 775 762 768 +4 725 721 714 762 +4 760 775 714 768 +4 714 725 762 754 +4 716 754 749 725 +4 783 717 756 766 +4 717 728 741 724 +4 798 777 747 717 +4 717 793 752 737 +4 807 717 794 755 +4 804 752 759 717 +4 717 766 793 737 +4 746 736 717 761 +4 804 752 717 807 +4 717 752 793 805 +4 741 766 717 737 +4 794 759 717 807 +4 736 717 718 746 +4 807 717 755 798 +4 777 755 747 717 +4 747 717 736 783 +4 746 717 718 756 +4 761 736 717 783 +4 793 783 717 798 +4 766 717 756 728 +4 756 746 717 761 +4 756 717 718 728 +4 766 783 717 793 +4 717 805 793 807 +4 805 807 717 752 +4 717 793 798 807 +4 728 766 717 741 +4 783 747 717 798 +4 717 756 761 783 +4 804 717 759 807 +4 717 741 737 724 +4 798 755 777 717 +4 728 746 718 756 +4 730 718 746 736 +4 773 721 725 762 +4 729 762 721 773 +4 740 723 724 741 +4 740 724 753 741 +4 766 753 724 741 +4 766 724 737 741 +4 753 724 737 766 +4 762 725 765 754 +4 765 773 725 762 +4 749 754 765 725 +4 726 745 743 748 +4 727 733 779 770 +4 770 727 733 738 +4 733 779 742 727 +4 756 741 766 728 +4 729 762 773 791 +4 733 751 767 729 +4 767 733 729 762 +4 729 767 762 791 +4 750 730 746 736 +4 734 731 735 744 +4 731 758 769 735 +4 734 731 769 735 +4 734 758 769 731 +4 732 774 779 751 +4 732 779 742 751 +4 742 751 733 732 +4 732 774 742 779 +4 779 751 733 742 +4 779 733 788 770 +4 763 733 788 820 +4 733 784 779 788 +4 733 829 762 784 +4 784 751 733 779 +4 757 762 733 824 +4 820 733 784 824 +4 733 762 767 784 +4 824 733 784 829 +4 770 733 788 763 +4 788 733 784 820 +4 767 751 733 784 +4 824 763 733 757 +4 829 733 762 824 +4 733 770 738 763 +4 820 763 733 824 +4 769 744 734 735 +4 785 764 735 780 +4 769 785 744 735 +4 758 735 780 769 +4 780 785 769 735 +4 746 750 736 761 +4 778 761 747 736 +4 778 747 781 736 +4 736 761 750 778 +4 761 783 747 736 +4 737 793 752 795 +4 737 753 766 782 +4 793 766 782 737 +4 795 793 782 737 +4 771 745 772 743 +4 772 743 745 748 +4 785 744 771 769 +4 772 745 771 787 +4 771 745 759 787 +4 747 781 798 783 +4 781 777 747 798 +4 783 747 781 778 +4 778 783 747 761 +4 754 749 765 797 +4 774 784 779 751 +4 786 784 774 751 +4 792 784 751 767 +4 784 786 792 751 +4 759 789 752 804 +4 804 805 789 752 +4 752 793 805 795 +4 805 752 795 789 +4 805 804 807 752 +4 809 754 775 762 +4 809 754 765 797 +4 762 754 765 809 +4 785 807 755 764 +4 807 794 785 755 +4 807 755 806 777 +4 807 755 799 806 +4 807 764 799 755 +4 807 777 798 755 +4 828 762 757 824 +4 757 776 828 824 +4 813 757 824 815 +4 776 762 757 828 +4 824 757 776 815 +4 763 757 824 813 +4 804 759 789 800 +4 759 804 794 787 +4 759 794 804 807 +4 787 794 759 771 +4 804 759 800 787 +4 760 801 775 802 +4 760 768 802 775 +4 776 768 762 826 +4 775 809 762 836 +4 762 836 826 775 +4 791 762 814 827 +4 762 829 767 784 +4 809 773 762 836 +4 828 836 762 829 +4 829 762 767 803 +4 814 827 762 836 +4 826 836 762 828 +4 836 827 762 829 +4 762 773 791 814 +4 775 768 826 762 +4 814 762 773 836 +4 829 791 762 803 +4 762 828 776 826 +4 762 791 767 803 +4 827 791 762 829 +4 765 773 762 809 +4 762 828 829 824 +4 763 788 770 811 +4 820 788 763 811 +4 763 820 811 813 +4 820 763 824 813 +4 807 764 785 799 +4 780 785 764 799 +4 765 809 797 808 +4 809 765 773 808 +4 767 792 784 803 +4 829 767 784 803 +4 768 826 812 802 +4 776 812 768 826 +4 802 768 826 775 +4 832 814 773 836 +4 773 809 808 836 +4 773 808 814 832 +4 832 773 808 836 +4 784 779 796 774 +4 796 810 786 774 +4 784 796 786 774 +4 831 801 826 775 +4 775 831 809 836 +4 826 831 775 836 +4 826 801 802 775 +4 828 812 776 826 +4 812 776 815 828 +4 776 828 824 815 +4 807 777 806 798 +4 798 790 777 806 +4 798 777 790 781 +4 788 784 779 817 +4 779 817 784 796 +4 824 784 820 823 +4 786 821 784 792 +4 821 784 818 796 +4 796 821 784 786 +4 784 817 788 820 +4 784 792 825 803 +4 829 784 825 803 +4 823 824 784 829 +4 792 821 784 825 +4 784 817 821 818 +4 818 784 817 796 +4 817 823 784 821 +4 823 784 821 825 +4 823 817 784 820 +4 784 823 829 825 +4 794 807 785 799 +4 818 786 819 821 +4 810 786 819 818 +4 818 810 786 796 +4 818 821 796 786 +4 819 786 792 821 +4 803 829 791 827 +4 827 791 803 830 +4 822 819 792 821 +4 822 825 821 792 +4 792 825 816 822 +4 792 816 825 803 +4 808 834 809 797 +4 831 835 801 838 +4 802 801 835 838 +4 802 835 801 831 +4 826 802 801 831 +4 812 835 802 826 +4 826 835 802 831 +4 803 829 827 825 +4 827 803 825 830 +4 803 825 830 816 +4 809 836 833 808 +4 833 834 809 808 +4 808 814 832 833 +4 808 836 833 832 +4 834 809 841 833 +4 836 841 809 833 +4 809 831 841 836 +4 812 828 815 826 +4 812 835 826 839 +4 814 833 837 832 +4 832 827 814 836 +4 836 831 842 826 +4 826 839 835 842 +4 835 826 842 831 +4 835 844 838 831 +4 851 841 831 842 +4 842 844 835 831 +4 831 847 851 842 +4 831 842 844 847 +4 847 841 831 851 +4 831 841 836 842 +4 831 844 838 847 +4 833 832 845 837 +4 832 836 833 845 +4 833 836 841 845 +4 833 840 845 841 +4 834 840 833 841 +4 840 833 845 837 +4 834 843 840 841 +4 841 848 834 843 +4 844 835 846 839 +4 839 844 835 842 +4 836 851 842 841 +4 836 851 841 845 +4 840 845 850 837 +4 844 838 847 854 +4 846 852 842 839 +4 846 844 839 842 +4 849 841 845 840 +4 843 840 848 849 +4 843 841 848 840 +4 840 841 848 849 +4 849 845 850 840 +4 853 861 841 851 +4 841 861 849 845 +4 845 841 861 851 +4 853 848 841 861 +4 861 848 841 849 +4 841 851 847 853 +4 842 847 851 852 +4 847 842 844 852 +4 842 846 844 852 +4 844 855 859 847 +4 855 852 847 844 +4 855 844 846 852 +4 854 844 859 847 +4 850 861 845 849 +4 856 852 855 846 +4 867 859 847 862 +4 863 854 859 847 +4 859 863 847 862 +4 869 851 847 852 +4 869 853 847 851 +4 869 853 862 847 +4 847 869 852 867 +4 862 869 847 867 +4 847 855 859 852 +4 859 867 847 852 +4 858 849 857 848 +4 858 861 849 848 +4 861 853 848 858 +4 849 861 860 850 +4 849 865 858 857 +4 865 860 849 858 +4 861 849 860 858 +4 860 861 864 850 +4 869 851 861 853 +4 855 867 852 856 +4 859 855 867 852 +4 874 869 853 862 +4 853 861 874 858 +4 870 853 874 858 +4 853 874 862 870 +4 861 869 853 874 +4 863 868 859 854 +4 857 865 858 866 +4 871 870 858 865 +4 861 860 865 858 +4 870 874 871 858 +4 865 870 858 866 +4 858 874 871 865 +4 874 858 861 865 +4 859 867 868 863 +4 859 868 867 872 +4 863 867 862 859 +4 860 864 861 865 +4 860 865 871 864 +4 861 864 874 865 +4 867 862 869 863 +4 862 883 869 863 +4 877 862 874 870 +4 863 883 873 862 +4 862 873 877 883 +4 883 862 874 877 +4 883 869 874 862 +4 876 863 873 868 +4 868 863 872 879 +4 883 876 863 873 +4 879 869 883 863 +4 863 869 867 872 +4 876 863 879 883 +4 867 863 872 868 +4 863 879 869 872 +4 863 868 876 879 +4 864 871 874 865 +4 871 874 875 864 +4 866 870 871 865 +4 866 870 878 871 +4 879 867 869 872 +4 876 868 872 879 +4 869 874 886 883 +4 869 886 879 883 +4 887 882 888 870 +4 877 888 870 887 +4 883 870 874 887 +4 871 882 874 870 +4 887 882 870 874 +4 878 888 882 870 +4 877 870 874 883 +4 877 870 883 887 +4 871 878 882 870 +4 882 874 875 871 +4 876 872 881 879 +4 880 883 873 884 +4 884 883 873 876 +4 877 883 873 880 +4 874 887 882 875 +4 887 874 883 886 +4 876 884 883 881 +4 881 876 879 883 +4 891 888 877 883 +4 887 877 888 883 +4 877 891 883 880 +4 888 882 894 878 +4 879 883 886 885 +4 883 879 881 885 +4 884 893 880 883 +4 893 880 891 892 +4 893 883 891 880 +4 889 881 885 883 +4 889 883 884 881 +4 889 885 881 890 +4 894 888 887 882 +4 898 894 887 882 +4 891 900 906 883 +4 885 895 883 886 +4 888 887 883 897 +4 897 886 883 895 +4 906 897 891 883 +4 891 883 893 900 +4 888 883 891 897 +4 895 885 883 889 +4 883 884 893 889 +4 895 883 893 889 +4 887 886 883 897 +4 900 883 893 895 +4 895 906 900 883 +4 897 906 895 883 +4 895 885 889 890 +4 894 897 898 887 +4 888 897 894 887 +4 910 888 894 909 +4 888 910 897 915 +4 909 903 915 888 +4 909 888 902 903 +4 891 888 915 903 +4 894 910 897 888 +4 891 888 897 915 +4 894 888 902 909 +4 910 909 915 888 +4 900 895 889 901 +4 895 889 893 900 +4 900 889 896 901 +4 896 889 895 901 +4 889 895 890 896 +4 906 904 891 915 +4 904 893 891 892 +4 904 891 899 892 +4 899 891 904 915 +4 899 903 891 915 +4 891 897 906 915 +4 904 900 906 891 +4 904 893 900 891 +4 898 909 894 907 +4 898 910 897 894 +4 909 894 910 898 +4 901 900 895 906 +4 905 900 896 901 +4 910 906 897 915 +4 910 909 898 907 +4 915 913 912 899 +4 899 912 904 908 +4 912 915 899 904 +4 913 915 903 899 +4 912 899 913 908 +4 900 914 906 905 +4 912 914 906 900 +4 906 900 905 901 +4 906 904 912 900 +4 923 915 909 902 +4 916 925 902 923 +4 916 922 902 925 +4 902 916 915 903 +4 916 915 923 902 +4 902 915 909 903 +4 916 915 903 913 +4 904 912 915 906 +4 917 914 905 906 +4 906 917 914 919 +4 914 915 912 906 +4 910 915 919 906 +4 906 914 915 919 +4 910 907 911 909 +4 924 912 913 908 +4 908 913 924 921 +4 909 918 920 923 +4 920 915 909 923 +4 910 915 909 920 +4 911 918 920 909 +4 911 920 910 909 +4 910 919 915 927 +4 915 910 927 920 +4 924 928 915 912 +4 915 912 913 924 +4 912 928 915 914 +4 933 915 913 924 +4 913 916 933 926 +4 915 916 933 913 +4 933 913 926 929 +4 913 933 924 929 +4 913 926 929 921 +4 929 924 913 921 +4 917 919 928 914 +4 915 928 919 914 +4 919 915 933 928 +4 933 915 923 916 +4 923 930 915 933 +4 928 915 933 924 +4 930 927 915 933 +4 915 933 927 919 +4 927 915 920 930 +4 930 915 920 923 +4 922 935 933 916 +4 925 933 923 916 +4 933 916 935 926 +4 916 922 925 933 +4 919 928 932 917 +4 934 930 920 918 +4 920 923 918 930 +4 919 933 932 928 +4 933 941 927 919 +4 933 919 932 941 +4 941 919 932 927 +4 934 927 920 930 +4 926 929 921 931 +4 935 937 922 936 +4 925 922 936 933 +4 935 922 933 936 +4 922 925 936 937 +4 933 923 940 936 +4 923 930 933 940 +4 923 925 936 933 +4 929 933 924 938 +4 933 928 924 942 +4 924 933 942 938 +4 945 933 926 931 +4 935 933 926 945 +4 926 933 929 931 +4 946 941 934 927 +4 946 933 927 930 +4 933 941 946 927 +4 930 946 934 927 +4 942 933 928 941 +4 928 932 944 942 +4 928 932 942 941 +4 928 933 932 941 +4 939 931 929 938 +4 938 929 933 931 +4 943 934 930 940 +4 946 930 934 940 +4 946 940 933 930 +4 945 938 933 931 +4 938 945 939 931 +4 942 932 944 941 +4 938 933 942 958 +4 935 933 949 936 +4 933 955 951 957 +4 955 946 940 933 +4 958 957 949 933 +4 933 955 957 940 +4 933 957 951 958 +4 933 946 941 951 +4 933 945 935 949 +4 933 949 958 945 +4 955 946 933 951 +4 936 933 957 940 +4 933 957 949 936 +4 941 942 933 951 +4 951 942 933 958 +4 958 938 933 945 +4 946 934 943 940 +4 949 937 935 936 +4 954 957 950 936 +4 949 957 954 936 +4 936 950 954 948 +4 936 957 950 940 +4 948 949 936 937 +4 954 949 936 948 +4 942 953 938 958 +4 947 938 953 945 +4 945 947 938 939 +4 945 938 953 958 +4 950 940 955 952 +4 946 955 940 952 +4 950 957 955 940 +4 946 952 940 943 +4 944 941 951 942 +4 944 942 951 956 +4 942 956 953 958 +4 956 942 951 958 +4 957 955 951 958 +CELL_TYPES 13072 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 diff --git a/tools/postinstall-fixup/macos-postinstall-fixup.sh b/tools/postinstall-fixup/macos-postinstall-fixup.sh index b905d0d0ed0..329be2877c7 100644 --- a/tools/postinstall-fixup/macos-postinstall-fixup.sh +++ b/tools/postinstall-fixup/macos-postinstall-fixup.sh @@ -70,6 +70,7 @@ check-all-deps() { echo " Checking (pass $pass) $lib" libqt="" + libpython="" libboost="" libicu="" libglew="" @@ -83,6 +84,7 @@ check-all-deps() { is_fixup_needed="false" if echo "$dependencies" | grep --quiet "/Qt" || + echo "$dependencies" | grep --quiet "/Python" || echo "$dependencies" | grep --quiet "/libboost" || echo "$dependencies" | grep --quiet "/libicu" || echo "$dependencies" | grep --quiet "/libGLEW" || @@ -101,6 +103,8 @@ check-all-deps() { (echo "$dependencies") | while read dep; do if libqt="$(echo $dep | egrep -o "/Qt[A-Za-z]*$" | cut -c2-)" && [ -n "$libqt" ]; then libname="$libqt" + elif libpython="$(echo $dep | egrep -o "/Python.framework.*" | cut -c2-)" && [ -n "$libpython" ]; then + libname="$libpython" elif libboost="$(echo $dep | egrep -o "/libboost_[^\/]*?\.dylib" | cut -c2-)" && [ -n "$libboost" ]; then libname="$libboost" elif libicu="$(echo $dep | egrep -o "/libicu[^\/]*?\.dylib$" | cut -c2-)" && [ -n "$libicu" ]; then @@ -135,13 +139,15 @@ check-all-deps() { originlib="$dep" destlib="$INSTALL_DIR/lib/$libname" fi - if [ -e $originlib ] && [ ! -e $destlib ]; then + if [ -e $originlib ] && [ ! -e $destlib ] && [ -z "$libpython" ]; then echo " cp -Rf $dep $INSTALL_DIR/lib" cp -Rf $originlib $INSTALL_DIR/lib fi elif [[ "$mode" == "fixup" ]]; then if [ -n "$libqt" ]; then rpathlib="$libqt.framework/$libqt" + elif [ -n "$libpython" ]; then + rpathlib="$libpython" else rpathlib="$libname" fi From 5e455e40581d4be035646949594485db9fed0b18 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 23 Jan 2025 14:49:55 +0100 Subject: [PATCH 12/21] Fix compilation --- .../solidmechanics/spring/FixedWeakConstraint.h | 2 +- .../solidmechanics/spring/FixedWeakConstraint.inl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index d5ed13fe513..1fc80413b7a 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include namespace sofa::core::behavior diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl index 5ab787e4025..5dba0d315f9 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.inl @@ -108,7 +108,7 @@ const bool FixedWeakConstraint::checkState() /// Compile time condition to check if we are working with a Rigid3Types or a type that does not /// need the Angular Stiffness parameters. //if constexpr (isRigid()) - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { sofa::helper::ReadAccessor> s = d_stiffness; sofa::helper::WriteOnlyAccessor> as = d_angularStiffness; @@ -274,7 +274,7 @@ void FixedWeakConstraint::addForce(const MechanicalParams* mparams , const auto & activeDirections = getActiveDirections(); // rigid case - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { CPos dx = p1[index].getCenter() - p0[ext_index].getCenter(); @@ -362,7 +362,7 @@ void FixedWeakConstraint::addDForce(const MechanicalParams* mparams, const auto stiffness = k[static_cast(i < k.size()) * i]; - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { const auto angularStiffness = k_a[static_cast(i < k_a.size()) * i]; @@ -458,7 +458,7 @@ void FixedWeakConstraint::addKToMatrix(const MechanicalParams* mparam } // rotation (if applicable) - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { const auto vr = -kFact * k_a[(index < k_a.size()) * index]; for (sofa::Size i = space_size; i < total_size; i++) @@ -507,7 +507,7 @@ void FixedWeakConstraint::buildStiffnessMatrix(core::behavior::Stiffn } // rotation (if applicable) - if constexpr (sofa::type::isRigidType()) + if constexpr (sofa::type::isRigidType) { const auto vr = -k_a[(index < k_a.size()) * index]; for (sofa::Size i = space_size; i < total_size; ++i) From 1985599e59ed197dcfe3097c435715c8b818e65c Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 23 Jan 2025 15:39:36 +0100 Subject: [PATCH 13/21] Try to fix windows compilation --- .../component/solidmechanics/spring/FixedWeakConstraint.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h index 1fc80413b7a..c710d994709 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/FixedWeakConstraint.h @@ -104,12 +104,12 @@ class FixedWeakConstraint : public core::behavior::ForceField protected : FixedWeakConstraint(); - static constexpr type::fixed_array s_defaultActiveDirections = sofa::type::makeHomogeneousArray(true); + static constexpr type::fixed_array::coord_total_size> s_defaultActiveDirections = sofa::type::makeHomogeneousArray::coord_total_size>(true); virtual const DataVecCoord* getExtPosition() const; virtual const VecIndex& getIndices() const; virtual const VecIndex& getExtIndices() const; - virtual const type::fixed_array& getActiveDirections() const; + virtual const type::fixed_array::coord_total_size>& getActiveDirections() const; virtual const bool checkState(); virtual bool checkOutOfBoundsIndices(); From b4e8d4308589649c9bb052674c1c178ab8d3ad3c Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 23 Jan 2025 16:40:34 +0100 Subject: [PATCH 14/21] Avoid using an intermediate expression and directly use the right term --- .../solidmechanics/spring/RestShapeSpringsForceField.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl index c3fc5d30191..14e67f2cf63 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.inl @@ -163,7 +163,7 @@ const typename RestShapeSpringsForceField::VecIndex& RestShapeSprings } template -const type::fixed_array::coord_total_size>& RestShapeSpringsForceField::getActiveDirections() const +const type::fixed_array& RestShapeSpringsForceField::getActiveDirections() const { return d_activeDirections.getValue(); } From eada37f2cc754d854aed1e2b97fdb372019a4785 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Fri, 28 Feb 2025 16:47:26 +0100 Subject: [PATCH 15/21] Squashed commit of the following: commit 0806b074743b886b6adfd20d9e51312e342a398d Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Fri Feb 21 15:55:34 2025 +0100 [github] Use token for performance regression launching (#5287) Try fixing action commit 9f56fca787132ad2f3255ae434d868ec41777fc1 Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Fri Feb 21 15:16:12 2025 +0100 [github] Add workflow for performance testing launch (#5286) * Add workflow for performance testing launch * Fix github token and sha commit 700b6cdd94fe24a51b2a7014fb0fc83e6abe1fbc Author: Olivier Roussel Date: Thu Feb 20 23:27:00 2025 +0100 [IO.Mesh] Fix missing `iomanip` header in tests (#5279) Fix missing header commit 5307e85cbfe60520a0e509fc6931c6b6f963c464 Author: Hugo Date: Wed Feb 19 14:25:24 2025 +0100 [ODESolver] Update data comment in EulerImplicit (#5282) commit fee965740e7d59e7a50808f3e7347142ad651fa7 Author: Alex Bilger Date: Wed Feb 19 13:48:07 2025 +0100 [ODESolver] Add option to compute residual at the end of the solving (#5263) commit a22997231bf7a0ea3edd37d03360e5c86eb3ea78 Author: Alex Bilger Date: Wed Feb 19 12:20:51 2025 +0100 [Helper] Deprecate findOrCreateAValidPath and introduce clearer functions (#5264) * [Helper] Fix findOrCreateAValidPath when given a file path * [Helper] Fix findOrCreateAValidPath when given a file path * Introduce clearer function names * deprecate findOrCreateAValidPath * restore previous findOrCreateAValidPath commit 4ee24f6218a7285b8b4faf9f9d69ea2746fa2a6a Author: Frederick Roy Date: Wed Feb 19 20:15:38 2025 +0900 [All] Fix compilation with FLOATING_POINT_TYPE=float (#5269) fix compilation with FLOATING_POINT_TYPE=float commit ef7ff21931491fc482974af7fc950be5ca734d31 Author: Hugo Date: Wed Feb 19 09:52:47 2025 +0100 [SceneUtility] Remove *AliasComponent (#5241) * [SceneUtility] Remove *AliasComponent * Update in the ComponentChange so that it appears as Removed * remove associated scenes commit aa3609843698ab1fec13fa2beab73487c3a5ba86 Author: Alex Bilger Date: Wed Feb 19 00:04:17 2025 +0100 [SceneChecking] Check if a Node has an empty name (#5276) commit f2f0b108268a56bca118ab6e3e6c72aa76f10760 Author: EulalieCoevoet Date: Wed Feb 12 12:14:48 2025 +0100 [visual] Adds features to LineAxis and DrawTools (#5258) * [visual-gl] LineAxis & DrawTool: - fixes usage of thickness - new feature: infinite lines - new feature: vanishing infinite line - fixes typo * [visual] LineAxis: cleaning commit b4e8b98aeae827c646ab3f671f9f352689b554ee Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Wed Feb 12 09:35:16 2025 +0100 [GUI] Remove Qt and make SofaImGUI as default viewer (#5176) * Add possibility to fetch and add by default for external plugins and set SofaGLFW as ON by default * Remove Qt-based GUI from sources * Add way to pull and build Sofa.Qt plugin * Fix compilation * Change order so SofaGLFW and SofaIMGUI are already in the target stack when runSofa produce the plugin_list.cong.default * Merge master * Make the packaging possible without Qt * Remove GuiDataRepository that was Qt specific -> will need to include it to the Qt gui plugin * Add fetchable Qt commit d2f194d5c1631bc90ebb70b2e6669e2d92cef612 Author: Alex Bilger Date: Wed Feb 12 07:26:17 2025 +0100 [Contact] Clean FrictionContact (#5261) * [Contact] Replace double by SReal * add override keyword on destructor commit 62264fbe152b4286efb4fda1e250cfdacbfe8016 Author: Alex Bilger Date: Mon Feb 10 14:20:15 2025 +0100 [StateContainer] Allow coord difference in vOp for rigids (#5253) * [StateContainer] Allow coord difference in vOp for rigids * check that DataTypes support coordDifference commit 5120328b3b72af66a97e85112af6e6fe2bc30478 Author: erik pernod Date: Mon Feb 10 14:19:28 2025 +0100 [Topology.Container] Add new method computeSegmentTriangleIntersectionInPlane in TriangleSetGeometryAlgorithm (#5188) * Update TriangleSetGeometryAlgorithms.h * Update TriangleSetGeometryAlgorithms.inl * [TopologyTest] Add comments * [Topology.Dynamic_test] factorize some code in TriangleSetTopology_test * [Topology.Dynamic_test] Add some tests in TriangleSetTopology_test to test adding and removing triangles * typo errors * [Topology.Dynamic_test] Add tests in TriangleSetTopology_test tto test TriangleSegmentIntersection inside same plane or with projection * Update TriangleSetTopology_test.cpp * Update TriangleSetTopology_test.cpp * Update TriangleSetTopology_test.cpp * Fix namespace commit 5448a14f0526ac3d597c1abb8c4427acde4055cd Author: Alex Bilger Date: Fri Jan 31 15:10:05 2025 +0100 [StateContainer] Extend the possible vector operations in vOp (#5237) * missing test * remove duplicated test * [StateContainer] Extend the possible vector operations in vOp --------- Co-authored-by: Paul Baksic <30337881+bakpaul@users.noreply.github.com> commit 6af25d5812580fafe94cd840a84c11d404714dde Author: Alex Bilger Date: Fri Jan 31 15:04:36 2025 +0100 [Simulation] Trigger warning when Node already contains component (#5212) * [Simulation] Trigger error when Node already contains component * also mention the class name * convert error to warning * fix STLExporter_test commit 9ceb6dc2270c33c218d35c9ef911b310b6d5bc28 Author: Alex Bilger Date: Fri Jan 31 15:04:21 2025 +0100 [SofaCUDA] Print CUDA standard at init of the module (#5166) * [SofaCUDA] Print CUDA standard at init of the module * add an empty scene loading the plugin * compiler output * remove empty scene commit 3eecf8f0b4d0e58986f2dda28c0a9b36eb7cb488 Author: Alex Bilger Date: Wed Jan 29 22:18:50 2025 +0100 Bump version of Tracy from v0.9.1 to v0.11.1 (#5249) commit 365940321143e545a865765cef669cb267f485e8 Author: Alex Bilger Date: Wed Jan 29 21:39:51 2025 +0100 [Core] Remove some static functions create (#5239) commit 989a885269ec2e97491de89264861c35c8ab36d2 Author: Alex Bilger Date: Wed Jan 29 21:03:59 2025 +0100 [StateContainer] Extensive tests of MechanicalObject::vOp (#5233) * [StateContainer] Extensive tests of MechanicalObject::vOp * fix wrong name * fix test * Use variable for the coefficients * missing test * remove duplicated test commit 38c295dcb7fffee64cbb7bf538fc6c60a61f2273 Author: Alex Bilger Date: Wed Jan 29 19:54:39 2025 +0100 [Playback] Remove deprecated macro (#5231) commit ffddff707679c4558e3f86b44aea6b43167e4d02 Author: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Wed Jan 29 19:48:23 2025 +0100 [CMake] Add possibility to remove auto installing of resource files (#5230) Add possibility to remove auto installing of ressource files commit 7c6bddcb48c2699135f46beb9fa54b8c63dd0c1b Author: Alex Bilger Date: Fri Jan 24 14:24:02 2025 +0100 [ODESolver] Remove repeated class name in log messages (#5242) --- .github/workflows/launch-perf-test.yml | 21 + .../contact/AugmentedLagrangianResponse.inl | 4 +- .../response/contact/FrictionContact.h | 4 +- .../response/contact/FrictionContact.inl | 2 +- .../model/BilateralConstraintResolution.h | 4 +- .../model/BilateralLagrangianConstraint.h | 4 +- .../IO/Mesh/tests/MeshExporter_test.cpp | 2 + .../IO/Mesh/tests/STLExporter_test.cpp | 58 +- .../backward/EulerImplicitSolver.cpp | 84 +- .../odesolver/backward/EulerImplicitSolver.h | 17 + .../sofa/component/playback/CompareState.cpp | 4 +- .../component/playback/CompareTopology.cpp | 4 +- .../src/sofa/component/playback/config.h.in | 9 - Sofa/Component/SceneUtility/CMakeLists.txt | 4 - .../sceneutility/MakeAliasComponent.cpp | 90 - .../sceneutility/MakeAliasComponent.h | 73 - .../sceneutility/MakeDataAliasComponent.cpp | 120 - .../sceneutility/MakeDataAliasComponent.h | 76 - .../src/sofa/component/sceneutility/init.cpp | 6 +- .../SceneUtility/tests/CMakeLists.txt | 2 - .../tests/MakeAliasComponent_test.cpp | 203 -- .../tests/MakeDataAliasComponent_test.cpp | 226 -- .../hyperelastic/material/StableNeoHookean.h | 4 +- .../statecontainer/MechanicalObject.inl | 380 ++- .../StateContainer/tests/CMakeLists.txt | 1 + .../tests/MechanicalObjectVOp_test.cpp | 982 +++++++ .../dynamic/TriangleSetGeometryAlgorithms.h | 16 +- .../dynamic/TriangleSetGeometryAlgorithms.inl | 56 + .../tests/TriangleSetTopology_test.cpp | 486 +++- .../src/sofa/component/visual/LineAxis.cpp | 78 +- .../src/sofa/component/visual/LineAxis.h | 6 +- .../src/sofa/component/visual/VisualGrid.cpp | 1 - Sofa/GL/src/sofa/gl/DrawToolGL.cpp | 15 +- Sofa/GL/src/sofa/gl/DrawToolGL.h | 4 +- Sofa/GUI/CMakeLists.txt | 2 +- Sofa/GUI/Common/CMakeLists.txt | 2 - .../src/sofa/gui/common/GuiDataRepository.cpp | 41 - .../src/sofa/gui/common/GuiDataRepository.h | 29 - Sofa/GUI/Qt/CMakeLists.txt | 406 --- Sofa/GUI/Qt/LICENSE.GPL.txt | 339 --- Sofa/GUI/Qt/Sofa.GUI.QtConfig.cmake.in | 62 - Sofa/GUI/Qt/etc/Sofa.GUI.Qt.ini.in | 2 - Sofa/GUI/Qt/src/sofa/gui/qt/AboutDialog.ui | 209 -- .../Qt/src/sofa/gui/qt/AboutSOFADialog.cpp | 55 - Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.h | 41 - .../Qt/src/sofa/gui/qt/BaseGenGraphForm.ui | 1065 -------- .../Qt/src/sofa/gui/qt/DataFilenameWidget.cpp | 99 - .../Qt/src/sofa/gui/qt/DataFilenameWidget.h | 59 - Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.cpp | 308 --- Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h | 311 --- .../GUI/Qt/src/sofa/gui/qt/DialogAddObject.ui | 235 -- .../sofa/gui/qt/DisplayFlagsDataWidget.cpp | 220 -- .../src/sofa/gui/qt/DisplayFlagsDataWidget.h | 112 - .../Qt/src/sofa/gui/qt/Doc_Viewer/index.html | 284 -- .../gui/qt/Doc_Viewer/index_fichiers/GUI.png | Bin 8483 -> 0 bytes .../index_fichiers/GUI_caption0.png | Bin 69466 -> 0 bytes .../index_fichiers/GUI_caption1.png | Bin 154800 -> 0 bytes .../Doc_Viewer/index_fichiers/Tab_graph.png | Bin 7561 -> 0 bytes .../qt/Doc_Viewer/index_fichiers/Tab_show.png | Bin 9293 -> 0 bytes .../Doc_Viewer/index_fichiers/Tab_stats.png | Bin 6197 -> 0 bytes .../Doc_Viewer/index_fichiers/VIewerOGRE.png | Bin 320324 -> 0 bytes .../qt/Doc_Viewer/index_fichiers/Viewer.png | Bin 10961 -> 0 bytes .../GUI/Qt/src/sofa/gui/qt/FileManagement.cpp | 120 - Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.h | 42 - Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.cpp | 138 - Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.h | 68 - Sofa/GUI/Qt/src/sofa/gui/qt/GUI.ui | 1008 ------- Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.cpp | 526 ---- Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.h | 70 - Sofa/GUI/Qt/src/sofa/gui/qt/GenericWidget.h | 84 - .../Qt/src/sofa/gui/qt/GraphDataWidget.cpp | 151 -- Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.h | 385 --- .../sofa/gui/qt/GraphListenerQListView.cpp | 763 ------ .../src/sofa/gui/qt/GraphListenerQListView.h | 96 - Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.cpp | 362 --- Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.h | 88 - Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.cpp | 119 - Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.h | 189 -- .../Qt/src/sofa/gui/qt/MaterialDataWidget.cpp | 245 -- .../Qt/src/sofa/gui/qt/MaterialDataWidget.h | 123 - Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.cpp | 568 ---- Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.h | 188 -- Sofa/GUI/Qt/src/sofa/gui/qt/MouseManager.ui | 104 - .../src/sofa/gui/qt/PickHandlerCallBacks.cpp | 107 - .../Qt/src/sofa/gui/qt/PickHandlerCallBacks.h | 64 - Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.cpp | 173 -- Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.h | 88 - Sofa/GUI/Qt/src/sofa/gui/qt/PluginManager.ui | 186 -- .../sofa/gui/qt/QDataDescriptionWidget.cpp | 193 -- .../src/sofa/gui/qt/QDataDescriptionWidget.h | 51 - .../Qt/src/sofa/gui/qt/QDisplayDataWidget.cpp | 351 --- .../Qt/src/sofa/gui/qt/QDisplayDataWidget.h | 131 - .../Qt/src/sofa/gui/qt/QDisplayLinkWidget.cpp | 204 -- .../Qt/src/sofa/gui/qt/QDisplayLinkWidget.h | 108 - .../sofa/gui/qt/QDisplayPropertyWidget.cpp | 668 ----- .../src/sofa/gui/qt/QDisplayPropertyWidget.h | 155 -- .../Qt/src/sofa/gui/qt/QEnergyStatWidget.cpp | 81 - .../Qt/src/sofa/gui/qt/QEnergyStatWidget.h | 53 - .../Qt/src/sofa/gui/qt/QGraphStatWidget.cpp | 163 -- .../GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.h | 99 - .../sofa/gui/qt/QMenuFilesRecentlyOpened.cpp | 61 - .../sofa/gui/qt/QMenuFilesRecentlyOpened.h | 49 - .../gui/qt/QModelViewTableDataContainer.h | 751 ------ .../sofa/gui/qt/QModelViewTableUpdater.cpp | 127 - .../src/sofa/gui/qt/QModelViewTableUpdater.h | 65 - .../src/sofa/gui/qt/QMomentumStatWidget.cpp | 81 - .../Qt/src/sofa/gui/qt/QMomentumStatWidget.h | 52 - .../Qt/src/sofa/gui/qt/QMouseOperations.cpp | 426 --- .../GUI/Qt/src/sofa/gui/qt/QMouseOperations.h | 190 -- .../gui/qt/QMouseWheelAdjustementGuard.cpp | 45 - .../sofa/gui/qt/QMouseWheelAdjustementGuard.h | 46 - .../Qt/src/sofa/gui/qt/QRGBAColorPicker.cpp | 168 -- .../GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.h | 85 - Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.cpp | 744 ------ Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.h | 174 -- .../Qt/src/sofa/gui/qt/QSofaStatWidget.cpp | 147 -- Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.h | 66 - .../Qt/src/sofa/gui/qt/QTableDataContainer.h | 736 ------ Sofa/GUI/Qt/src/sofa/gui/qt/QTableUpdater.h | 80 - .../sofa/gui/qt/QTabulationModifyObject.cpp | 159 -- .../src/sofa/gui/qt/QTabulationModifyObject.h | 93 - .../src/sofa/gui/qt/QTransformationWidget.cpp | 144 - .../src/sofa/gui/qt/QTransformationWidget.h | 57 - .../src/sofa/gui/qt/QVisitorControlPanel.cpp | 142 - .../Qt/src/sofa/gui/qt/QVisitorControlPanel.h | 54 - .../src/sofa/gui/qt/RGBAColorDataWidget.cpp | 61 - .../Qt/src/sofa/gui/qt/RGBAColorDataWidget.h | 75 - Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.cpp | 2335 ----------------- Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.h | 437 --- .../Qt/src/sofa/gui/qt/SimpleDataWidget.cpp | 352 --- .../GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h | 1031 -------- .../Qt/src/sofa/gui/qt/SofaMouseManager.cpp | 157 -- .../GUI/Qt/src/sofa/gui/qt/SofaMouseManager.h | 67 - .../Qt/src/sofa/gui/qt/SofaPluginManager.cpp | 336 --- .../Qt/src/sofa/gui/qt/SofaPluginManager.h | 65 - .../src/sofa/gui/qt/SofaSceneGraphWidget.cpp | 71 - .../Qt/src/sofa/gui/qt/SofaSceneGraphWidget.h | 118 - .../sofa/gui/qt/SofaVideoRecorderManager.cpp | 167 -- .../sofa/gui/qt/SofaVideoRecorderManager.h | 110 - .../src/sofa/gui/qt/SofaWindowDataGraph.cpp | 270 -- .../Qt/src/sofa/gui/qt/SofaWindowDataGraph.h | 87 - .../Qt/src/sofa/gui/qt/SofaWindowProfiler.cpp | 763 ------ .../Qt/src/sofa/gui/qt/SofaWindowProfiler.h | 265 -- .../Qt/src/sofa/gui/qt/StructDataWidget.cpp | 43 - .../GUI/Qt/src/sofa/gui/qt/StructDataWidget.h | 564 ---- .../Qt/src/sofa/gui/qt/TableDataWidget.cpp | 128 - Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.h | 47 - .../src/sofa/gui/qt/VideoRecorderManager.ui | 188 -- Sofa/GUI/Qt/src/sofa/gui/qt/VisitorGUI.ui | 89 - .../Qt/src/sofa/gui/qt/WDoubleLineEdit.cpp | 158 -- Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.h | 101 - Sofa/GUI/Qt/src/sofa/gui/qt/WindowProfiler.ui | 233 -- Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.cpp | 276 -- Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.h | 125 - Sofa/GUI/Qt/src/sofa/gui/qt/config.h.in | 52 - .../qt/dataGraph/SofaComponentNodeModel.cpp | 213 -- .../gui/qt/dataGraph/SofaComponentNodeModel.h | 119 - Sofa/GUI/Qt/src/sofa/gui/qt/fwd.h | 30 - Sofa/GUI/Qt/src/sofa/gui/qt/init.cpp | 78 - Sofa/GUI/Qt/src/sofa/gui/qt/init.h | 28 - .../Qt/src/sofa/gui/qt/panels/QDocBrowser.cpp | 318 --- .../Qt/src/sofa/gui/qt/panels/QDocBrowser.h | 90 - Sofa/GUI/Qt/src/sofa/gui/qt/qt.conf.h | 137 - .../Qt/src/sofa/gui/qt/resources/RealGUI.qrc | 9 - .../src/sofa/gui/qt/resources/icons/back.png | Bin 519 -> 0 bytes .../src/sofa/gui/qt/resources/icons/back.xpm | 55 - .../gui/qt/resources/icons/collapseAll.svg | 63 - .../sofa/gui/qt/resources/icons/expandAll.svg | 70 - .../sofa/gui/qt/resources/icons/graphicon.ico | Bin 1406 -> 0 bytes .../src/sofa/gui/qt/resources/icons/home.png | Bin 1279 -> 0 bytes .../src/sofa/gui/qt/resources/icons/home.xpm | 150 -- .../sofa/gui/qt/resources/icons/icondata.xpm | 32 - .../sofa/gui/qt/resources/icons/iconerror.xpm | 27 - .../sofa/gui/qt/resources/icons/iconinfo.xpm | 27 - .../gui/qt/resources/icons/iconmultinode.xpm | 27 - .../sofa/gui/qt/resources/icons/iconnode.xpm | 26 - .../sofa/gui/qt/resources/icons/iconsleep.xpm | 26 - .../gui/qt/resources/icons/iconwarning.xpm | 27 - .../sofa/gui/qt/resources/icons/openFile.png | Bin 1247 -> 0 bytes .../icons/sceneGraphRefresh-dirty.svg | 205 -- .../icons/sceneGraphRefresh-locked.svg | 199 -- .../icons/sceneGraphRefresh-unlocked.svg | 201 -- .../src/sofa/gui/qt/sofa-logo-alpha-text.png | Bin 34666 -> 0 bytes .../Qt/src/sofa/gui/qt/viewer/EngineBackend.h | 53 - .../Qt/src/sofa/gui/qt/viewer/GLBackend.cpp | 154 -- .../GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.h | 60 - .../src/sofa/gui/qt/viewer/OglModelPolicy.cpp | 48 - .../src/sofa/gui/qt/viewer/OglModelPolicy.h | 57 - .../Qt/src/sofa/gui/qt/viewer/SofaViewer.cpp | 554 ---- .../Qt/src/sofa/gui/qt/viewer/SofaViewer.h | 103 - .../sofa/gui/qt/viewer/VisualModelPolicy.cpp | 38 - .../sofa/gui/qt/viewer/VisualModelPolicy.h | 41 - .../src/sofa/gui/qt/viewer/qgl/QtGLViewer.cpp | 1122 -------- .../src/sofa/gui/qt/viewer/qgl/QtGLViewer.h | 232 -- .../Qt/src/sofa/gui/qt/viewer/qt/QtViewer.cpp | 1558 ----------- .../Qt/src/sofa/gui/qt/viewer/qt/QtViewer.h | 267 -- .../src/sofa/gui/qt/viewer/qt/graphicon.ico | Bin 1406 -> 0 bytes .../Qt/src/sofa/gui/qt/viewer/qt/iconnode.xpm | 26 - Sofa/GUI/Sofa.GUIConfig.cmake.in | 1 - Sofa/GUI/src/sofa/gui/init.cpp | 4 +- Sofa/framework/Config/CMakeLists.txt | 2 +- .../Config/cmake/SofaMacrosConfigure.cmake | 8 +- .../Config/cmake/SofaMacrosInstall.cmake | 28 +- .../Core/src/sofa/core/Multi2Mapping.h | 17 - .../Core/src/sofa/core/MultiMapping.h | 20 - .../behavior/MixedInteractionConstraint.h | 15 - .../src/sofa/helper/ComponentChange.cpp | 8 +- .../Helper/src/sofa/helper/Utils.cpp | 4 +- .../Helper/src/sofa/helper/config.h.in | 8 + .../src/sofa/helper/system/FileSystem.cpp | 21 + .../src/sofa/helper/system/FileSystem.h | 21 +- .../Helper/src/sofa/helper/visual/DrawTool.h | 3 +- .../Helper/test/system/FileSystem_test.cpp | 67 + .../Core/src/sofa/simulation/Node.cpp | 20 +- .../Simulation/Graph/test/Node_test.cpp | 55 + .../Simulation/Graph/test/Simulation_test.cpp | 3 +- .../AnimationLoopParallelScheduler.h | 11 - .../plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu | 30 + applications/projects/CMakeLists.txt | 3 +- .../projects/SceneChecking/CMakeLists.txt | 2 + .../SceneChecking/SceneCheckEmptyNodeName.cpp | 55 +- .../SceneChecking/SceneCheckEmptyNodeName.h | 23 +- .../Sofa.Qt/ExternalProjectConfig.cmake.in | 15 + applications/projects/runSofa/Main.cpp | 28 +- .../Backward/EulerImplicitSolver.scn | 2 +- examples/Component/SceneUtility/MakeAlias.scn | 9 - .../Component/SceneUtility/MakeDataAlias.scn | 9 - tools/postinstall-fixup/CMakeLists.txt | 30 +- .../linux-postinstall-fixup.sh | 72 +- .../macos-postinstall-fixup.sh | 34 +- 230 files changed, 2380 insertions(+), 33470 deletions(-) create mode 100644 .github/workflows/launch-perf-test.yml delete mode 100644 Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.cpp delete mode 100644 Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.h delete mode 100644 Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.cpp delete mode 100644 Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.h delete mode 100644 Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp delete mode 100644 Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp create mode 100644 Sofa/Component/StateContainer/tests/MechanicalObjectVOp_test.cpp delete mode 100644 Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.cpp delete mode 100644 Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.h delete mode 100644 Sofa/GUI/Qt/CMakeLists.txt delete mode 100644 Sofa/GUI/Qt/LICENSE.GPL.txt delete mode 100644 Sofa/GUI/Qt/Sofa.GUI.QtConfig.cmake.in delete mode 100644 Sofa/GUI/Qt/etc/Sofa.GUI.Qt.ini.in delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/AboutDialog.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/BaseGenGraphForm.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DialogAddObject.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index.html delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI_caption0.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI_caption1.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_graph.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_show.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_stats.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/VIewerOGRE.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Viewer.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GUI.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GenericWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.h delete mode 100755 Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.cpp delete mode 100755 Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/MouseManager.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/PluginManager.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableDataContainer.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTableDataContainer.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTableUpdater.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/VideoRecorderManager.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/VisitorGUI.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/WindowProfiler.ui delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/config.h.in delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/fwd.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/init.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/init.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/qt.conf.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/RealGUI.qrc delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/collapseAll.svg delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/expandAll.svg delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/graphicon.ico delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/home.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/home.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/icondata.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconerror.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconinfo.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconmultinode.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconnode.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconsleep.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconwarning.xpm delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/openFile.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-dirty.svg delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-locked.svg delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-unlocked.svg delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/sofa-logo-alpha-text.png delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/EngineBackend.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.cpp delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.h delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/graphicon.ico delete mode 100644 Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/iconnode.xpm rename Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.cpp => applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.cpp (59%) rename Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.h => applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.h (71%) create mode 100644 applications/projects/Sofa.Qt/ExternalProjectConfig.cmake.in delete mode 100644 examples/Component/SceneUtility/MakeAlias.scn delete mode 100644 examples/Component/SceneUtility/MakeDataAlias.scn diff --git a/.github/workflows/launch-perf-test.yml b/.github/workflows/launch-perf-test.yml new file mode 100644 index 00000000000..7e2777d3ec5 --- /dev/null +++ b/.github/workflows/launch-perf-test.yml @@ -0,0 +1,21 @@ +name: Launch performance testing +on: + push: + branches: + - master +jobs: + run: + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'sofa-framework' }} + + steps: + - name: Launch performance regression test + run: | + sudo apt install curl + + curl -L -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.PERF_REG_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/sofa-framework/PerformanceRegression/dispatches \ + -d '{"event_type":"Launch perf test from SOFA commit","client_payload":{"branch":"master","commit_hash":"${{ github.sha }}"}}' diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl index f49fedf5602..d4d7b88c52e 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/AugmentedLagrangianResponse.inl @@ -42,8 +42,8 @@ AugmentedLagrangianResponse template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > AugmentedLagrangianResponse::AugmentedLagrangianResponse(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod) : BaseUnilateralContactResponse(model1,model2,intersectionMethod) - , d_mu (initData(&d_mu, 0.0, "mu", "Friction coefficient (0 for frictionless contacts)")) - , d_epsilon (initData(&d_epsilon, 0.0, "epsilon", "Penalty parameter. It can be think of as a proportional controller, the Lagrange multiplier is augmented by the violation multiplied by this factor at each solving iteration.")) + , d_mu (initData(&d_mu, 0.0_sreal, "mu", "Friction coefficient (0 for frictionless contacts)")) + , d_epsilon (initData(&d_epsilon, 0.0_sreal, "epsilon", "Penalty parameter. It can be thought of as a proportional controller, the Lagrange multiplier is augmented by the violation multiplied by this factor at each solving iteration.")) { } diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h index 9c9869e53d5..d5a67173928 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.h @@ -49,12 +49,12 @@ class FrictionContact : public BaseUnilateralContactResponse MechanicalState1; typedef core::behavior::MechanicalState MechanicalState2; - Data d_mu; ///< friction parameter + Data d_mu; ///< friction parameter FrictionContact(); FrictionContact(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod); - virtual ~FrictionContact() = default; + ~FrictionContact() override = default; virtual constraint::lagrangian::model::UnilateralLagrangianContactParameters getParameterFromDatas() const override; virtual void setupConstraint(MechanicalState1 *,MechanicalState2 *) override; diff --git a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl index 0d2d1b43cb0..45768288849 100644 --- a/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl +++ b/Sofa/Component/Collision/Response/Contact/src/sofa/component/collision/response/contact/FrictionContact.inl @@ -42,7 +42,7 @@ FrictionContact::FrictionCo template < class TCollisionModel1, class TCollisionModel2, class ResponseDataTypes > FrictionContact::FrictionContact(CollisionModel1* model1, CollisionModel2* model2, Intersection* intersectionMethod) : BaseUnilateralContactResponse(model1,model2,intersectionMethod) - , d_mu (initData(&d_mu, 0.8, "mu", "Friction coefficient (0 for frictionless contacts)")) + , d_mu (initData(&d_mu, 0.8_sreal, "mu", "Friction coefficient (0 for frictionless contacts)")) { } diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralConstraintResolution.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralConstraintResolution.h index 10af8e5ab20..2a821314be6 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralConstraintResolution.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralConstraintResolution.h @@ -68,7 +68,7 @@ class BilateralConstraintResolution3Dof : public ConstraintResolution { public: - BilateralConstraintResolution3Dof(sofa::type::Vec3d* vec = nullptr) + BilateralConstraintResolution3Dof(sofa::type::Vec3* vec = nullptr) : ConstraintResolution(3) , _f(vec) { @@ -130,7 +130,7 @@ class BilateralConstraintResolution3Dof : public ConstraintResolution protected: sofa::type::Mat<3,3,SReal> invW; - sofa::type::Vec3d* _f; + sofa::type::Vec3* _f; }; class BilateralConstraintResolutionNDof : public ConstraintResolution diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h index 9b693e076e3..6208918eb92 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h @@ -49,7 +49,7 @@ using sofa::core::ConstraintParams ; using sofa::core::ConstVecCoordId; using sofa::linearalgebra::BaseVector ; -using sofa::type::Vec3d; +using sofa::type::Vec3; using sofa::type::Quat ; using sofa::defaulttype::Rigid3Types ; @@ -123,7 +123,7 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology1; ///< Link to be set to the first topology container in order to support topological changes SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology2; ///< Link to be set to the second topology container in order to support topological changes - std::vector prevForces; + std::vector prevForces; BilateralLagrangianConstraint(MechanicalState* object1, MechanicalState* object2) ; BilateralLagrangianConstraint(MechanicalState* object) ; diff --git a/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp index eb0282269cd..af2a4b83763 100644 --- a/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/MeshExporter_test.cpp @@ -19,6 +19,8 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ +#include + #include using std::vector; diff --git a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp index 1f8429d1224..61e2cdf2e72 100644 --- a/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp +++ b/Sofa/Component/IO/Mesh/tests/STLExporter_test.cpp @@ -90,25 +90,22 @@ class STLExporter_test : public BaseSimulationTest { } } - void checkBasicBehavior(const std::string& filename, std::vector pathes){ + void checkBasicBehavior(const std::string& filename, std::vector pathes) + { dataPath = pathes ; EXPECT_MSG_NOEMIT(Error, Warning) ; - std::stringstream scene1; - scene1 << - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("testscene", scene1.str().c_str()); - - ASSERT_NE(root.get(), nullptr) << scene1.str() ; - root->init(sofa::core::execparams::defaultInstance()) ; + + const Node::SPtr root = sofa::simpleapi::createRootNode(sofa::simulation::getSimulation(), "root", {{"gravity", "0 0 0"}}); + sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"position", "0 1 2 3 4 5 6 7 8 9"}}); + sofa::simpleapi::createObject(root, "MeshOBJLoader", {{"name", "loader"}, {"filename", "mesh/liver-smooth.obj"}}); + const Node::SPtr visualNode = sofa::simpleapi::createChild(root, "Visual"); + sofa::simpleapi::createObject(visualNode, "VisualModel", {{"src", "@../loader"}}); + sofa::simpleapi::createObject(visualNode, "STLExporter", {{"name", "exporter1"}, {"filename", filename}, {"exportAtBegin", "true"}}); + + ASSERT_NE(root.get(), nullptr); + sofa::simulation::node::initRoot(root.get()); // SimulationInitDoneEvent is used to trigger exportAtBegin SimulationInitDoneEvent endInit; @@ -119,32 +116,27 @@ class STLExporter_test : public BaseSimulationTest { for(auto& pathToCheck : pathes) { - EXPECT_TRUE( FileSystem::exists(pathToCheck) ) << "Problem with '" << pathToCheck << "'"<< std::endl - << "================= scene dump ===========================" - << scene1.str() ; + EXPECT_TRUE( FileSystem::exists(pathToCheck) ); } } - void checkSimulationWriteEachNbStep(const std::string& filename, std::vector pathes, unsigned int numstep){ + void checkSimulationWriteEachNbStep(const std::string& filename, std::vector pathes, unsigned int numstep) + { dataPath = pathes ; EXPECT_MSG_NOEMIT(Error, Warning) ; - std::stringstream scene1; - scene1 << - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("testscene", scene1.str().c_str()); + + const Node::SPtr root = sofa::simpleapi::createRootNode(sofa::simulation::getSimulation(), "root", {{"gravity", "0 0 0"}}); + sofa::simpleapi::createObject(root, "DefaultAnimationLoop"); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"position", "0 1 2 3 4 5 6 7 8 9"}}); + sofa::simpleapi::createObject(root, "MeshOBJLoader", {{"name", "loader"}, {"filename", "mesh/liver-smooth.obj"}}); + const Node::SPtr visualNode = sofa::simpleapi::createChild(root, "Visual"); + sofa::simpleapi::createObject(visualNode, "VisualModel", {{"src", "@../loader"}}); + sofa::simpleapi::createObject(visualNode, "STLExporter", {{"name", "exporterA"}, {"filename", filename}, {"exportEveryNumberOfSteps", "5"}}); ASSERT_NE(root.get(), nullptr) ; - root->init(sofa::core::execparams::defaultInstance()) ; + sofa::simulation::node::initRoot(root.get()); for(unsigned int i=0;i #include +#include namespace sofa::component::odesolver::backward { @@ -44,20 +45,24 @@ EulerImplicitSolver::EulerImplicitSolver() , d_trapezoidalScheme( initData(&d_trapezoidalScheme,false,"trapezoidalScheme","Boolean to use the trapezoidal scheme instead of the implicit Euler scheme and get second order accuracy in time (false by default)") ) , d_solveConstraint(initData(&d_solveConstraint, false, "solveConstraint", "Apply ConstraintSolver (requires a ConstraintSolver in the same node as this solver, disabled by by default for now)") ) , d_threadSafeVisitor(initData(&d_threadSafeVisitor, false, "threadSafeVisitor", "If true, do not use realloc and free visitors in fwdInteractionForceField.")) + , d_computeResidual(initData(&d_computeResidual, false, "computeResidual", "If true, the residual is computed at the end of the solving")) + , d_residual(initData(&d_residual, std::numeric_limits::max(), "residual", "Residual norm at the end of the free-motion solving")) { f_rayleighStiffness.setOriginalData(&d_rayleighStiffness); f_rayleighMass.setOriginalData(&d_rayleighMass); f_velocityDamping.setOriginalData(&d_velocityDamping); f_firstOrder.setOriginalData(&d_firstOrder); f_solveConstraint.setOriginalData(&d_solveConstraint); - } void EulerImplicitSolver::init() { + sofa::core::behavior::OdeSolver::init(); + sofa::core::behavior::LinearSolverAccessor::init(); + if (!this->getTags().empty()) { - msg_info() << "EulerImplicitSolver: responsible for the following objects with tags " << this->getTags() << " :"; + msg_info() << "Responsible for the following objects with tags " << this->getTags() << " :"; type::vector objs; this->getContext()->get(&objs,this->getTags(),sofa::core::objectmodel::BaseContext::SearchDown); for (const auto* obj : objs) @@ -65,15 +70,19 @@ void EulerImplicitSolver::init() msg_info() << " " << obj->getClassName() << ' ' << obj->getName(); } } - sofa::core::behavior::OdeSolver::init(); - sofa::core::behavior::LinearSolverAccessor::init(); + + simulation::common::VectorOperations vop(sofa::core::execparams::defaultInstance(), this->getContext()); + reallocSolutionVector(&vop); + reallocRightHandSideVector(&vop); } void EulerImplicitSolver::cleanup() { - // free the locally created vector x (including eventual external mechanical states linked by an InteractionForceField) + // free the locally created vectors (including eventual external mechanical states linked by an InteractionForceField) sofa::simulation::common::VectorOperations vop( core::execparams::defaultInstance(), this->getContext() ); vop.v_free(x.id(), !d_threadSafeVisitor.getValue(), true); + vop.v_free(b.id(), !d_threadSafeVisitor.getValue(), true); + vop.v_free(m_residual.id(), !d_threadSafeVisitor.getValue(), true); } void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa::core::MultiVecCoordId xResult, sofa::core::MultiVecDerivId vResult) @@ -86,7 +95,6 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: MultiVecCoord pos(&vop, core::vec_id::write_access::position ); MultiVecDeriv vel(&vop, core::vec_id::write_access::velocity ); MultiVecDeriv f(&vop, core::vec_id::write_access::force ); - MultiVecDeriv b(&vop, true, core::VecIdProperties{"RHS", GetClass()->className}); MultiVecCoord newPos(&vop, xResult ); MultiVecDeriv newVel(&vop, vResult ); @@ -98,8 +106,8 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: MultiVecDeriv dx(&vop, core::vec_id::write_access::dx); dx.realloc(&vop, !d_threadSafeVisitor.getValue(), true); - x.realloc(&vop, !d_threadSafeVisitor.getValue(), true, core::VecIdProperties{"solution", GetClass()->className}); - + reallocSolutionVector(&vop); + reallocRightHandSideVector(&vop); #ifdef SOFA_DUMP_VISITOR_INFO sofa::simulation::Visitor::printCloseNode("SolverVectorAllocation"); @@ -125,7 +133,7 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: // compute the net forces at the beginning of the time step mop.computeForce(f); //f = Kx + Bv - msg_info() << "EulerImplicitSolver, initial f = " << f; + msg_info() << "initial f = " << f; } { @@ -141,7 +149,7 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: // force in the current configuration b.eq(f); // b = f - msg_info() << "EulerImplicitSolver, f = " << f; + msg_info() << "f = " << f; // add the change of force due to stiffness + Rayleigh damping mop.addMBKv(b, core::MatricesFactors::M(-d_rayleighMass.getValue()), @@ -152,11 +160,11 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: b.teq(h); // b = h(f + ( rm M + (h+rs) K ) v ) } - msg_info() << "EulerImplicitSolver, b = " << b; + msg_info() << "b = " << b; mop.projectResponse(b); // b is projected to the constrained space - msg_info() << "EulerImplicitSolver, projected b = " << b; + msg_info() << "projected b = " << b; } { @@ -299,10 +307,38 @@ void EulerImplicitSolver::solve(const core::ExecParams* params, SReal dt, sofa:: mop.projectVelocity(newVel); mop.propagateX(newPos); mop.propagateV(newVel); - msg_info() << "EulerImplicitSolver, final x = " << newPos; - msg_info() << "EulerImplicitSolver, final v = " << newVel; + msg_info() << "final x = " << newPos; + msg_info() << "final v = " << newVel; + mop.computeForce(f); + msg_info() << "final f = " << f; + } + + if (d_computeResidual.getValue()) + { + reallocResidualVector(&vop); + + // r = 0 + vop.v_clear(m_residual); + + // r += M (v - v_n) + { + core::behavior::MultiVecDeriv tmp(&vop); + + vop.v_eq(tmp, newVel); + vop.v_peq(tmp, vel, -1); + mop.addMdx(m_residual, tmp); + } + + // r += - dt * F mop.computeForce(f); - msg_info() << "EulerImplicitSolver, final f = " << f; + vop.v_peq(m_residual, f, -dt); + + mop.projectResponse(m_residual); + + vop.v_dot(m_residual, m_residual); + d_residual.setValue(vop.finish()); + + msg_info() << "Residual norm: " << std::setw(6) << vop.finish(); } } @@ -338,13 +374,29 @@ SReal EulerImplicitSolver::getSolutionIntegrationFactor(int outputDerivative) co SReal EulerImplicitSolver::getSolutionIntegrationFactor(int outputDerivative, SReal dt) const { - const SReal vect[3] = { dt, 1, 1/dt}; + const SReal vect[3] = {dt, 1, 1 / dt}; if (outputDerivative >= 3) return 0; else return vect[outputDerivative]; } +void EulerImplicitSolver::reallocSolutionVector(sofa::simulation::common::VectorOperations* vop) +{ + x.realloc(vop, !d_threadSafeVisitor.getValue(), true, + core::VecIdProperties{.label = "solution", .group = GetClass()->className}); +} +void EulerImplicitSolver::reallocRightHandSideVector(sofa::simulation::common::VectorOperations* vop) +{ + b.realloc(vop, !d_threadSafeVisitor.getValue(), true, + core::VecIdProperties{.label = "RHS", .group = GetClass()->className}); +} +void EulerImplicitSolver::reallocResidualVector(sofa::simulation::common::VectorOperations* vop) +{ + m_residual.realloc(vop, !d_threadSafeVisitor.getValue(), true, + core::VecIdProperties{.label = "residual", .group = GetClass()->className}); +} + void registerEulerImplicitSolver(sofa::core::ObjectFactory* factory) { factory->registerObjects(core::ObjectRegistrationData("Time integrator using implicit backward Euler scheme.") diff --git a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h index ccebff28494..c9b793d794a 100644 --- a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h +++ b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/EulerImplicitSolver.h @@ -27,6 +27,11 @@ #include +namespace sofa::simulation::common +{ +class VectorOperations; +} + namespace sofa::component::odesolver::backward { @@ -129,6 +134,9 @@ class SOFA_COMPONENT_ODESOLVER_BACKWARD_API EulerImplicitSolver : Data d_solveConstraint; ///< Apply ConstraintSolver (requires a ConstraintSolver in the same node as this solver, disabled by by default for now) Data d_threadSafeVisitor; ///< If true, do not use realloc and free visitors in fwdInteractionForceField. + Data d_computeResidual; + Data d_residual; + protected: EulerImplicitSolver(); public: @@ -182,6 +190,15 @@ class SOFA_COMPONENT_ODESOLVER_BACKWARD_API EulerImplicitSolver : /// the solution vector is stored for warm-start core::behavior::MultiVecDeriv x; + /// Right-hand side vector + core::behavior::MultiVecDeriv b; + + /// Residual vector (optionally computed) + core::behavior::MultiVecDeriv m_residual; + + void reallocSolutionVector(sofa::simulation::common::VectorOperations* vop); + void reallocRightHandSideVector(sofa::simulation::common::VectorOperations* vop); + void reallocResidualVector(sofa::simulation::common::VectorOperations* vop); }; } // namespace sofa::component::odesolver::backward diff --git a/Sofa/Component/Playback/src/sofa/component/playback/CompareState.cpp b/Sofa/Component/Playback/src/sofa/component/playback/CompareState.cpp index ead0a2e58aa..989ea02d5bb 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/CompareState.cpp +++ b/Sofa/Component/Playback/src/sofa/component/playback/CompareState.cpp @@ -263,7 +263,7 @@ void CompareState::draw(const core::visual::VisualParams* vparams) CompareStateCreator::CompareStateCreator(const core::ExecParams* params) : Visitor(params) , sceneName("") -#if SOFAGENERALLOADER_HAVE_ZLIB +#if SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB , extension(".txt.gz") #else , extension(".txt") @@ -277,7 +277,7 @@ CompareStateCreator::CompareStateCreator(const core::ExecParams* params) CompareStateCreator::CompareStateCreator(const std::string &n, const core::ExecParams* params, bool i, int c) : Visitor(params) , sceneName(n) -#if SOFAGENERALLOADER_HAVE_ZLIB +#if SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB , extension(".txt.gz") #else , extension(".txt") diff --git a/Sofa/Component/Playback/src/sofa/component/playback/CompareTopology.cpp b/Sofa/Component/Playback/src/sofa/component/playback/CompareTopology.cpp index b6a20b6fe7f..10b0a1bde72 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/CompareTopology.cpp +++ b/Sofa/Component/Playback/src/sofa/component/playback/CompareTopology.cpp @@ -298,7 +298,7 @@ void CompareTopology::processCompareTopology() CompareTopologyCreator::CompareTopologyCreator(const core::ExecParams* params) :Visitor(params) , sceneName("") -#if SOFAGENERALLOADER_HAVE_ZLIB +#if SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB , extension(".txt.gz") #else , extension(".txt") @@ -312,7 +312,7 @@ CompareTopologyCreator::CompareTopologyCreator(const core::ExecParams* params) CompareTopologyCreator::CompareTopologyCreator(const std::string &n, const core::ExecParams* params, bool i, int c) :Visitor(params) , sceneName(n) -#if SOFAGENERALLOADER_HAVE_ZLIB +#if SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB , extension(".txt.gz") #else , extension(".txt") diff --git a/Sofa/Component/Playback/src/sofa/component/playback/config.h.in b/Sofa/Component/Playback/src/sofa/component/playback/config.h.in index cdd661afb43..588d17cb0ed 100644 --- a/Sofa/Component/Playback/src/sofa/component/playback/config.h.in +++ b/Sofa/Component/Playback/src/sofa/component/playback/config.h.in @@ -39,15 +39,6 @@ namespace sofa::component::playback constexpr const char* MODULE_VERSION = "@PROJECT_VERSION@"; } // namespace sofa::component::playback -// Keep the previous macros -// This backward compatibility will be removed at v23.06 -#ifndef SOFAGENERALLOADER_HAVE_ZLIB -#define SOFAGENERALLOADER_HAVE_ZLIB SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB -#endif -#ifndef SOFAEXPORTER_HAVE_ZLIB -#define SOFAEXPORTER_HAVE_ZLIB SOFA_COMPONENT_PLAYBACK_HAVE_ZLIB -#endif - #ifdef SOFA_BUILD_SOFA_COMPONENT_PLAYBACK #define SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_PLAYBACK() #else diff --git a/Sofa/Component/SceneUtility/CMakeLists.txt b/Sofa/Component/SceneUtility/CMakeLists.txt index eb3562d6a15..dfebecb2701 100644 --- a/Sofa/Component/SceneUtility/CMakeLists.txt +++ b/Sofa/Component/SceneUtility/CMakeLists.txt @@ -9,8 +9,6 @@ set(HEADER_FILES ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/AddResourceRepository.h ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/APIVersion.h ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/InfoComponent.h - ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MakeAliasComponent.h - ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MakeDataAliasComponent.h ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MessageHandlerComponent.h ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/PauseAnimation.h ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/PauseAnimationOnEvent.h @@ -21,8 +19,6 @@ set(SOURCE_FILES ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/AddResourceRepository.cpp ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/APIVersion.cpp ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/InfoComponent.cpp - ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MakeAliasComponent.cpp - ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MakeDataAliasComponent.cpp ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/MessageHandlerComponent.cpp ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/PauseAnimation.cpp ${SOFACOMPONENTSCENEUTILITY_SOURCE_DIR}/PauseAnimationOnEvent.cpp diff --git a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.cpp b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.cpp deleted file mode 100644 index 0698496c34b..00000000000 --- a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -using sofa::core::ObjectFactory ; - -using sofa::core::objectmodel::ComponentState ; - -#include - -using std::string; - -namespace sofa::component::sceneutility -{ - -namespace makealiascomponent -{ - -MakeAliasComponent::MakeAliasComponent() : - d_targetcomponent(initData(&d_targetcomponent, "targetcomponent", "The component class for which to create an alias.")) - ,d_alias(initData(&d_alias, "alias", "The new alias of the component.")) -{ - d_componentState.setValue(ComponentState::Invalid) ; -} - -void MakeAliasComponent::parse ( core::objectmodel::BaseObjectDescription* arg ) -{ - BaseObject::parse(arg) ; - - const char* target=arg->getAttribute("targetcomponent") ; - if(target==nullptr) - { - msg_error(this) << "The mandatory 'targetcomponent' attribute is missing. " - "The component is disabled. " - "To remove this error message you need to add a targetcomponent attribute pointing to a valid component's ClassName."; - return ; - } - const string starget(target) ; - - const char* alias=arg->getAttribute("alias") ; - if(alias==nullptr) - { - msg_error(this) << "The mandatory 'alias' attribute is missing. " - "The component is disabled. " - "To remove this error message you need to add an alias attribute with a valid string component's ClassName."; - return ; - } - const string salias(alias); - - if(!ObjectFactory::getInstance()->hasCreator(starget)) - { - msg_error(this) << "The provided attribute 'targetcomponent= "<< starget << "' does not correspond to a valid component ClassName " - "The component is disabled. " - "To remove this error message you need to fix your scene and provide a valid component ClassName in the 'targetcomponent' attribute. "; - return ; - } - - ObjectFactory::getInstance()->addAlias(salias, starget); - - d_componentState.setValue(ComponentState::Valid) ; -} - -} // namespace makealiascomponent - -void registerMakeAliasComponent(sofa::core::ObjectFactory* factory) -{ - factory->registerObjects(core::ObjectRegistrationData("This object creates an alias to a component name to make the scene more readable.") - .add< MakeAliasComponent >()); -} - -} // namespace sofa::component::sceneutility diff --git a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.h b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.h deleted file mode 100644 index 96ccab239de..00000000000 --- a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeAliasComponent.h +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#include -#include -#include - -#include - -namespace sofa::component::sceneutility::makealiascomponent -{ - -/// I use a per-file namespace so that I can employ the 'using' keywords without -/// fearing it will leak names into the global namespace. When closing this namespace -/// selected object from this per-file namespace are then imported into their parent namespace. -/// for ease of use -/// -/// A component to add alias to other components. -class SOFA_COMPONENT_SCENEUTILITY_API MakeAliasComponent : public core::objectmodel::BaseObject -{ -public: - SOFA_CLASS(MakeAliasComponent, core::objectmodel::BaseObject); - - MakeAliasComponent() ; - ~MakeAliasComponent() override{} - - /// Inherited from BaseObject. - /// Parse the given description to assign values to this object's fields and - /// potentially other parameters. - void parse ( core::objectmodel::BaseObjectDescription* arg ) override; - - Data d_targetcomponent ; ///< The component class for which to create an alias. - Data d_alias ; ///< The new alias of the component. - - /// Returns the sofa class name. By default the name of the c++ class is exposed... but - /// Here we want it to be MakeAlias so we need to customize it. - /// More details on the name customization infrastructure is in NameDecoder.h - static std::string GetCustomClassName() - { - return "MakeAlias" ; - } -}; - -} // namespace sofa::component::sceneutility::makealiascomponent - -namespace sofa::component::sceneutility -{ -/// Import the component from the per-file namespace. -using makealiascomponent::MakeAliasComponent ; - -} // namespace sofa::component::sceneutility diff --git a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.cpp b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.cpp deleted file mode 100644 index 3f6ee73c225..00000000000 --- a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -using sofa::core::ObjectFactory ; - -using sofa::core::objectmodel::ComponentState ; - -#include - -using std::string; - -namespace sofa::component::sceneutility -{ - -namespace makedataaliascomponent -{ - -MakeDataAliasComponent::MakeDataAliasComponent() - : d_componentname(initData(&d_componentname, "componentname", "The component class for which to create an alias.")) - , d_dataname(initData(&d_dataname, "dataname", "The data field for which to create an alias.")) - , d_alias(initData(&d_alias, "alias", "The alias of the data field.")) -{ - d_componentState.setValue(ComponentState::Invalid) ; -} - -MakeDataAliasComponent::~MakeDataAliasComponent() -{ - if (m_hasAddedAlias) - { - ObjectFactory::ClassEntry& creatorentry = ObjectFactory::getInstance()->getEntry(d_componentname.getValue()); - auto& aliases = creatorentry.m_dataAlias[d_dataname.getValue()]; - const auto it = std::find(aliases.begin(), aliases.end(), d_alias.getValue()); - if (it != aliases.end()) - { - aliases.erase(std::remove(aliases.begin(), aliases.end(), d_alias.getValue()), aliases.end()); - } - } -} - -void MakeDataAliasComponent::parse ( core::objectmodel::BaseObjectDescription* arg ) -{ - BaseObject::parse(arg) ; - - const char* component=arg->getAttribute("componentname") ; - if(component==nullptr) - { - msg_error(this) << "The mandatory 'componentname' attribute is missing. " - "The component is disabled. " - "To remove this error message you need to add a targetcomponent attribute pointing to a valid component's ClassName."; - return ; - } - const string scomponent(component) ; - - - const char* dataname=arg->getAttribute("dataname") ; - if(dataname==nullptr) - { - msg_error(this) << "The mandatory 'dataname' attribute is missing. " - "The component is disabled. " - "To remove this error message you need to add a targetcomponent attribute pointing to a valid component's ClassName."; - return ; - } - - const char* alias=arg->getAttribute("alias") ; - if(alias==nullptr) - { - msg_error(this) << "The mandatory 'alias' attribute is missing. " - "The component is disabled. " - "To remove this error message you need to add an alias attribute with a valid string component's ClassName."; - return ; - } - const string salias(alias); - - if(!ObjectFactory::getInstance()->hasCreator(scomponent)){ - msg_error(this) << "The value '"<< scomponent << "' for 'componentname' does not correspond to a valid name. " - "The component is disabled. " - "To remove this error message you need to add a targetcomponent attribute pointing to a valid component's ClassName."; - return ; - } - - ObjectFactory::ClassEntry& creatorentry = ObjectFactory::getInstance()->getEntry(scomponent); - auto& aliases = creatorentry.m_dataAlias[dataname]; - const auto it = std::find(aliases.begin(), aliases.end(), salias); - if (it != aliases.end()) - { - aliases.push_back(salias); - m_hasAddedAlias = true; - } - - d_componentState.setValue(ComponentState::Valid); -} -} // namespace makedataaliascomponent - -void registerMakeDataAliasComponent(sofa::core::ObjectFactory* factory) -{ - factory->registerObjects(core::ObjectRegistrationData("This object creates an alias to a data field.") - .add< MakeDataAliasComponent >()); -} - -} // namespace sofa::component::sceneutility diff --git a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.h b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.h deleted file mode 100644 index eee41a045da..00000000000 --- a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/MakeDataAliasComponent.h +++ /dev/null @@ -1,76 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#include -#include -#include - -#include - -namespace sofa::component::sceneutility::makedataaliascomponent -{ -/// I use a per-file namespace so that I can employ the 'using' keywords without -/// fearing it will leak names into the global namespace. When closing this namespace -/// selected object from this per-file namespace are then imported into their parent namespace. -/// for ease of use - -/// A component to add alias to other components. -class SOFA_COMPONENT_SCENEUTILITY_API MakeDataAliasComponent : public core::objectmodel::BaseObject -{ -public: - SOFA_CLASS(MakeDataAliasComponent, core::objectmodel::BaseObject); - - MakeDataAliasComponent() ; - ~MakeDataAliasComponent() override; - - /// Inherited from BaseObject. - /// Parse the given description to assign values to this object's fields and - /// potentially other parameters. - void parse ( core::objectmodel::BaseObjectDescription* arg ) override; - - Data d_componentname ; ///< The component class for which to create an alias. - Data d_dataname ; ///< The data field for which to create an alias. - Data d_alias ; ///< The alias of the data field. - - /// Returns the sofa class name. By default the name of the c++ class is exposed... but - /// Here we want it to be MakeAlias so we need to customize it. - /// More details on the name customization infrastructure is in NameDecoder.h - static std::string GetCustomClassName() - { - return "MakeDataAlias" ; - } -private: - - bool m_hasAddedAlias { false }; -}; - -} // namespace sofa::component::sceneutility::makedataaliascomponent - -namespace sofa::component::sceneutility -{ -/// Import the component from the per-file namespace. -using makedataaliascomponent::MakeDataAliasComponent ; - -} // namespace sofa::component::sceneutility diff --git a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/init.cpp b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/init.cpp index 1f1dead21ae..ed5d28c77b9 100644 --- a/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/init.cpp +++ b/Sofa/Component/SceneUtility/src/sofa/component/sceneutility/init.cpp @@ -31,8 +31,6 @@ extern void registerAddPluginRepository(sofa::core::ObjectFactory* factory); extern void registerAPIVersion(sofa::core::ObjectFactory* factory); extern void registerFileMessageHandlerComponent(sofa::core::ObjectFactory* factory); extern void registerInfoComponent(sofa::core::ObjectFactory* factory); -extern void registerMakeAliasComponent(sofa::core::ObjectFactory* factory); -extern void registerMakeDataAliasComponent(sofa::core::ObjectFactory* factory); extern void registerMessageHandlerComponent(sofa::core::ObjectFactory* factory); extern void registerPauseAnimationOnEvent(sofa::core::ObjectFactory* factory); @@ -64,9 +62,7 @@ void registerObjects(sofa::core::ObjectFactory* factory) registerAddPluginRepository(factory); registerAPIVersion(factory); registerFileMessageHandlerComponent(factory); - registerInfoComponent(factory);; - registerMakeAliasComponent(factory); - registerMakeDataAliasComponent(factory); + registerInfoComponent(factory); registerMessageHandlerComponent(factory); registerPauseAnimationOnEvent(factory); } diff --git a/Sofa/Component/SceneUtility/tests/CMakeLists.txt b/Sofa/Component/SceneUtility/tests/CMakeLists.txt index 00292aa674e..ac128afddb6 100644 --- a/Sofa/Component/SceneUtility/tests/CMakeLists.txt +++ b/Sofa/Component/SceneUtility/tests/CMakeLists.txt @@ -4,8 +4,6 @@ project(Sofa.Component.SceneUtility_test) set(SOURCE_FILES AddResourceRepository_test.cpp - MakeAliasComponent_test.cpp - MakeDataAliasComponent_test.cpp MessageHandlerComponent_test.cpp ) diff --git a/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp b/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp deleted file mode 100644 index 552ad09b95a..00000000000 --- a/Sofa/Component/SceneUtility/tests/MakeAliasComponent_test.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -using std::string ; - -#include -#include - -#include -using sofa::simulation::graph::DAGSimulation ; - -#include -using sofa::simulation::Simulation ; - -#include -using sofa::simulation::Node ; - -#include -using sofa::simulation::SceneLoaderXML ; - -#include -using sofa::component::sceneutility::MakeAliasComponent ; - -//TODO(dmarchal): all these lines are ugly...this is too much for simple initialization stuff. -#include -using sofa::helper::logging::MessageDispatcher; -using sofa::helper::logging::MessageHandler; -using sofa::helper::logging::ConsoleMessageHandler; -using sofa::helper::logging::Message ; - -#include -using sofa::helper::logging::RichConsoleStyleMessageFormatter ; - -using sofa::core::objectmodel::ComponentState ; - -#include - -//TODO(dmarchal): handle properly the memory cycle of the simulation objects. -// now it is soo ugly... - -namespace makealiascomponent_test -{ - -MessageHandler* defaultHandler=nullptr; -Simulation* theSimulation = nullptr ; - -bool doInit(){ - return true; -} -bool inited = doInit(); - -void perTestInit() -{ - sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); - - theSimulation = sofa::simulation::getSimulation(); - - if(defaultHandler==nullptr) - defaultHandler=new ConsoleMessageHandler(&RichConsoleStyleMessageFormatter::getInstance()) ; - - /// THE TESTS HERE ARE NOT INHERITING FROM SOFA TEST SO WE NEED TO MANUALLY INSTALL THE HANDLER - /// DO NO REMOVE - MessageDispatcher::addHandler( sofa::testing::MainGtestMessageHandler::getInstance() ); -} - - -TEST(MakeAliasComponent, checkGracefullHandlingOfMissingAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - sofa::simulation::node::unload(root); -} - -TEST(MakeAliasComponent, checkGracefullHandlingOfMissingTargetAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - sofa::simulation::node::unload(root); -} - -TEST(MakeAliasComponent, checkGracefullHandlingOfMissingAliasAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - sofa::simulation::node::unload(root); -} - -TEST(MakeAliasComponent, checkGracefullHandlingOfInvalidTargetName) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - - const string scene = - " \n" - " \n" - " \n" - " \n" ; - - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - sofa::simulation::node::unload(root); -} - -TEST(MakeAliasComponent, checkValidBehavior) -{ - EXPECT_MSG_NOEMIT(Error) ; - - const string scene = - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeAliasComponent* component = nullptr; - root->getTreeObject(component) ; - - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Valid) ; - sofa::simulation::node::unload(root); -} - -} diff --git a/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp b/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp deleted file mode 100644 index 7a36ee55625..00000000000 --- a/Sofa/Component/SceneUtility/tests/MakeDataAliasComponent_test.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -using std::string ; - -#include -#include - -#include -using sofa::simulation::graph::DAGSimulation ; - -#include -using sofa::simulation::Simulation ; - -#include -using sofa::simulation::Node ; - -#include -using sofa::simulation::SceneLoaderXML ; - -#include -using sofa::component::sceneutility::MakeDataAliasComponent ; - -#include -using sofa::helper::logging::MessageDispatcher; -using sofa::helper::logging::MessageHandler; -using sofa::helper::logging::ConsoleMessageHandler; -using sofa::helper::logging::Message ; - - -using sofa::helper::logging::LogMessage ; - -#include -using sofa::helper::logging::RichConsoleStyleMessageFormatter ; - -using sofa::core::objectmodel::ComponentState ; - -#include - -namespace makedataaliascomponent_test -{ - -MessageHandler* defaultHandler=nullptr ; -Simulation* theSimulation = nullptr ; - -bool doInit(){ - return true; -} - -bool inited = doInit(); - -void perTestInit() -{ - sofa::simpleapi::importPlugin(Sofa.Component.SceneUtility); - sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); - - if(defaultHandler==nullptr) - defaultHandler=new ConsoleMessageHandler(&RichConsoleStyleMessageFormatter::getInstance()) ; - - /// THE TESTS HERE ARE NOT INHERITING FROM SOFA TEST SO WE NEED TO MANUALLY INSTALL THE HANDLER - /// DO NO REMOVE - MessageDispatcher::addHandler( sofa::testing::MainGtestMessageHandler::getInstance() ); -} - -TEST(MakeDataAliasComponent, checkGracefullHandlingOfMissingAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeDataAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - - sofa::simulation::node::unload(root); -} - -TEST(MakeDataAliasComponent, checkGracefullHandlingOfMissingTargetAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeDataAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - - sofa::simulation::node::unload(root); -} - -TEST(MakeDataAliasComponent, checkGracefullHandlingOfMissingAliasAttributes) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - - const string scene = - " " - " " - " " - " " ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeDataAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - - sofa::simulation::node::unload(root); -} - -TEST(MakeDataAliasComponent, checkGracefullHandlingOfInvalidTargetName) -{ - perTestInit(); - EXPECT_MSG_EMIT(Error) ; - - const string scene = - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeDataAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Invalid) ; - - sofa::simulation::node::unload(root); -} - -TEST(MakeDataAliasComponent, checkGracefullHandlingOfInvalidDataName) -{ - perTestInit(); - EXPECT_MSG_EMIT(Warning) ; - - const string scene = - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test1", scene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - MakeDataAliasComponent* component = nullptr; - - root->getTreeObject(component) ; - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Valid) ; - - sofa::simulation::node::unload(root); -} - -TEST(MakeDataAliasComponent, checkValidBehavior) -{ - EXPECT_MSG_NOEMIT(Error) ; - - const string ascene = - " \n" - " \n" - " \n" - " \n" - " \n" ; - - const Node::SPtr root = SceneLoaderXML::loadFromMemory("test", ascene.c_str()); - EXPECT_TRUE(root!=nullptr) ; - - MakeDataAliasComponent* component = nullptr; - root->getTreeObject(component) ; - - EXPECT_TRUE(component!=nullptr) ; - EXPECT_EQ(component->getComponentState(), ComponentState::Valid) ; - - sofa::simulation::node::unload(root); -} - -} diff --git a/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/material/StableNeoHookean.h b/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/material/StableNeoHookean.h index ae23678051d..0729ef28e0d 100644 --- a/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/material/StableNeoHookean.h +++ b/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/material/StableNeoHookean.h @@ -1,4 +1,4 @@ -/****************************************************************************** +/****************************************************************************** * SOFA, Simulation Open-Framework Architecture * * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * * * @@ -125,7 +125,7 @@ class StableNeoHookean : public HyperelasticMaterial MatrixSym Firstmatrix; MatrixSym::Mat2Sym(inverse_C * (inputTensor * inverse_C), Firstmatrix); - outputTensor = 0.5 * (lambda + mu) * (Firstmatrix * (-2 * J * (J - alpha)) + outputTensor = 0.5_sreal * (lambda + mu) * (Firstmatrix * (-2 * J * (J - alpha)) + inverse_C * (J * (2 * J - alpha) * trHC)); } diff --git a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl index f2942f5ece6..aa2b2dc6fd6 100644 --- a/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl +++ b/Sofa/Component/StateContainer/src/sofa/component/statecontainer/MechanicalObject.inl @@ -1784,6 +1784,228 @@ DataTypes>::getReadAccessor(core::ConstVecId v) *this->read(core::TVecId(v))); } +#define APPLY_PREDICATE_ONEPARAMS(PRED, v)\ + bool canApplyPredicate = false;\ + if (v.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, f);\ + }\ + else if (v.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, f);\ + } + +#define APPLY_PREDICATE_TWOPARAMS(PRED, v, b)\ + bool canApplyPredicate = false;\ + if (v.type == core::V_COORD)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, b, f);\ + }\ + }\ + else if (v.type == core::V_DERIV)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, b, f);\ + }\ + } + +#define APPLY_PREDICATE_THREEPARAMS(PRED, v, a, b)\ + bool canApplyPredicate = false;\ + if (v.type == core::V_COORD)\ + {\ + if (a.type == core::V_COORD)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + }\ + else if (a.type == core::V_DERIV)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + }\ + }\ + else if (v.type == core::V_DERIV)\ + {\ + if (a.type == core::V_COORD)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + }\ + else if (a.type == core::V_DERIV)\ + {\ + if (b.type == core::V_COORD)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + else if (b.type == core::V_DERIV)\ + {\ + canApplyPredicate = PRED(*this, v, a, b, f);\ + }\ + }\ + } + +template +bool vOp_vf(MechanicalObject& self, core::VecId v, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, Real_t fc){vc[0] *= fc;}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] *= f; + } + return true; + } + return false; +} + +template +bool vOp_vbf(MechanicalObject& self, core::VecId v, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t bc, Real_t fc){vc[0] = bc[0] * fc;}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] = vb[i] * f; + } + return true; + } + return false; +} + +template +bool vOp_va(MechanicalObject& self, core::VecId v, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t bc){vc[0] = bc[0];}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.wref() = vb.ref(); + return true; + } + return false; +} + +template +bool vOp_vb(MechanicalObject& self, core::VecId v, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t bc){vc[0] += bc[0];}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] += vb[i]; + } + return true; + } + return false; +} + +template +bool vOp_avf(MechanicalObject& self, core::VecId v, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t bc){vc[0] *= f; vc[0] += bc[0];}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] *= f; + vv[i] += vb[i]; + } + return true; + } + return false; +} + +template +bool vOp_v_inc_bf(MechanicalObject& self, core::VecId v, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t bc, Real_t fc){vc[0] += bc[0] * fc;}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] += vb[i] * f; + } + return true; + } + return false; +} + +template +bool vOp_vab(MechanicalObject& self, core::VecId v, core::ConstVecId a, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t ac, core::StateVecType_t bc){vc[0] = ac[0] + bc[0];}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto va = helper::getReadAccessor(*self.read(core::TVecId(a))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] = va[i] + vb[i]; + } + return true; + } + return false; +} + +template +bool vOp_vabf(MechanicalObject& self, core::VecId v, core::ConstVecId a, core::ConstVecId b, Real_t f) +{ + if constexpr (requires(core::StateVecType_t vc, core::StateVecType_t ac, core::StateVecType_t bc, Real_t fc){vc[0] = ac[0] + bc[0] * fc;}) + { + auto vv = helper::getWriteOnlyAccessor(*self.write(core::TVecId(v))); + auto va = helper::getReadAccessor(*self.read(core::TVecId(a))); + auto vb = helper::getReadAccessor(*self.read(core::TVecId(b))); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] = va[i] + vb[i] * f; + } + return true; + } + return false; +} + template void MechanicalObject::vOp(const core::ExecParams* params, core::VecId v, core::ConstVecId a, @@ -1812,54 +2034,27 @@ void MechanicalObject::vOp(const core::ExecParams* params, core::VecI } else { - if (b.type != v.type) - { - // ERROR - msg_error() << "Invalid vOp operation 2 ("<getWriteAccessor(v); - for (unsigned int i = 0; i < vv.size(); ++i) - vv[i] *= static_cast(f); - }); + APPLY_PREDICATE_ONEPARAMS(vOp_vf, v) + msg_error_when(!canApplyPredicate) << "Cannot apply vector operation v *= f (" << v << ',' << a << ',' << b << ',' << f << ")"; } else { // v = b*f - applyPredicateIfCoordOrDeriv(v.type, [this, &v, &b, f](auto vtype_v) - { - auto vv = this->getWriteAccessor(v); - auto vb = this->getReadAccessor(b); - vv.resize(vb.size()); - for (unsigned int i = 0; i < vv.size(); ++i) - vv[i] = vb[i] * static_cast(f); - }); + APPLY_PREDICATE_TWOPARAMS(vOp_vbf, v, b) + msg_error_when(!canApplyPredicate) << "Cannot apply vector operation v = b*f (" << v << ',' << a << ',' << b << ',' << f << ")"; } } } else { - if (a.type != v.type) - { - // ERROR - msg_error() << "Invalid vOp operation 3 ("<getWriteOnlyAccessor(v); - auto va = this->getReadAccessor(a); - vv.wref() = va.ref(); - }); + APPLY_PREDICATE_TWOPARAMS(vOp_va, v, a) + msg_error_when(!canApplyPredicate) << "Cannot apply vector operation v = a (" << v << ',' << a << ',' << b << ',' << f << ")"; } else { @@ -1868,36 +2063,14 @@ void MechanicalObject::vOp(const core::ExecParams* params, core::VecI if (f == 1._sreal) { // v += b - const bool isApplied = applyPredicateIfCoordOrDeriv(v.type, b.type, - [this, &v, &b](auto vtype_v, auto vtype_b) - { - auto vv = this->getWriteAccessor(v); - auto vb = this->getReadAccessor(b); - - if (vb.size() > vv.size()) - vv.resize(vb.size()); - - for (unsigned int i = 0; i < vb.size(); ++i) - vv[i] += vb[i]; - }); - msg_error_when(!isApplied) << "Invalid vOp operation 4 ("<getWriteAccessor(v); - auto vb = this->getReadAccessor(b); - - if (vb.size() > vv.size()) - vv.resize(vb.size()); - - for (unsigned int i = 0; i < vb.size(); ++i) - vv[i] += vb[i] * static_cast(f); - }); - msg_error_when(!isApplied) << "Invalid vOp operation 5 ("<::vOp(const core::ExecParams* params, core::VecI if (f == 1._sreal) { // v += a - const bool isApplied = applyPredicateIfCoordOrDeriv(v.type, a.type, - [this, &v, &a](auto vtype_v, auto vtype_a) - { - auto vv = this->getWriteAccessor(v); - auto va = this->getReadAccessor(a); - - if (va.size() > vv.size()) - vv.resize(va.size()); - - for (unsigned int i = 0; i < va.size(); ++i) - vv[i] += va[i]; - }); - msg_error_when(!isApplied) << "Invalid vOp operation 6 ("<getWriteOnlyAccessor(v); - auto va = this->getReadAccessor(a); - - vv.resize(va.size()); - for (unsigned int i = 0; i < vv.size(); ++i) - { - vv[i] *= static_cast(f); - vv[i] += va[i]; - } - }); + APPLY_PREDICATE_TWOPARAMS(vOp_avf, v, a) + msg_error_when(!canApplyPredicate) << "Cannot apply vector operation v = a+v*f (" << v << ',' << a << ',' << b << ',' << f << ")"; } } else @@ -1941,42 +2093,42 @@ void MechanicalObject::vOp(const core::ExecParams* params, core::VecI if (f == 1._sreal) { // v = a+b - const bool isApplied = applyPredicateIfCoordOrDeriv(v.type, b.type, - [this, &v, &a, &b](auto vtype_v, auto vtype_b) - { - auto vv = this->getWriteOnlyAccessor(v); - auto va = this->getReadAccessor(a); - auto vb = this->getReadAccessor(b); - - vv.resize(va.size()); - - for (unsigned int i = 0; i < vb.size(); ++i) - { - vv[i] = va[i]; - vv[i] += vb[i]; - } - }); - msg_error_when(!isApplied) << "Invalid vOp operation 7 ("<getWriteOnlyAccessor(v); - auto va = this->getReadAccessor(a); - auto vb = this->getReadAccessor(b); - - vv.resize(va.size()); - - for (unsigned int i = 0; i < vb.size(); ++i) + // v = a+b*f + APPLY_PREDICATE_THREEPARAMS(vOp_vabf, v, a, b) + msg_error_when(!canApplyPredicate) << "Cannot apply vector operation v = a+b*f (" << v << ',' << a << ',' << b << ',' << f << ")"; + }; + + if constexpr (requires (Coord ca, Coord cb) {DataTypes::coordDifference(ca, cb);}) + { + if (f == -1._sreal && + (v.type == core::V_DERIV && a.type == core::V_COORD && b.type == core::V_COORD)) { - vv[i] = va[i]; - vv[i] += vb[i] * static_cast(f); + // v = a-b + auto vv = this->getWriteOnlyAccessor(v); + auto va = this->getReadAccessor(a); + auto vb = this->getReadAccessor(b); + vv.resize(vb.size()); + for (unsigned int i = 0; i < vv.size(); ++i) + { + vv[i] = DataTypes::coordDifference(va[i], vb[i]); + } } - }); - msg_error_when(!isApplied) << "Invalid vOp operation 8 ("<. * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include + +namespace sofa +{ + +template +struct MechanicalObjectVOpTest : public testing::BaseTest +{ + using MO = component::statecontainer::MechanicalObject; + + static constexpr bool isRigid = type::isRigidType; + + static constexpr Real_t positionCoefficient = 19; + static constexpr Real_t restPositionCoefficient = 20; + static constexpr Real_t freePositionCoefficient = 5; + static constexpr Real_t velocityCoefficient = 12; + static constexpr Real_t forceCoefficient = 63; + static constexpr Real_t freeVelocityCoefficient = 78; + + void onSetUp() override + { + m_mechanicalObject = core::objectmodel::New(); + + m_mechanicalObject->x0.forceSet(); + m_mechanicalObject->f.forceSet(); + m_mechanicalObject->xfree.forceSet(); + m_mechanicalObject->vfree.forceSet(); + + m_mechanicalObject->resize(10); + + setVecValues(positionCoefficient); + checkVecValues(positionCoefficient); + + setVecValues(restPositionCoefficient); + checkVecValues(restPositionCoefficient); + + setVecValues(freePositionCoefficient); + checkVecValues(freePositionCoefficient); + + setVecValues(velocityCoefficient); + checkVecValues(velocityCoefficient); + + setVecValues(forceCoefficient); + checkVecValues(forceCoefficient); + + setVecValues(freeVelocityCoefficient); + checkVecValues(freeVelocityCoefficient); + } + + template + void setVecValues(Real_t coefficient = 1) const + { + unsigned int index {}; + auto vec = sofa::helper::getWriteOnlyAccessor(*m_mechanicalObject->write(vtype)); + ASSERT_EQ(vec.size(), 10); + for (auto& v : vec) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + v[i] = static_cast>(index) * coefficient; + } + ++index; + } + } + + template + void checkVecValues(Real_t coefficient = 1) const + { + unsigned int index {}; + auto vec = sofa::helper::getReadAccessor(*m_mechanicalObject->read(vtype)); + ASSERT_EQ(vec.size(), 10); + for (auto& v : vec) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + EXPECT_FLOATINGPOINT_EQ(v[i], static_cast>(index) * coefficient); + } + ++index; + } + } + + template + void checkVecSpatialValues(Real_t coefficient = 1) const + { + unsigned int index {}; + auto vec = sofa::helper::getReadAccessor(*m_mechanicalObject->read(vtype)); + ASSERT_EQ(vec.size(), 10); + for (auto& v : vec) + { + for (std::size_t i = 0; i < DataTypes::spatial_dimensions; ++i) + { + EXPECT_FLOATINGPOINT_EQ(v[i], static_cast>(index) * coefficient); + } + ++index; + } + } + + bool v_null() const + { + //check that an error is emitted + { + EXPECT_MSG_EMIT(Error); + m_mechanicalObject->vOp(nullptr, core::VecId::null()); + } + + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient); + + return true; + } + + void resetPosition() const + { + //check that an error is not emitted + { + EXPECT_MSG_NOEMIT(Error); + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position); + } + + //position is reset + for (auto& position : m_mechanicalObject->readPositions()) + { + static Coord_t defaulConstructedCoord; + for (std::size_t i = 0; i < position.size(); ++i) + { + EXPECT_FLOATINGPOINT_EQ(position[i], defaulConstructedCoord[i]); + } + } + + checkVecValues(velocityCoefficient); + } + + void resetVelocity() const + { + //check that an error is not emitted + { + EXPECT_MSG_NOEMIT(Error); + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity); + } + + //velocity is reset + for (auto& velocity : m_mechanicalObject->readVelocities()) + { + static Deriv_t defaulConstructedDeriv; + for (std::size_t i = 0; i < velocity.size(); ++i) + { + EXPECT_FLOATINGPOINT_EQ(velocity[i], defaulConstructedDeriv[i]); + } + } + + checkVecValues(positionCoefficient); + } + + void multiplyByScalarPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v *= f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::ConstVecId::null(), core::vec_id::read_access::position, 2._sreal); + } + checkVecSpatialValues(positionCoefficient * 2_sreal); + checkVecValues(velocityCoefficient); + } + + void multiplyByScalarVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v *= f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::ConstVecId::null(), core::vec_id::read_access::velocity, 2._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient * 2_sreal); + } + + void equalOtherMultiplyByScalarPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::ConstVecId::null(), core::vec_id::read_access::restPosition, 2._sreal); + } + checkVecSpatialValues(restPositionCoefficient * 2); + checkVecValues(velocityCoefficient); + } + + void equalOtherMultiplyByScalarVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::ConstVecId::null(), core::vec_id::read_access::force, 2._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(forceCoefficient * 2); + } + + void equalOtherMultiplyByScalarPositionMix() const + { + //v = b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::ConstVecId::null(), core::vec_id::read_access::velocity, 2._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(isRigid ? positionCoefficient : velocityCoefficient * 2_sreal); + checkVecValues(velocityCoefficient); + } + + void equalOtherMultiplyByScalarVelocityMix() const + { + //v = b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::ConstVecId::null(), core::vec_id::read_access::position, 2._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : positionCoefficient * 2_sreal); + } + + void equalOtherPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::ConstVecId::null(), 1._sreal); + } + checkVecValues(restPositionCoefficient); + checkVecValues(velocityCoefficient); + } + + void equalOtherPositionMix() const + { + //v = a + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::velocity, core::ConstVecId::null(), 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(isRigid ? positionCoefficient : velocityCoefficient); + checkVecValues(velocityCoefficient); + } + + void equalOtherVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::ConstVecId::null(), 1._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(forceCoefficient); + } + + void equalOtherVelocityMix() const + { + //v = a + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::restPosition, core::ConstVecId::null(), 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : restPositionCoefficient); + } + + void plusEqualOtherPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::position, core::vec_id::read_access::restPosition, 1._sreal); + } + checkVecSpatialValues(positionCoefficient + restPositionCoefficient); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherPositionMix() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::position, core::vec_id::read_access::freeVelocity, 1._sreal); + } + checkVecSpatialValues(positionCoefficient + freeVelocityCoefficient); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::velocity, core::vec_id::read_access::force, 1._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient + forceCoefficient); + } + + void plusEqualOtherVelocityMix() const + { + //v += b + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::velocity, core::vec_id::read_access::position, 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : velocityCoefficient + positionCoefficient); + } + + void plusEqualOtherMultipliedByScalarPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::position, core::vec_id::read_access::restPosition, 2._sreal); + } + checkVecSpatialValues(positionCoefficient + restPositionCoefficient * 2); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherMultipliedByScalarPositionMix() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::position, core::vec_id::read_access::freeVelocity, 2._sreal); + } + checkVecSpatialValues(positionCoefficient + freeVelocityCoefficient * 2); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherMultipliedByScalarVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::velocity, core::vec_id::read_access::force, 2._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient + forceCoefficient * 2); + } + + void plusEqualOtherMultipliedByScalarVelocityMix() const + { + //v += b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::velocity, core::vec_id::read_access::freePosition, 2._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : velocityCoefficient + freePositionCoefficient * 2); + } + + void plusEqualOtherPosition_2() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += a + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::position, 1._sreal); + } + checkVecSpatialValues(positionCoefficient + restPositionCoefficient); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherPositionMix_2() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += a + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::freeVelocity, core::vec_id::read_access::position, 1._sreal); + } + checkVecSpatialValues(positionCoefficient + freeVelocityCoefficient); + checkVecValues(velocityCoefficient); + } + + void plusEqualOtherVelocity_2() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v += a + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::velocity, 1._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient + forceCoefficient); + } + + void plusEqualOtherVelocityMix_2() const + { + //v += a + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::freePosition, core::vec_id::read_access::velocity, 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : velocityCoefficient + freePositionCoefficient); + } + + void multipliedByScalarThenAddOtherPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+v*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::position, 3_sreal); + } + checkVecSpatialValues(restPositionCoefficient + positionCoefficient * 3); + checkVecValues(velocityCoefficient); + } + + void multipliedByScalarThenAddOtherPositionMix() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+v*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::freeVelocity, core::vec_id::read_access::position, 3_sreal); + } + checkVecSpatialValues(freeVelocityCoefficient + positionCoefficient * 3); + checkVecValues(velocityCoefficient); + } + + void multipliedByScalarThenAddOtherVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+v*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::velocity, 7._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(velocityCoefficient * 7 + forceCoefficient); + } + + void multipliedByScalarThenAddOtherVelocityMix() const + { + //v = a+v*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::freePosition, core::vec_id::read_access::velocity, 7._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : freePositionCoefficient + velocityCoefficient * 7); + } + + void equalSumPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::freePosition, 1_sreal); + } + checkVecSpatialValues(restPositionCoefficient + freePositionCoefficient); + checkVecValues(velocityCoefficient); + } + + void equalSumPositionMix1() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::freeVelocity, 1_sreal); + } + checkVecSpatialValues(restPositionCoefficient+freeVelocityCoefficient); + checkVecValues(velocityCoefficient); + } + + void equalSumPositionMix2() const + { + //v = a+b + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::freeVelocity, core::vec_id::read_access::freePosition, 1_sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(isRigid ? positionCoefficient : freeVelocityCoefficient + freePositionCoefficient); + checkVecValues(velocityCoefficient); + } + + void equalSumVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::freeVelocity, 1._sreal); + } + checkVecValues(positionCoefficient); + checkVecValues(forceCoefficient + freeVelocityCoefficient); + } + + void equalSumVelocityMix1() const + { + //v = a+b + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::position, core::vec_id::read_access::freeVelocity, 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : positionCoefficient + freeVelocityCoefficient); + } + + void equalSumVelocityMix2() const + { + //v = a+b + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::position, 1._sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : forceCoefficient + positionCoefficient); + } + + void equalSumWithScalarPosition() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::freePosition, 12_sreal); + } + checkVecSpatialValues(restPositionCoefficient + freePositionCoefficient * 12); + checkVecValues(velocityCoefficient); + } + + void equalSumWithScalarPositionMix1() const + { + //v = a+b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::velocity, core::vec_id::read_access::freePosition, 12_sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(isRigid ? positionCoefficient : velocityCoefficient + freePositionCoefficient * 12); + checkVecValues(velocityCoefficient); + } + + void equalSumWithScalarPositionMix2() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::position, core::vec_id::read_access::restPosition, core::vec_id::read_access::freeVelocity, 12_sreal); + } + checkVecSpatialValues(restPositionCoefficient + freeVelocityCoefficient * 12); + checkVecValues(velocityCoefficient); + } + + void equalSumWithScalarVelocity() const + { + { + EXPECT_MSG_NOEMIT(Error); + //v = a+b*f + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::freeVelocity, 12_sreal); + } + checkVecSpatialValues(positionCoefficient); + checkVecValues(forceCoefficient + freeVelocityCoefficient * 12); + } + + void equalSumWithScalarVelocityMix1() const + { + //v = a+b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::position, core::vec_id::read_access::freeVelocity, 12_sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : positionCoefficient + freeVelocityCoefficient * 12); + } + + void equalSumWithScalarVelocityMix2() const + { + //v = a+b*f + const auto vop = [this]() + { + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::force, core::vec_id::read_access::position, 12_sreal); + }; + if constexpr (isRigid) + { + EXPECT_MSG_EMIT(Error); + vop(); + } + else + { + EXPECT_MSG_NOEMIT(Error); + vop(); + } + checkVecSpatialValues(positionCoefficient); + checkVecValues(isRigid ? velocityCoefficient : forceCoefficient + positionCoefficient * 12); + } + + void equalCoordDifference() const + { + // v = a-b + m_mechanicalObject->vOp(nullptr, core::vec_id::write_access::velocity, core::vec_id::read_access::restPosition, core::vec_id::read_access::position, -1_sreal); + + unsigned int index {}; + auto vv = sofa::helper::getReadAccessor(*m_mechanicalObject->read(core::vec_id::read_access::velocity)); + auto va = sofa::helper::getReadAccessor(*m_mechanicalObject->read(core::vec_id::read_access::restPosition)); + auto vb = sofa::helper::getReadAccessor(*m_mechanicalObject->read(core::vec_id::read_access::position)); + + ASSERT_EQ(vv.size(), 10); + for (std::size_t i = 0; i < vv.size(); ++i) + { + const auto& v = vv[i]; + const auto diff = DataTypes::coordDifference(va[i], vb[i]); + for (std::size_t j = 0; j < v.size(); ++j) + { + EXPECT_FLOATINGPOINT_EQ(v[j], diff[j]) + } + ++index; + } + + checkVecValues(positionCoefficient); + } + + typename MO::SPtr m_mechanicalObject; +}; + +typedef ::testing::Types< + defaulttype::Vec1Types, + defaulttype::Vec2Types, + defaulttype::Vec3Types, + defaulttype::Rigid2Types, + defaulttype::Rigid3Types +> DataTypesList; + +TYPED_TEST_SUITE(MechanicalObjectVOpTest, DataTypesList); + +TYPED_TEST(MechanicalObjectVOpTest, v_null) +{ + EXPECT_TRUE(this->v_null()); +} + +TYPED_TEST(MechanicalObjectVOpTest, resetPosition) +{ + this->resetPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, resetVelocity) +{ + this->resetVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multiplyByScalarPosition) +{ + this->multiplyByScalarPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multiplyByScalarVelocity) +{ + this->multiplyByScalarVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherMultiplyByScalarPosition) +{ + this->equalOtherMultiplyByScalarPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherMultiplyByScalarVelocity) +{ + this->equalOtherMultiplyByScalarVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherMultiplyByScalarPositionMix) +{ + this->equalOtherMultiplyByScalarPositionMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherMultiplyByScalarVelocityMix) +{ + this->equalOtherMultiplyByScalarVelocityMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherPosition) +{ + this->equalOtherPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherPositionMix) +{ + this->equalOtherPositionMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherVelocity) +{ + this->equalOtherVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalOtherVelocityMix) +{ + this->equalOtherVelocityMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherPosition) +{ + this->plusEqualOtherPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherPositionMix) +{ + this->plusEqualOtherPositionMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherVelocity) +{ + this->plusEqualOtherVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherVelocityMix) +{ + this->plusEqualOtherVelocityMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherMultipliedByScalarPosition) +{ + this->plusEqualOtherMultipliedByScalarPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherMultipliedByScalarPositionMix) +{ + this->plusEqualOtherMultipliedByScalarPositionMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherMultipliedByScalarVelocity) +{ + this->plusEqualOtherMultipliedByScalarVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherMultipliedByScalarVelocityMix) +{ + this->plusEqualOtherMultipliedByScalarVelocityMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherPosition_2) +{ + this->plusEqualOtherPosition_2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherPositionMix_2) +{ + this->plusEqualOtherPositionMix_2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherVelocity_2) +{ + this->plusEqualOtherVelocity_2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, plusEqualOtherVelocityMix_2) +{ + this->plusEqualOtherVelocityMix_2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multipliedByScalarThenAddOtherPosition) +{ + this->multipliedByScalarThenAddOtherPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multipliedByScalarThenAddOtherPositionMix) +{ + this->multipliedByScalarThenAddOtherPositionMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multipliedByScalarThenAddOtherVelocity) +{ + this->multipliedByScalarThenAddOtherVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, multipliedByScalarThenAddOtherVelocityMix) +{ + this->multipliedByScalarThenAddOtherVelocityMix(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumPosition) +{ + this->equalSumPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumPositionMix1) +{ + this->equalSumPositionMix1(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumPositionMix2) +{ + this->equalSumPositionMix2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumVelocity) +{ + this->equalSumVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumVelocityMix1) +{ + this->equalSumVelocityMix1(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumVelocityMix2) +{ + this->equalSumVelocityMix2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarPosition) +{ + this->equalSumWithScalarPosition(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarPositionMix1) +{ + this->equalSumWithScalarPositionMix1(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarPositionMix2) +{ + this->equalSumWithScalarPositionMix2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarVelocity) +{ + this->equalSumWithScalarVelocity(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarVelocityMix1) +{ + this->equalSumWithScalarVelocityMix1(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalSumWithScalarVelocityMix2) +{ + this->equalSumWithScalarVelocityMix2(); +} + +TYPED_TEST(MechanicalObjectVOpTest, equalCoordDifference) +{ + this->equalCoordDifference(); +} + +} \ No newline at end of file diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.h b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.h index b4f0541a94c..1935b481cb0 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.h +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.h @@ -231,8 +231,6 @@ class TriangleSetGeometryAlgorithms : public EdgeSetGeometryAlgorithms& a, const sofa::type::Vec<3, Real>& b, @@ -240,6 +238,20 @@ class TriangleSetGeometryAlgorithms : public EdgeSetGeometryAlgorithms& indices, Real& baryCoef, Real& coord_kmin) const; + /** \brief Computes the intersection between the edges of the Triangle triId and the vector [AB] projected into this Triangle frame. + * @param ptA : first input point + * @param ptB : last input point + * @param triId : index of the triangle whose edges will be checked + * @param intersectedEdges : output list of Edge global Ids that are intersected by vector AB (size could be 0, 1 or 2) + * @param baryCoefs : output list of barycoef corresponding to the relative position of the intersection on the edge (same size and order as @sa intersectedEdges) + */ + bool computeSegmentTriangleIntersectionInPlane( + const sofa::type::Vec<3, Real>& ptA, + const sofa::type::Vec<3, Real>& ptB, + const TriangleID triId, + sofa::type::vector& intersectedEdges, + sofa::type::vector& baryCoefs) const; + /** \brief Computes the intersections of the vector from point a to point b and the triangle indexed by t * * @param a : first input point diff --git a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.inl b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.inl index c5908a82906..0adba4d8c6f 100644 --- a/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.inl +++ b/Sofa/Component/Topology/Container/Dynamic/src/sofa/component/topology/container/dynamic/TriangleSetGeometryAlgorithms.inl @@ -1299,6 +1299,62 @@ void TriangleSetGeometryAlgorithms< DataTypes >::prepareVertexDuplication(const } } + +template +bool TriangleSetGeometryAlgorithms< DataTypes >::computeSegmentTriangleIntersectionInPlane( + const sofa::type::Vec<3, Real>& ptA, + const sofa::type::Vec<3, Real>& ptB, + const TriangleID triId, + sofa::type::vector& intersectedEdges, + sofa::type::vector& baryCoefs) const +{ + // Get coordinates of each vertex of the triangle + const typename DataTypes::VecCoord& coords = (this->object->read(core::ConstVecCoordId::position())->getValue()); + const Triangle& tri = this->m_topology->getTriangle(triId); + + const typename DataTypes::Coord& c0 = coords[tri[0]]; + const typename DataTypes::Coord& c1 = coords[tri[1]]; + const typename DataTypes::Coord& c2 = coords[tri[2]]; + type::fixed_array triP = { Vec3(c0[0], c0[1], c0[2]), Vec3(c1[0], c1[1], c1[2]), Vec3(c2[0], c2[1], c2[2]) }; + + // Project A and B into triangle plan + Vec3 v_normal = (triP[2] - triP[0]).cross(triP[1] - triP[0]); + v_normal.normalize(); + const Vec3 pa_proj = ptA - v_normal * dot(ptA - triP[0], v_normal); + const Vec3 pb_proj = ptB - v_normal * dot(ptB - triP[0], v_normal); + + // check intersection between AB and each edge of the triangle + const sofa::type::fixed_array& edgesInTri = this->m_topology->getEdgesInTriangle(triId); + for (const EdgeID& edgeId : edgesInTri) + { + const Edge& edge = this->m_topology->getEdge(edgeId); + Edge localIds; + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 3; j++) + { + if (edge[i] == tri[j]) + { + localIds[i] = j; + break; + } + } + } + + type::Vec2 baryCoords(type::NOINIT); + bool res = geometry::Edge::intersectionWithEdge(triP[localIds[0]], triP[localIds[1]], pa_proj, pb_proj, baryCoords); + + if (res) + { + intersectedEdges.push_back(edgeId); + baryCoefs.push_back(baryCoords[0]); + } + } + + return !intersectedEdges.empty(); +} + + // Computes the intersection of the segment from point a to point b and the triangle indexed by t template bool TriangleSetGeometryAlgorithms< DataTypes >::computeSegmentTriangleIntersection(bool is_entered, diff --git a/Sofa/Component/Topology/Container/Dynamic/tests/TriangleSetTopology_test.cpp b/Sofa/Component/Topology/Container/Dynamic/tests/TriangleSetTopology_test.cpp index 559485ef6a2..a478733e6bf 100644 --- a/Sofa/Component/Topology/Container/Dynamic/tests/TriangleSetTopology_test.cpp +++ b/Sofa/Component/Topology/Container/Dynamic/tests/TriangleSetTopology_test.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include using namespace sofa::component::topology::container::dynamic; @@ -32,12 +34,46 @@ using namespace sofa::testing; class TriangleSetTopology_test : public BaseTest { public: + /// Test on TriangleSetTopologyContainer creation without Data. All container should be empty. bool testEmptyContainer(); + + /// Test on TriangleSetTopologyContainer creation with a triangular mesh as input. Check Triangle container size and content against know values. bool testTriangleBuffers(); + + /// Test on TriangleSetTopologyContainer creation with a triangular mesh as input. Check Edge container size and content against know values. bool testEdgeBuffers(); + + /// Test on TriangleSetTopologyContainer creation with a triangular mesh as input. Check Vertex container size and content against know values. bool testVertexBuffers(); + + /// Test on TriangleSetTopologyContainer creation with a triangular mesh as input. Call member method CheckTopology which check all buffers concistency. bool checkTopology(); + + /// Test on @sa TriangleSetTopologyModifier::removeVertices method and check triangle buffers. + bool testRemovingVertices(); + + /// Test on @sa TriangleSetTopologyModifier::removeTriangles method with isolated vertices and check triangle buffers. + bool testRemovingTriangles(); + + /// Test on @sa TriangleSetTopologyModifier::addTriangles method and check triangle buffers. + bool testAddingTriangles(); + + + /// Test on @sa TriangleSetGeometryAlgorithms::computeSegmentTriangleIntersectionInPlane method. + bool testTriangleSegmentIntersectionInPlane(const sofa::type::Vec3& bufferZ); + +private: + /// Method to factorize the creation and loading of the @sa m_scene and retrieve Topology container @sa m_topoCon + bool loadTopologyContainer(const std::string& filename); + + /// Pointer to the basic scene created with a topology for the tests + std::unique_ptr m_scene; + + /// Pointer to the topology container created in the scene @sa m_scene + TriangleSetTopologyContainer::SPtr m_topoCon = nullptr; + + // Ground truth values for mesh 'square1.obj' int nbrTriangle = 26; int nbrEdge = 45; int nbrVertex = 20; @@ -45,6 +81,28 @@ class TriangleSetTopology_test : public BaseTest }; +bool TriangleSetTopology_test::loadTopologyContainer(const std::string& filename) +{ + m_scene = std::make_unique(filename, sofa::geometry::ElementType::TRIANGLE); + + if (m_scene == nullptr) { + msg_error("TriangleSetTopology_test") << "Fake Topology creation from file: " << filename << " failed."; + return false; + } + + const auto root = m_scene->getNode().get(); + m_topoCon = root->get(sofa::core::objectmodel::BaseContext::SearchDown); + + if (m_topoCon == nullptr) + { + msg_error("TriangleSetTopology_test") << "TriangleSetTopologyContainer not found in scene."; + return false; + } + + return true; +} + + bool TriangleSetTopology_test::testEmptyContainer() { const TriangleSetTopologyContainer::SPtr triangleContainer = sofa::core::objectmodel::New< TriangleSetTopologyContainer >(); @@ -66,29 +124,22 @@ bool TriangleSetTopology_test::testEmptyContainer() bool TriangleSetTopology_test::testTriangleBuffers() { - fake_TopologyScene* scene = new fake_TopologyScene("mesh/square1.obj", sofa::geometry::ElementType::TRIANGLE); - TriangleSetTopologyContainer* topoCon = dynamic_cast(scene->getNode().get()->getMeshTopology()); - - if (topoCon == nullptr) - { - if (scene != nullptr) - delete scene; + if (!loadTopologyContainer("mesh/square1.obj")) return false; - } // Check creation of the container - EXPECT_EQ((topoCon->getName()), std::string("topoCon")); + EXPECT_EQ((m_topoCon->getName()), std::string("topoCon")); // Check triangle container buffers size - EXPECT_EQ(topoCon->getNbTriangles(), nbrTriangle); - EXPECT_EQ(topoCon->getNumberOfElements(), nbrTriangle); - EXPECT_EQ(topoCon->getNumberOfTriangles(), nbrTriangle); - EXPECT_EQ(topoCon->getTriangles().size(), nbrTriangle); + EXPECT_EQ(m_topoCon->getNbTriangles(), nbrTriangle); + EXPECT_EQ(m_topoCon->getNumberOfElements(), nbrTriangle); + EXPECT_EQ(m_topoCon->getNumberOfTriangles(), nbrTriangle); + EXPECT_EQ(m_topoCon->getTriangles().size(), nbrTriangle); // check edges buffer has been created - EXPECT_EQ(topoCon->getNumberOfEdges(), nbrEdge); - EXPECT_EQ(topoCon->getNbEdges(), nbrEdge); - EXPECT_EQ(topoCon->getEdges().size(), nbrEdge); + EXPECT_EQ(m_topoCon->getNumberOfEdges(), nbrEdge); + EXPECT_EQ(m_topoCon->getNbEdges(), nbrEdge); + EXPECT_EQ(m_topoCon->getEdges().size(), nbrEdge); // The first 2 triangles in this file should be : sofa::type::fixed_array triTruth0(0, 18, 11); @@ -96,7 +147,7 @@ bool TriangleSetTopology_test::testTriangleBuffers() // check triangle buffer - const sofa::type::vector& triangles = topoCon->getTriangleArray(); + const sofa::type::vector& triangles = m_topoCon->getTriangleArray(); if (triangles.empty()) return false; @@ -108,53 +159,42 @@ bool TriangleSetTopology_test::testTriangleBuffers() EXPECT_EQ(tri0[i], triTruth0[i]); // check triangle indices - int vertexID = topoCon->getVertexIndexInTriangle(tri0, triTruth0[1]); + int vertexID = m_topoCon->getVertexIndexInTriangle(tri0, triTruth0[1]); EXPECT_EQ(vertexID, 1); - vertexID = topoCon->getVertexIndexInTriangle(tri0, triTruth0[2]); + vertexID = m_topoCon->getVertexIndexInTriangle(tri0, triTruth0[2]); EXPECT_EQ(vertexID, 2); - vertexID = topoCon->getVertexIndexInTriangle(tri0, 120); + vertexID = m_topoCon->getVertexIndexInTriangle(tri0, 120); EXPECT_EQ(vertexID, -1); // Check triangle buffer access - const TriangleSetTopologyContainer::Triangle& tri1 = topoCon->getTriangle(1); + const TriangleSetTopologyContainer::Triangle& tri1 = m_topoCon->getTriangle(1); for (int i = 0; igetTriangle(1000); + const TriangleSetTopologyContainer::Triangle& tri2 = m_topoCon->getTriangle(1000); for (int i = 0; i(scene->getNode().get()->getMeshTopology()); - - if (topoCon == nullptr) - { - if (scene != nullptr) - delete scene; + if (!loadTopologyContainer("mesh/square1.obj")) return false; - } // create and check edges - const sofa::type::vector< TriangleSetTopologyContainer::TrianglesAroundEdge >& triAroundEdges = topoCon->getTrianglesAroundEdgeArray(); + const sofa::type::vector< TriangleSetTopologyContainer::TrianglesAroundEdge >& triAroundEdges = m_topoCon->getTrianglesAroundEdgeArray(); // check only the edge buffer size: Full test on edges are done in EdgeSetTopology_test - EXPECT_EQ(topoCon->getNumberOfEdges(), nbrEdge); - EXPECT_EQ(topoCon->getNbEdges(), nbrEdge); - EXPECT_EQ(topoCon->getEdges().size(), nbrEdge); + EXPECT_EQ(m_topoCon->getNumberOfEdges(), nbrEdge); + EXPECT_EQ(m_topoCon->getNbEdges(), nbrEdge); + EXPECT_EQ(m_topoCon->getEdges().size(), nbrEdge); // check edge created element - TriangleSetTopologyContainer::Edge edge = topoCon->getEdge(0); + TriangleSetTopologyContainer::Edge edge = m_topoCon->getEdge(0); EXPECT_EQ(edge[0], 18); EXPECT_EQ(edge[1], 11); @@ -162,7 +202,7 @@ bool TriangleSetTopology_test::testEdgeBuffers() // check TriangleAroundEdge buffer access EXPECT_EQ(triAroundEdges.size(), nbrEdge); const TriangleSetTopologyContainer::TrianglesAroundEdge& triAEdge = triAroundEdges[0]; - const TriangleSetTopologyContainer::TrianglesAroundEdge& triAEdgeM = topoCon->getTrianglesAroundEdge(0); + const TriangleSetTopologyContainer::TrianglesAroundEdge& triAEdgeM = m_topoCon->getTrianglesAroundEdge(0); EXPECT_EQ(triAEdge.size(), triAEdgeM.size()); for (size_t i = 0; i < triAEdge.size(); i++) @@ -174,11 +214,11 @@ bool TriangleSetTopology_test::testEdgeBuffers() // check EdgesInTriangle buffer access - const sofa::type::vector< TriangleSetTopologyContainer::EdgesInTriangle > & edgeInTriangles = topoCon->getEdgesInTriangleArray(); + const sofa::type::vector< TriangleSetTopologyContainer::EdgesInTriangle > & edgeInTriangles = m_topoCon->getEdgesInTriangleArray(); EXPECT_EQ(edgeInTriangles.size(), nbrTriangle); const TriangleSetTopologyContainer::EdgesInTriangle& edgeInTri = edgeInTriangles[2]; - const TriangleSetTopologyContainer::EdgesInTriangle& edgeInTriM = topoCon->getEdgesInTriangle(2); + const TriangleSetTopologyContainer::EdgesInTriangle& edgeInTriM = m_topoCon->getEdgesInTriangle(2); EXPECT_EQ(edgeInTri.size(), edgeInTriM.size()); for (size_t i = 0; i < edgeInTri.size(); i++) @@ -191,9 +231,9 @@ bool TriangleSetTopology_test::testEdgeBuffers() // Check Edge Index in Triangle for (size_t i = 0; igetEdgeIndexInTriangle(edgeInTri, edgeInTriTruth[i]), i); + EXPECT_EQ(m_topoCon->getEdgeIndexInTriangle(edgeInTri, edgeInTriTruth[i]), i); - int edgeId = topoCon->getEdgeIndexInTriangle(edgeInTri, 20000); + int edgeId = m_topoCon->getEdgeIndexInTriangle(edgeInTri, 20000); EXPECT_EQ(edgeId, -1); // check link between TrianglesAroundEdge and EdgesInTriangle @@ -217,8 +257,6 @@ bool TriangleSetTopology_test::testEdgeBuffers() if (found == false) { - if (scene != nullptr) - delete scene; return false; } } @@ -230,27 +268,20 @@ bool TriangleSetTopology_test::testEdgeBuffers() bool TriangleSetTopology_test::testVertexBuffers() { - fake_TopologyScene* scene = new fake_TopologyScene("mesh/square1.obj", sofa::geometry::ElementType::TRIANGLE); - TriangleSetTopologyContainer* topoCon = dynamic_cast(scene->getNode().get()->getMeshTopology()); - - if (topoCon == nullptr) - { - if (scene != nullptr) - delete scene; + if (!loadTopologyContainer("mesh/square1.obj")) return false; - } // create and check vertex buffer - const sofa::type::vector< TriangleSetTopologyContainer::TrianglesAroundVertex >& triAroundVertices = topoCon->getTrianglesAroundVertexArray(); + const sofa::type::vector< TriangleSetTopologyContainer::TrianglesAroundVertex >& triAroundVertices = m_topoCon->getTrianglesAroundVertexArray(); //// check only the vertex buffer size: Full test on vertics are done in PointSetTopology_test - EXPECT_EQ(topoCon->d_initPoints.getValue().size(), nbrVertex); - EXPECT_EQ(topoCon->getNbPoints(), nbrVertex); + EXPECT_EQ(m_topoCon->d_initPoints.getValue().size(), nbrVertex); + EXPECT_EQ(m_topoCon->getNbPoints(), nbrVertex); // check TrianglesAroundVertex buffer access EXPECT_EQ(triAroundVertices.size(), nbrVertex); const TriangleSetTopologyContainer::TrianglesAroundVertex& triAVertex = triAroundVertices[0]; - const TriangleSetTopologyContainer::TrianglesAroundVertex& triAVertexM = topoCon->getTrianglesAroundVertex(0); + const TriangleSetTopologyContainer::TrianglesAroundVertex& triAVertexM = m_topoCon->getTrianglesAroundVertex(0); EXPECT_EQ(triAVertex.size(), triAVertexM.size()); for (size_t i = 0; i < triAVertex.size(); i++) @@ -261,35 +292,313 @@ bool TriangleSetTopology_test::testVertexBuffers() EXPECT_EQ(triAVertex[1], 1); - const TriangleSetTopologyContainer::Triangle &tri = topoCon->getTriangle(1); - int vId = topoCon->getVertexIndexInTriangle(tri, 0); + const TriangleSetTopologyContainer::Triangle &tri = m_topoCon->getTriangle(1); + int vId = m_topoCon->getVertexIndexInTriangle(tri, 0); EXPECT_NE(vId, sofa::InvalidID); - vId = topoCon->getVertexIndexInTriangle(tri, 20000); + vId = m_topoCon->getVertexIndexInTriangle(tri, 20000); EXPECT_EQ(vId, -1); return true; } - bool TriangleSetTopology_test::checkTopology() { - fake_TopologyScene* scene = new fake_TopologyScene("mesh/square1.obj", sofa::geometry::ElementType::TRIANGLE); - const TriangleSetTopologyContainer* topoCon = dynamic_cast(scene->getNode().get()->getMeshTopology()); + if (!loadTopologyContainer("mesh/square1.obj")) + return false; - if (topoCon == nullptr) - { - if (scene != nullptr) - delete scene; + return m_topoCon->checkTopology(); +} + + + +bool TriangleSetTopology_test::testRemovingVertices() +{ + if (!loadTopologyContainer("mesh/square1.obj")) return false; - } - const bool res = topoCon->checkTopology(); + // Get access to the Triangle modifier + const TriangleSetTopologyModifier::SPtr triangleModifier = m_scene->getNode()->get(sofa::core::objectmodel::BaseContext::SearchDown); + + if (triangleModifier == nullptr) + return false; + + // get nbr triangles around vertex Id 0 + const auto triAV = m_topoCon->getTrianglesAroundVertex(0); + sofa::topology::SetIndex vToremove = { 0 }; - if (scene != nullptr) - delete scene; + // TODO @epernod (2025-01-28): triangles are not removed when a vertex is removed. An msg_error is fired as some buffers are not concistent anymore but the vertex is still removed. + // This might create errors. + EXPECT_MSG_EMIT(Error); + triangleModifier->removePoints(vToremove); + + EXPECT_EQ(m_topoCon->getNbPoints(), nbrVertex - 1); + // EXPECT_EQ(m_topoCon->getNbTriangles(), nbrTriangle - triAV.size()); // see comment above - return res; + + return true; +} + + +bool TriangleSetTopology_test::testRemovingTriangles() +{ + if (!loadTopologyContainer("mesh/square1.obj")) + return false; + + // Get access to the Triangle modifier + const TriangleSetTopologyModifier::SPtr triangleModifier = m_scene->getNode()->get(sofa::core::objectmodel::BaseContext::SearchDown); + + if (triangleModifier == nullptr) + return false; + + // Check triangle buffer before changes + const sofa::type::vector& triangles = m_topoCon->getTriangleArray(); + EXPECT_EQ(m_topoCon->getNbPoints(), nbrVertex); + EXPECT_EQ(m_topoCon->getNbEdges(), nbrEdge); + EXPECT_EQ(triangles.size(), nbrTriangle); + + // 1. Check first the swap + pop_back method + const TriangleSetTopologyContainer::Triangle lastTri = triangles.back(); + sofa::type::vector< TriangleSetTopologyContainer::TriangleID > triIds = { 0 }; + + // Remove first edge from the buffer + triangleModifier->removeTriangles(triIds, true, true); + + // Check size of the new size of the topology containers + int newNbrTri = nbrTriangle - 1; + int newNbrEdge = nbrEdge - 1; // 1st triangle is on border + int newNbrVertex = nbrVertex; + EXPECT_EQ(m_topoCon->getNbTriangles(), newNbrTri); + EXPECT_EQ(m_topoCon->getNbEdges(), newNbrEdge); + EXPECT_EQ(m_topoCon->getNbPoints(), newNbrVertex); + + // Check that first triangle is now the previous last triangle + const TriangleSetTopologyContainer::Triangle& newTri = m_topoCon->getTriangle(0); + EXPECT_EQ(lastTri[0], newTri[0]); + EXPECT_EQ(lastTri[1], newTri[1]); + EXPECT_EQ(lastTri[2], newTri[2]); + + + // 2. Check removal of single Triangle in middle of the mesh, should not remove edge nor vertex + triIds[0] = 18; + triangleModifier->removeTriangles(triIds, true, true); + + // Check size of the new triangle buffer + newNbrTri--; + EXPECT_EQ(m_topoCon->getNbTriangles(), newNbrTri); + EXPECT_EQ(m_topoCon->getNbEdges(), newNbrEdge); + EXPECT_EQ(m_topoCon->getNbPoints(), newNbrVertex); + + + // 3. Check removal of 2 Triangles side by side in middle of the mesh. Should remove commun edge + const auto& triAEdge = m_topoCon->getTrianglesAroundEdge(22); + triangleModifier->removeTriangles(triAEdge, true, true); + + // Check size of the new triangle buffer + newNbrTri = newNbrTri - 2; + newNbrEdge--; + EXPECT_EQ(m_topoCon->getNbTriangles(), newNbrTri); + EXPECT_EQ(m_topoCon->getNbEdges(), newNbrEdge); + EXPECT_EQ(m_topoCon->getNbPoints(), newNbrVertex); + + + // 4. Check removal of 2 Triangles side by side on corner of the mesh. Should remove commun edge, 2 edges on border and isolated vertex + const auto& triAEdge2 = m_topoCon->getTrianglesAroundEdge(11); + triangleModifier->removeTriangles(triAEdge2, true, true); + + // Check size of the new triangle buffer + newNbrTri = newNbrTri - 2; + newNbrEdge = newNbrEdge - 3; + newNbrVertex = newNbrVertex - 1; + EXPECT_EQ(m_topoCon->getNbTriangles(), newNbrTri); + EXPECT_EQ(m_topoCon->getNbEdges(), newNbrEdge); + EXPECT_EQ(m_topoCon->getNbPoints(), newNbrVertex); + + return true; +} + + +bool TriangleSetTopology_test::testAddingTriangles() +{ + if (!loadTopologyContainer("mesh/square1.obj")) + return false; + + // Get access to the Triangle modifier + const TriangleSetTopologyModifier::SPtr triangleModifier = m_scene->getNode()->get(sofa::core::objectmodel::BaseContext::SearchDown); + + if (triangleModifier == nullptr) + return false; + + // construct triangles based on vertices of 2 triangles which do not have vertices in commun + const sofa::type::vector& triangles = m_topoCon->getTriangleArray(); + const TriangleSetTopologyContainer::Triangle tri0 = triangles[0]; + const TriangleSetTopologyContainer::Triangle tri1 = triangles[10]; + + const auto triAV0 = m_topoCon->getTrianglesAroundVertex(tri1[0]); + const auto triAV1 = m_topoCon->getTrianglesAroundVertex(tri1[2]); + + const TriangleSetTopologyContainer::Triangle newTri0 = TriangleSetTopologyContainer::Triangle(tri0[0], tri0[1], tri1[2]); + const TriangleSetTopologyContainer::Triangle newTri1 = TriangleSetTopologyContainer::Triangle(tri1[0], tri0[2], tri1[2]); + + sofa::type::vector< TriangleSetTopologyContainer::Triangle > triangesToAdd = { newTri0 , newTri1 }; + + // Add triangles + // TODO @epernod (2025-01-28): Adding the triangle create a segmentation fault. Need to investigate why + // triangleModifier->addTriangles(triangesToAdd); + return true; // exit for now + + // Check buffers on new triangle just added + EXPECT_EQ(m_topoCon->getNbTriangles(), nbrTriangle + triangesToAdd.size()); + const TriangleSetTopologyContainer::Triangle& checkTri0 = m_topoCon->getTriangle(nbrTriangle); + const TriangleSetTopologyContainer::Triangle& checkTri1 = m_topoCon->getTriangle(nbrTriangle + 1); + + for (int i = 0; i < 3; i++) + { + EXPECT_EQ(newTri0[i], checkTri0[i]); + EXPECT_EQ(newTri1[i], checkTri1[i]); + } + + // Check cross buffer around vertex + const auto& newTriAV0 = m_topoCon->getTrianglesAroundVertex(tri1[0]); + const auto& newTriAV1 = m_topoCon->getTrianglesAroundVertex(tri1[2]); + + EXPECT_EQ(newTriAV0.size(), triAV0.size() + 1); // newTri0 has been added around vertex tri1[0] + EXPECT_EQ(newTriAV1.size(), triAV1.size() + 2); // newTri0 and newTri1 have been added around vertex tri1[2] + + EXPECT_EQ(newTriAV0.back(), nbrTriangle); // last tri in this buffer should be triangle id == nbrTriangle + EXPECT_EQ(newTriAV1.back(), nbrTriangle + 1); // last tri in this buffer should be triangle id == nbrTriangle + 1 + + return true; +} + + + +bool TriangleSetTopology_test::testTriangleSegmentIntersectionInPlane(const sofa::type::Vec3& bufferZ) +{ + if (!loadTopologyContainer("mesh/square1.obj")) + return false; + + // Get access to the Triangle modifier + const TriangleSetGeometryAlgorithms::SPtr triangleGeo = m_scene->getNode()->get >(); + using Real = sofa::defaulttype::Vec3Types::Real; + + if (triangleGeo == nullptr) + return false; + + const TriangleSetTopologyContainer::TriangleID tId = 0; + const TriangleSetTopologyContainer::Triangle tri0 = m_topoCon->getTriangle(tId); + const auto edgeIds = m_topoCon->getEdgesInTriangle(tId); // as a reminder localEdgeId 0 is the opposite edge of triangle vertex[0] + + const auto& p0 = triangleGeo->getPointPosition(tri0[0]); + const auto& p1 = triangleGeo->getPointPosition(tri0[1]); + const auto& p2 = triangleGeo->getPointPosition(tri0[2]); + + // store some coef with correct cast for computations and checks + Real coef1 = Real(0.5); + Real coef2 = Real(1.0 / 3.0); + + // Case 1: Normal case, full intersection of the segment through the triangle + sofa::type::Vec3 ptA = p0 * coef1 + p1 * 2 * coef2; + sofa::type::Vec3 ptB = p0 * coef1 + p2 * coef1; + // add small buffer to be outside the triangle + ptA = ptA + (ptA - ptB) + bufferZ; + ptB = ptB + (ptB - ptA) - bufferZ; + + sofa::type::vector intersectedEdges; + sofa::type::vector baryCoefs; + triangleGeo->computeSegmentTriangleIntersectionInPlane(ptA, ptB, tId, intersectedEdges, baryCoefs); + + // check results + EXPECT_EQ(intersectedEdges.size(), 2); + EXPECT_EQ(baryCoefs.size(), 2); + + EXPECT_EQ(intersectedEdges[0], edgeIds[1]); + EXPECT_EQ(intersectedEdges[1], edgeIds[2]); + + EXPECT_NEAR(baryCoefs[0], coef1, 1e-8); + EXPECT_NEAR(baryCoefs[1], coef2, 1e-8); + + + // Case 2: Intersection of only 1 segment. 1st point is inside the triangle + ptA = p0 * coef2 + p1 * coef2 + p2 * coef2; + ptB = p0 * coef1 + p2 * coef1; // [p0, p2] is edge local id = 1 + ptA = ptA + bufferZ; + ptB = ptB + (ptB - ptA) - bufferZ; + + intersectedEdges.clear(); + baryCoefs.clear(); + triangleGeo->computeSegmentTriangleIntersectionInPlane(ptA, ptB, tId, intersectedEdges, baryCoefs); + + // check results + EXPECT_EQ(intersectedEdges.size(), 1); + EXPECT_EQ(baryCoefs.size(), 1); + + EXPECT_EQ(intersectedEdges[0], edgeIds[1]); + EXPECT_NEAR(baryCoefs[0], coef1, 1e-8); + + + // Case 3: 1 vertex of the triangle is the intersection. 2 edges are intersected with coef 0 or 1 depending on edge numbering order + ptA = p2 + sofa::type::Vec3(-1.0, 0.0, 0.0) + bufferZ; + ptB = p2 + sofa::type::Vec3(1.0, 0.0, 0.0) - bufferZ; + intersectedEdges.clear(); + baryCoefs.clear(); + triangleGeo->computeSegmentTriangleIntersectionInPlane(ptA, ptB, tId, intersectedEdges, baryCoefs); + + // check results + EXPECT_EQ(intersectedEdges.size(), 2); + EXPECT_EQ(baryCoefs.size(), 2); + + EXPECT_EQ(intersectedEdges[0], edgeIds[0]); + EXPECT_EQ(intersectedEdges[1], edgeIds[1]); + + EXPECT_NEAR(baryCoefs[0], 0.0, 1e-8); + EXPECT_NEAR(baryCoefs[1], 1.0, 1e-8); + + + // Case 4: intersection is going through 1 vertex of the triangle and 1 opposite edge. The 3 edges are intersected + ptA = p0; + ptB = p1 * coef1 + p2 * coef1; + ptA = ptA + (ptA - ptB) + bufferZ; + ptB = ptB + (ptB - ptA) - bufferZ; + + intersectedEdges.clear(); + baryCoefs.clear(); + triangleGeo->computeSegmentTriangleIntersectionInPlane(ptA, ptB, tId, intersectedEdges, baryCoefs); + + // check results + EXPECT_EQ(intersectedEdges.size(), 3); + EXPECT_EQ(baryCoefs.size(), 3); + + EXPECT_EQ(intersectedEdges[0], edgeIds[0]); + EXPECT_EQ(intersectedEdges[1], edgeIds[1]); + EXPECT_EQ(intersectedEdges[2], edgeIds[2]); + + EXPECT_NEAR(baryCoefs[0], coef1, 1e-8); + EXPECT_NEAR(baryCoefs[1], 0.0, 1e-8); + EXPECT_NEAR(baryCoefs[2], 1.0, 1e-8); + + + // Case 5: Segment is colinear to edge local id 2 of the triangle. In this case results should be the 2 others edges intersected with coef 0 or 1. the Edge colinear is not considered + ptA = p0; + ptB = p1; + ptA = ptA + (ptA - ptB) + bufferZ; + ptB = ptB + (ptB - ptA) - bufferZ; + + intersectedEdges.clear(); + baryCoefs.clear(); + triangleGeo->computeSegmentTriangleIntersectionInPlane(ptA, ptB, tId, intersectedEdges, baryCoefs); + + // check results + EXPECT_EQ(intersectedEdges.size(), 2); + EXPECT_EQ(baryCoefs.size(), 2); + + EXPECT_EQ(intersectedEdges[0], edgeIds[0]); + EXPECT_EQ(intersectedEdges[1], edgeIds[1]); + + EXPECT_NEAR(baryCoefs[0], 1.0, 1e-8); + EXPECT_NEAR(baryCoefs[1], 0.0, 1e-8); + + return true; } @@ -321,6 +630,35 @@ TEST_F(TriangleSetTopology_test, checkTopology) } + +TEST_F(TriangleSetTopology_test, testRemovingVertices) +{ + ASSERT_TRUE(testRemovingVertices()); +} + +TEST_F(TriangleSetTopology_test, testRemovingTriangles) +{ + ASSERT_TRUE(testRemovingTriangles()); +} + +TEST_F(TriangleSetTopology_test, testAddingTriangles) +{ + ASSERT_TRUE(testAddingTriangles()); +} + + +TEST_F(TriangleSetTopology_test, testTriangleSegmentIntersectionInPlane) +{ + sofa::type::Vec3 inPlane = sofa::type::Vec3(0.0, 0.0, 0.0); + ASSERT_TRUE(testTriangleSegmentIntersectionInPlane(inPlane)); +} + +TEST_F(TriangleSetTopology_test, testTriangleSegmentIntersectionOutPlane) +{ + sofa::type::Vec3 outPlane = sofa::type::Vec3(0.0, 0.0, 1.0); + ASSERT_TRUE(testTriangleSegmentIntersectionInPlane(outPlane)); +} + + // TODO: test element on Border -// TODO: test triangle add/remove // TODO: test check connectivity diff --git a/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.cpp b/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.cpp index 3a12450b477..e7149516b6d 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.cpp +++ b/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.cpp @@ -29,6 +29,8 @@ namespace sofa::component::visual { +using helper::visual::DrawTool; + void registerLineAxis(sofa::core::ObjectFactory* factory) { factory->registerObjects(core::ObjectRegistrationData("Display scene axis") @@ -38,9 +40,11 @@ void registerLineAxis(sofa::core::ObjectFactory* factory) using namespace sofa::defaulttype; LineAxis::LineAxis() - : d_axis(initData(&d_axis, std::string("xyz"), "axis", "Axis to draw")) - , d_size(initData(&d_size, 10.f, "size", "Size of the squared grid")) - , d_thickness(initData(&d_thickness, 1.f, "thickness", "Thickness of the lines in the grid")) + : d_axis(initData(&d_axis, std::string("xyz"), "axis", "Axis to draw.")) + , d_size(initData(&d_size, 10.f, "size", "Size of the lines.")) + , d_infinite(initData(&d_infinite, false, "infinite", "If true, ignore the 'size' and draw infinite lines.")) + , d_thickness(initData(&d_thickness, 1.f, "thickness", "Thickness of the lines.")) + , d_vanishing(initData(&d_vanishing, false, "vanishing", "In case of infinite lines, should the lines gradually vanish.")) , m_drawX(true), m_drawY(true), m_drawZ(true) {} @@ -73,30 +77,72 @@ void LineAxis::doDrawVisual(const core::visual::VisualParams* vparams) { const double s = sofa::helper::narrow_cast(d_size.getValue()); - vparams->drawTool()->disableLighting(); + auto drawtool = vparams->drawTool(); + drawtool->disableLighting(); + + std::vector points; + points.resize(2); + + std::vector indices = {type::Vec2i(0,1)}; + + const auto& bbox = helper::getReadAccessor(getContext()->f_bbox); + auto v = bbox->maxBBox() - bbox->minBBox(); + const auto& thickness = helper::getReadAccessor(d_thickness); + const auto& vanishing = helper::getReadAccessor(d_vanishing); + const auto& infinite = helper::getReadAccessor(d_infinite); if(m_drawX) { - vparams->drawTool()->drawLine( - helper::visual::DrawTool::Vec3(-s*0.5, 0.0, 0.0), - helper::visual::DrawTool::Vec3(s*0.5, 0.0, 0.0), - helper::visual::DrawTool::RGBAColor(1.0f, 0.0f, 0.0f, 1.0f)); + points[0] = DrawTool::Vec3(-s*0.5, 0.0, 0.0); + points[1] = DrawTool::Vec3(s*0.5, 0.0, 0.0); + + if (!infinite) + { + drawtool->drawLines(points, indices, thickness, DrawTool::RGBAColor::red()); + } + else // infinite line + { + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(v.x(), 0, 0), thickness, + DrawTool::RGBAColor::red(), vanishing); + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(-v.x(), 0, 0), thickness, + DrawTool::RGBAColor::red(), vanishing); + } } if(m_drawY) { - vparams->drawTool()->drawLine( - helper::visual::DrawTool::Vec3(0.0, -s*0.5, 0.0), - helper::visual::DrawTool::Vec3(0.0, s*0.5, 0.0), - helper::visual::DrawTool::RGBAColor(0.0f, 1.0f, 0.0f, 1.0f)); + points[0] = DrawTool::Vec3(0.0, -s*0.5, 0.0); + points[1] = DrawTool::Vec3(0.0, s*0.5, 0.0); + + if (!infinite) + { + drawtool->drawLines(points, indices, thickness, DrawTool::RGBAColor::green()); + } + else // infinite line + { + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(0, v.y(), 0), thickness, + DrawTool::RGBAColor::green(), vanishing); + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(0, -v.y(), 0), thickness, + DrawTool::RGBAColor::green(), vanishing); + } } if(m_drawZ) { - vparams->drawTool()->drawLine( - helper::visual::DrawTool::Vec3(0.0, 0.0, -s*0.5), - helper::visual::DrawTool::Vec3(0.0, 0.0, s*0.5), - helper::visual::DrawTool::RGBAColor(0.0f, 0.0f, 1.0f, 1.0f)); + points[0] = DrawTool::Vec3(0.0, 0.0, -s*0.5); + points[1] = DrawTool::Vec3(0.0, 0.0, s*0.5); + + if (!infinite) + { + drawtool->drawLines(points, indices, thickness, DrawTool::RGBAColor::blue()); + } + else // infinite line + { + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(0, 0, v.z()), thickness, + DrawTool::RGBAColor::blue(), vanishing); + drawtool->drawInfiniteLine(DrawTool::Vec3(0, 0, 0), DrawTool::Vec3(0, 0, -v.z()), thickness, + DrawTool::RGBAColor::blue(), vanishing); + } } } diff --git a/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.h b/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.h index 26bbbebaefa..18ae5ec9a17 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.h +++ b/Sofa/Component/Visual/src/sofa/component/visual/LineAxis.h @@ -33,8 +33,10 @@ class SOFA_COMPONENT_VISUAL_API LineAxis : public core::visual::VisualModel SOFA_CLASS(LineAxis, VisualModel); Data d_axis; ///< Axis to draw - Data d_size; ///< Size of the squared grid - Data d_thickness; ///< Thickness of the lines in the grid + Data d_size; ///< Size of the lines + Data d_infinite; ///< If true, ignore the "size" and draw infinite lines + Data d_thickness; ///< Thickness of the lines + Data d_vanishing; ///< In case of infinite lines, should the lines gradually vanish. core::objectmodel::lifecycle::RemovedData d_draw {this, "v23.06", "23.12", "draw", "Use the 'enable' data field instead of 'draw'"}; LineAxis(); diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualGrid.cpp b/Sofa/Component/Visual/src/sofa/component/visual/VisualGrid.cpp index 2ed11a8d360..cc42ee8dfff 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/VisualGrid.cpp +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualGrid.cpp @@ -184,7 +184,6 @@ void VisualGrid::doDrawVisual(const core::visual::VisualParams* vparams) { vparams->drawTool()->disableLighting(); vparams->drawTool()->drawLines(m_drawnPoints, d_thickness.getValue(), d_color.getValue()); - } } // namespace sofa::component::visual diff --git a/Sofa/GL/src/sofa/gl/DrawToolGL.cpp b/Sofa/GL/src/sofa/gl/DrawToolGL.cpp index 7ceb1e45f21..26aba45cf75 100644 --- a/Sofa/GL/src/sofa/gl/DrawToolGL.cpp +++ b/Sofa/GL/src/sofa/gl/DrawToolGL.cpp @@ -110,15 +110,26 @@ void DrawToolGL::drawLine(const Vec3 &p1, const Vec3 &p2, const type::RGBAColor& glEnd(); } -void DrawToolGL::drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const type::RGBAColor& color) +void DrawToolGL::drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const type::RGBAColor& color, const bool& vanishing) { glBegin(GL_LINES); - glColor4f(color[0],color[1],color[2],color[3]); + + glColor4f(color[0], color[1], color[2], color[3]); glVertex4d(point[0], point[1], point[2], 1.0); + if(vanishing) + glColor4f(color[0], color[1], color[2], 0.0f); glVertex4d(direction[0], direction[1], direction[2], 0.0); + glEnd(); } +void DrawToolGL::drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const float& size, const type::RGBAColor& color, const bool &vanishing) +{ + glLineWidth(size); + drawInfiniteLine(point, direction, color, vanishing); + glLineWidth(1); +} + void DrawToolGL::drawLines(const std::vector &points, float size, const type::RGBAColor& color) { setMaterial(color); diff --git a/Sofa/GL/src/sofa/gl/DrawToolGL.h b/Sofa/GL/src/sofa/gl/DrawToolGL.h index 5f7c18dee34..cea1eb0cd18 100644 --- a/Sofa/GL/src/sofa/gl/DrawToolGL.h +++ b/Sofa/GL/src/sofa/gl/DrawToolGL.h @@ -52,7 +52,9 @@ class SOFA_GL_API DrawToolGL : public helper::visual::DrawTool virtual void drawPoints(const std::vector &points, float size, const std::vector& color) override; void drawLine(const type::Vec3 &p1, const type::Vec3 &p2, const type::RGBAColor& color) override; - void drawInfiniteLine(const type::Vec3 &point, const type::Vec3 &direction, const type::RGBAColor& color) override; + void drawInfiniteLine(const type::Vec3 &point, const type::Vec3 &direction, const type::RGBAColor& color, const bool& vanishing=false) override; + void drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const float& size, const type::RGBAColor& color, const bool& vanishing=false) override; + virtual void drawLines(const std::vector &points, float size, const type::RGBAColor& color) override; virtual void drawLines(const std::vector &points, float size, const std::vector& colors) override; virtual void drawLines(const std::vector &points, const std::vector< type::Vec2i > &index, float size, const type::RGBAColor& color) override; diff --git a/Sofa/GUI/CMakeLists.txt b/Sofa/GUI/CMakeLists.txt index 2e983351bd6..e24b621396d 100644 --- a/Sofa/GUI/CMakeLists.txt +++ b/Sofa/GUI/CMakeLists.txt @@ -20,7 +20,7 @@ else() list(APPEND SOFAGUI_MISSINGTARGETS ${PROJECT_NAME}.Common) endif() -set(SOFAGUI_DIRS Batch Qt) +set(SOFAGUI_DIRS Batch) foreach(dir ${SOFAGUI_DIRS}) sofa_add_subdirectory(plugin ${dir} ${PROJECT_NAME}.${dir} ON) if(TARGET ${PROJECT_NAME}.${dir}) diff --git a/Sofa/GUI/Common/CMakeLists.txt b/Sofa/GUI/Common/CMakeLists.txt index 995a47bf217..8f764ae8fb5 100644 --- a/Sofa/GUI/Common/CMakeLists.txt +++ b/Sofa/GUI/Common/CMakeLists.txt @@ -35,7 +35,6 @@ set(HEADER_FILES ${SOFAGUICOMMON_ROOT}/BaseViewer.h ${SOFAGUICOMMON_ROOT}/ColourPickingVisitor.h ${SOFAGUICOMMON_ROOT}/FilesRecentlyOpenedManager.h - ${SOFAGUICOMMON_ROOT}/GuiDataRepository.h ${SOFAGUICOMMON_ROOT}/GUIManager.h ${SOFAGUICOMMON_ROOT}/MouseOperations.h ${SOFAGUICOMMON_ROOT}/OperationFactory.h @@ -50,7 +49,6 @@ set(SOURCE_FILES ${SOFAGUICOMMON_ROOT}/BaseViewer.cpp ${SOFAGUICOMMON_ROOT}/ColourPickingVisitor.cpp ${SOFAGUICOMMON_ROOT}/FilesRecentlyOpenedManager.cpp - ${SOFAGUICOMMON_ROOT}/GuiDataRepository.cpp ${SOFAGUICOMMON_ROOT}/GUIManager.cpp ${SOFAGUICOMMON_ROOT}/MouseOperations.cpp ${SOFAGUICOMMON_ROOT}/PickHandler.cpp diff --git a/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.cpp b/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.cpp deleted file mode 100644 index c1aa11d99ab..00000000000 --- a/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include - -using sofa::helper::system::FileRepository; -using sofa::helper::Utils; - -namespace sofa::gui::common -{ - -FileRepository GuiDataRepository( - "GUI_DATA_PATH", - { - Utils::getSofaPathTo("share/sofa/gui/qt") - }, - { - { Utils::getSofaPathTo("etc/Sofa.Gui.Qt.ini").c_str(), {"RESOURCES_DIR"} } - } -); - -} // namespace sofa::gui::common diff --git a/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.h b/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.h deleted file mode 100644 index 088942ad6a4..00000000000 --- a/Sofa/GUI/Common/src/sofa/gui/common/GuiDataRepository.h +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include - -namespace sofa::gui::common -{ - extern SOFA_GUI_COMMON_API sofa::helper::system::FileRepository GuiDataRepository; -} // namespace sofa::gui::common diff --git a/Sofa/GUI/Qt/CMakeLists.txt b/Sofa/GUI/Qt/CMakeLists.txt deleted file mode 100644 index 85ebe4e49ee..00000000000 --- a/Sofa/GUI/Qt/CMakeLists.txt +++ /dev/null @@ -1,406 +0,0 @@ -cmake_minimum_required(VERSION 3.22) -project(Sofa.GUI.Qt LANGUAGES CXX) - -# Detect if component is compiled outside SOFA -if ("${CMAKE_PROJECT_NAME}" STREQUAL "${PROJECT_NAME}") - find_package(Sofa.Config REQUIRED) - sofa_find_package(Sofa.GUI.Common REQUIRED) -endif() - -# Qt dependencies -set(SOFA_GUI_QT_TARGETS "") -set(QT_USE_IMPORTED_TARGETS 1) -set(QT5_NO_LINK_QTMAIN 1) - - - - -# Will only use Qt5 if Qt5 is found and Qt6 is not found -# if Qt5 and Qt6 are both found, Qt6 will take priority -find_package(Qt6 COMPONENTS Core CoreTools QUIET) -if (NOT Qt6Core_FOUND) - find_package(Qt5 COMPONENTS Core QUIET) -endif() - -if (Qt6Core_FOUND) - message("${PROJECT_NAME}: will use Qt6") - find_package(Qt6 COMPONENTS Gui GuiTools Widgets WidgetsTools OpenGLWidgets REQUIRED) - # GuiTools & WidgetsTools does not define a Qt6::component CMake target - # So we can't look for those target to know how we should define SOFA_GUI_QT_HAVE_QT6 - sofa_find_package(Qt6 COMPONENTS Gui Widgets OpenGLWidgets REQUIRED) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt::Core Qt::Gui Qt::Widgets Qt::OpenGLWidgets ) -elseif (Qt5Core_FOUND) - message("${PROJECT_NAME}: will use Qt5 (deprecated)") - sofa_find_package(Qt5 COMPONENTS Core Gui OpenGL REQUIRED) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt5::Core Qt5::Gui Qt5::OpenGL) -else() - message(SEND_ERROR "${PROJECT_NAME}: Could not find either Qt5 or Qt6.") -endif() - -if (Qt5Core_FOUND) - # Profiling - sofa_find_package(Qt5 COMPONENTS Charts QUIET BOTH_SCOPES) - if(Qt5Charts_FOUND) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt5::Charts) - else() - message(STATUS "${PROJECT_NAME}: Qt5Charts not found. No chart nor Profile will be compiled") - endif() - - # QDocBrowser - find_package(Qt5 COMPONENTS WebEngine QUIET) # if found, then QDocBrowser will be ON by default - option(SOFA_GUI_QT_ENABLE_QDOCBROWSER "Build the QDocBrowser. QtWebEngine is needed." ${Qt5WebEngine_FOUND}) - - if(SOFA_GUI_QT_ENABLE_QDOCBROWSER) - sofa_find_package(Qt5 COMPONENTS WebEngine WebEngineWidgets REQUIRED BOTH_SCOPES) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt5::WebEngine Qt5::WebEngineWidgets) - endif() -elseif (Qt6Core_FOUND) - - # Profiling - sofa_find_package(Qt6 COMPONENTS Charts QUIET BOTH_SCOPES) - if(Qt6Charts_FOUND) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt::Charts) - else() - message(STATUS "${PROJECT_NAME}: Qt6 Charts not found. No chart nor Profile will be compiled") - endif() - - # # QDocBrowser - find_package(Qt6 COMPONENTS WebEngineCore QUIET) # if found, then QDocBrowser will be ON by default - option(SOFA_GUI_QT_ENABLE_QDOCBROWSER "Build the QDocBrowser. QtWebEngine is needed." ${Qt6WebEngineCore_FOUND}) - if(SOFA_GUI_QT_ENABLE_QDOCBROWSER) - # WebEngineCore needs Positioning WebChannel at cmake configure step (?) - sofa_find_package(Qt6 COMPONENTS Positioning WebChannel WebEngineCore WebEngineWidgets REQUIRED BOTH_SCOPES) - set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt::WebEngineCore Qt::WebEngineWidgets) - endif() -endif() - - -sofa_find_package(Sofa.GL QUIET) - -# QtViewer and QGLViewer -if(Sofa.GL_FOUND) - # QtViewer - option(SOFA_GUI_QT_ENABLE_QTVIEWER "Compile the QtViewer for the Qt GUI" ON) - - # QGLViewer - option(SOFA_GUI_QT_ENABLE_QGLVIEWER "Compile the QGLViewer for the Qt GUI" ON) - - if(SOFA_GUI_QT_ENABLE_QGLVIEWER) - - find_package(QGLViewer QUIET) - if(NOT QGLViewer_FOUND AND SOFA_ALLOW_FETCH_DEPENDENCIES) - message("Sofa.GUI.Qt: DEPENDENCY QGLViewer NOT FOUND. SOFA_ALLOW_FETCH_DEPENDENCIES is ON, fetching QGLViewer...") - include(FetchContent) - FetchContent_Declare(QGLViewer - GIT_REPOSITORY https://github.com/sofa-framework/libQGLViewer/ - GIT_TAG v2.8.1_SOFA - ) - FetchContent_MakeAvailable(QGLViewer) - elseif (NOT QGLViewer_FOUND) - message(FATAL_ERROR "Sofa.GUI.Qt: DEPENDENCY QGLViewer NOT FOUND. SOFA_ALLOW_FETCH_DEPENDENCIES is OFF and thus cannot be fetched. Install QGLViewer (version=2.8.0), or enable SOFA_ALLOW_FETCH_DEPENDENCIES to fix this issue.") - endif() - endif() -else() - message(STATUS "Sofa.GUI.Qt: Sofa.GL has not been activated, QtViewer/QGLViewer will be disabled.") - set(SOFA_GUI_QT_ENABLE_QTVIEWER OFF) - set(SOFA_GUI_QT_ENABLE_QGLVIEWER OFF) -endif() - -# VSync -option(SOFA_GUI_QT_ENABLE_VSYNC "Enable vertical refresh sync" OFF) - -# Qt native menu -set(DEFAULT_SOFA_GUI_QT_ENABLE_NATIVE_MENU ON) -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(DEFAULT_SOFA_GUI_QT_ENABLE_NATIVE_MENU OFF) -endif() -option(SOFA_GUI_QT_ENABLE_NATIVE_MENU "Enable Qt to use the operating system's native menu for the Qt GUI" ${DEFAULT_SOFA_GUI_QT_ENABLE_NATIVE_MENU}) - -# NodeEditor -option(SOFA_GUI_QT_ENABLE_NODEGRAPH "Build the Node graph representation. NodeEditor library is needed." OFF) -if(SOFA_GUI_QT_ENABLE_NODEGRAPH) - sofa_find_package(NodeEditor REQUIRED BOTH_SCOPES) -endif() - -# FFMPEG_exec -sofa_find_package(FFMPEG_exec BOTH_SCOPES) - -# TinyXML -if(SOFA_DUMP_VISITOR_INFO) - sofa_find_package(TinyXML2 REQUIRED BOTH_SCOPES) -endif() - - - -set(SRC_ROOT src/sofa/gui/qt) - -set(MOC_HEADER_FILES - ${SRC_ROOT}/AboutSOFADialog.h - ${SRC_ROOT}/DataFilenameWidget.h - ${SRC_ROOT}/DataWidget.h - ${SRC_ROOT}/DisplayFlagsDataWidget.h - ${SRC_ROOT}/GenGraphForm.h - ${SRC_ROOT}/LinkWidget.h - ${SRC_ROOT}/MaterialDataWidget.h - ${SRC_ROOT}/RGBAColorDataWidget.h - ${SRC_ROOT}/ModifyObject.h - ${SRC_ROOT}/QDataDescriptionWidget.h - ${SRC_ROOT}/QDisplayDataWidget.h - ${SRC_ROOT}/QDisplayLinkWidget.h - ${SRC_ROOT}/QDisplayPropertyWidget.h - ${SRC_ROOT}/QRGBAColorPicker.h - ${SRC_ROOT}/QModelViewTableUpdater.h - ${SRC_ROOT}/QMouseOperations.h - ${SRC_ROOT}/QMouseWheelAdjustementGuard.h - ${SRC_ROOT}/QSofaListView.h - ${SRC_ROOT}/QSofaStatWidget.h - ${SRC_ROOT}/QTabulationModifyObject.h - ${SRC_ROOT}/QtMessageRedirection.h - ${SRC_ROOT}/QTransformationWidget.h - ${SRC_ROOT}/RealGUI.h - ${SRC_ROOT}/SimpleDataWidget.h - ${SRC_ROOT}/SofaMouseManager.h - ${SRC_ROOT}/SofaVideoRecorderManager.h - ${SRC_ROOT}/SofaPluginManager.h - ${SRC_ROOT}/SofaSceneGraphWidget.h - ${SRC_ROOT}/WDoubleLineEdit.h - ) -set(HEADER_FILES - ${SRC_ROOT}/config.h.in - ${SRC_ROOT}/fwd.h - ${SRC_ROOT}/init.h - ${SRC_ROOT}/qt.conf.h - ${SRC_ROOT}/FileManagement.h - ${SRC_ROOT}/GraphListenerQListView.h - ${SRC_ROOT}/PickHandlerCallBacks.h - ${SRC_ROOT}/QMenuFilesRecentlyOpened.h - ${SRC_ROOT}/QModelViewTableDataContainer.h - ${SRC_ROOT}/StructDataWidget.h - ${SRC_ROOT}/TableDataWidget.h - ${SRC_ROOT}/viewer/SofaViewer.h - ${SRC_ROOT}/viewer/EngineBackend.h - ${SRC_ROOT}/viewer/VisualModelPolicy.h - ${SRC_ROOT}/GenericWidget.h - ) -set(SOURCE_FILES - ${SRC_ROOT}/init.cpp - ${SRC_ROOT}/AboutSOFADialog.cpp - ${SRC_ROOT}/DataFilenameWidget.cpp - ${SRC_ROOT}/DataWidget.cpp - ${SRC_ROOT}/DisplayFlagsDataWidget.cpp - ${SRC_ROOT}/FileManagement.cpp - ${SRC_ROOT}/GenGraphForm.cpp - ${SRC_ROOT}/GraphListenerQListView.cpp - ${SRC_ROOT}/LinkWidget.cpp - ${SRC_ROOT}/MaterialDataWidget.cpp - ${SRC_ROOT}/RGBAColorDataWidget.cpp - ${SRC_ROOT}/ModifyObject.cpp - ${SRC_ROOT}/PickHandlerCallBacks.cpp - ${SRC_ROOT}/QDataDescriptionWidget.cpp - ${SRC_ROOT}/QDisplayDataWidget.cpp - ${SRC_ROOT}/QDisplayLinkWidget.cpp - ${SRC_ROOT}/QDisplayPropertyWidget.cpp - ${SRC_ROOT}/QRGBAColorPicker.cpp - ${SRC_ROOT}/QMenuFilesRecentlyOpened.cpp - ${SRC_ROOT}/QModelViewTableUpdater.cpp - ${SRC_ROOT}/QMouseOperations.cpp - ${SRC_ROOT}/QMouseWheelAdjustementGuard.cpp - ${SRC_ROOT}/QSofaListView.cpp - ${SRC_ROOT}/QSofaStatWidget.cpp - ${SRC_ROOT}/QTabulationModifyObject.cpp - ${SRC_ROOT}/QtMessageRedirection.cpp - ${SRC_ROOT}/QTransformationWidget.cpp - ${SRC_ROOT}/RealGUI.cpp - ${SRC_ROOT}/SimpleDataWidget.cpp - ${SRC_ROOT}/SofaMouseManager.cpp - ${SRC_ROOT}/SofaPluginManager.cpp - ${SRC_ROOT}/SofaVideoRecorderManager.cpp - ${SRC_ROOT}/StructDataWidget.cpp - ${SRC_ROOT}/TableDataWidget.cpp - ${SRC_ROOT}/WDoubleLineEdit.cpp - ${SRC_ROOT}/viewer/SofaViewer.cpp - ${SRC_ROOT}/SofaSceneGraphWidget.cpp - ${SRC_ROOT}/viewer/VisualModelPolicy.cpp -) -set(UI_FILES - ${SRC_ROOT}/AboutDialog.ui - ${SRC_ROOT}/BaseGenGraphForm.ui - ${SRC_ROOT}/DialogAddObject.ui - ${SRC_ROOT}/GUI.ui - ${SRC_ROOT}/MouseManager.ui - ${SRC_ROOT}/PluginManager.ui - ${SRC_ROOT}/VideoRecorderManager.ui -) -set(QRC_FILES - ${SRC_ROOT}/resources/RealGUI.qrc -) - - -if(SOFA_DUMP_VISITOR_INFO) - list(APPEND MOC_HEADER_FILES - ${SRC_ROOT}/WindowVisitor.h - ${SRC_ROOT}/QVisitorControlPanel.h - ${SRC_ROOT}/PieWidget.h - ) - list(APPEND HEADER_FILES - ${SRC_ROOT}/GraphVisitor.h - ) - list(APPEND SOURCE_FILES - ${SRC_ROOT}/GraphVisitor.cpp - ${SRC_ROOT}/WindowVisitor.cpp - ${SRC_ROOT}/QVisitorControlPanel.cpp - ${SRC_ROOT}/PieWidget.cpp - ) - list(APPEND UI_FILES - ${SRC_ROOT}/VisitorGUI.ui - ) -endif() - -if(Sofa.GL_FOUND) - list(APPEND HEADER_FILES - ${SRC_ROOT}/GLPickHandler.h - ${SRC_ROOT}/viewer/GLBackend.h - ${SRC_ROOT}/viewer/OglModelPolicy.h - ) - list(APPEND SOURCE_FILES - ${SRC_ROOT}/GLPickHandler.cpp - ${SRC_ROOT}/viewer/GLBackend.cpp - ${SRC_ROOT}/viewer/OglModelPolicy.cpp - ) - - # QtViewer - if(SOFA_GUI_QT_ENABLE_QTVIEWER) - list(APPEND MOC_HEADER_FILES ${SRC_ROOT}/viewer/qt/QtViewer.h) - list(APPEND SOURCE_FILES ${SRC_ROOT}/viewer/qt/QtViewer.cpp) - endif() - - if(SOFA_GUI_QT_ENABLE_QGLVIEWER) - list(APPEND MOC_HEADER_FILES ${SRC_ROOT}/viewer/qgl/QtGLViewer.h) - list(APPEND SOURCE_FILES ${SRC_ROOT}/viewer/qgl/QtGLViewer.cpp) - endif() - -endif() - -# QtCharts -if(Qt5Charts_FOUND OR Qt6Charts_FOUND) - list(APPEND MOC_HEADER_FILES - ${SRC_ROOT}/SofaWindowProfiler.h - ${SRC_ROOT}/QGraphStatWidget.h - ${SRC_ROOT}/QEnergyStatWidget.h - ${SRC_ROOT}/QMomentumStatWidget.h - ${SRC_ROOT}/GraphDataWidget.h - ) - list(APPEND SOURCE_FILES - ${SRC_ROOT}/SofaWindowProfiler.cpp - ${SRC_ROOT}/QGraphStatWidget.cpp - ${SRC_ROOT}/QEnergyStatWidget.cpp - ${SRC_ROOT}/QMomentumStatWidget.cpp - ${SRC_ROOT}/GraphDataWidget.cpp - ) - list(APPEND UI_FILES ${SRC_ROOT}/WindowProfiler.ui) -else() - message(STATUS "${PROJECT_NAME}: QtCharts not found, SofaWindowProfiler will not be built.") -endif() - -if(SOFA_GUI_QT_ENABLE_QDOCBROWSER) - list(APPEND MOC_HEADER_FILES ${SRC_ROOT}/panels/QDocBrowser.h) - list(APPEND SOURCE_FILES ${SRC_ROOT}/panels/QDocBrowser.cpp) -else() - message(STATUS "${PROJECT_NAME}: QtWebEngine not found, QDocBrowser will not be built.") -endif() - - - - -#NodeEditor -if (SOFA_GUI_QT_ENABLE_NODEGRAPH) - list(APPEND MOC_HEADER_FILES - ${SRC_ROOT}/SofaWindowDataGraph.h - ${SRC_ROOT}/dataGraph/SofaComponentNodeModel.h - ) - - list(APPEND SOURCE_FILES - ${SRC_ROOT}/SofaWindowDataGraph.cpp - ${SRC_ROOT}/dataGraph/SofaComponentNodeModel.cpp - ) -endif() - -if (Qt5Core_FOUND) - qt5_wrap_cpp(MOC_FILES ${MOC_HEADER_FILES}) - qt5_wrap_ui(FORM_FILES ${UI_FILES}) -elseif (Qt6Core_FOUND) - qt6_wrap_cpp(MOC_FILES ${MOC_HEADER_FILES}) - qt6_wrap_ui(FORM_FILES ${UI_FILES}) -endif() -set(MOC_FILES_GROUP "Generated") -set(FORM_FILES_GROUP "Generated") - -sofa_find_package(Sofa.Component.Visual REQUIRED) -sofa_find_package(Sofa.Component.SceneUtility REQUIRED) - -set(CMAKE_AUTORCC ON) -add_library(${PROJECT_NAME} SHARED ${MOC_HEADER_FILES} ${HEADER_FILES} ${MOC_FILES} ${FORM_FILES} ${SOURCE_FILES} ${QRC_FILES}) - - -# For files generated by the moc -target_include_directories(${PROJECT_NAME} PUBLIC "$") - -target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.GUI.Common) -target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Component.Visual) -target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Component.SceneUtility) -target_link_libraries(${PROJECT_NAME} PUBLIC ${SOFA_GUI_QT_TARGETS}) - - - -if(SOFA_DUMP_VISITOR_INFO) - target_link_libraries(${PROJECT_NAME} PRIVATE tinyxml2::tinyxml2) -endif() - -if(Sofa.GL_FOUND) - target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.GL) - if(SOFA_GUI_QT_ENABLE_QGLVIEWER) - target_link_libraries(${PROJECT_NAME} PUBLIC QGLViewer) - include_directories(${PROJECT_NAME} PUBLIC ${qglviewer_SOURCE_DIR}) - endif() -endif() - -if(SOFA_GUI_QT_ENABLE_NODEGRAPH) - target_link_libraries(${PROJECT_NAME} PUBLIC NodeEditor::nodes) - if (SOFA_BUILD_RELEASE_PACKAGE OR CMAKE_SYSTEM_NAME STREQUAL Windows) - sofa_install_libraries(TARGETS NodeEditor::nodes) - endif() -endif() - -# FFMPEG -if(FFMPEG_EXEC_FOUND) - install(PROGRAMS "${FFMPEG_EXEC_FILE}" DESTINATION bin COMPONENT applications) -endif() - -# Create build and install versions of .ini file for resources finding -set(RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_ROOT}/resources") -set(FFMPEG_EXEC_PATH "${FFMPEG_EXEC_FILE}") # absolute path for build dir, see .ini file -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/etc/${PROJECT_NAME}.ini.in "${CMAKE_BINARY_DIR}/etc/${PROJECT_NAME}.ini") -set(RESOURCES_DIR "../share/sofa/gui/qt") -get_filename_component(FFMPEG_EXEC_FILENAME "${FFMPEG_EXEC_FILE}" NAME) -set(FFMPEG_EXEC_PATH "../bin/${FFMPEG_EXEC_FILENAME}") # relative path for install dir, see .ini file -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/etc/${PROJECT_NAME}.ini.in "${CMAKE_BINARY_DIR}/etc/installed${PROJECT_NAME}.ini") -install(FILES "${CMAKE_BINARY_DIR}/etc/installed${PROJECT_NAME}.ini" DESTINATION etc RENAME ${PROJECT_NAME}.ini COMPONENT applications) - -install(DIRECTORY "${SRC_ROOT}/resources/" DESTINATION "share/sofa/gui/qt" COMPONENT resources) - - - - -sofa_create_package_with_targets( - PACKAGE_NAME ${PROJECT_NAME} - PACKAGE_VERSION ${Sofa_VERSION} - TARGETS ${PROJECT_NAME} AUTO_SET_TARGET_PROPERTIES - INCLUDE_SOURCE_DIR "src" - INCLUDE_INSTALL_DIR ${PROJECT_NAME} - ) - -# Qt deployment -if(CMAKE_SYSTEM_NAME STREQUAL Windows) - include(windeployqt) - windeployqt(${PROJECT_NAME} ${CMAKE_BINARY_DIR}/bin bin) -endif() diff --git a/Sofa/GUI/Qt/LICENSE.GPL.txt b/Sofa/GUI/Qt/LICENSE.GPL.txt deleted file mode 100644 index 23cb790338e..00000000000 --- a/Sofa/GUI/Qt/LICENSE.GPL.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Sofa/GUI/Qt/Sofa.GUI.QtConfig.cmake.in b/Sofa/GUI/Qt/Sofa.GUI.QtConfig.cmake.in deleted file mode 100644 index f9e7ce28642..00000000000 --- a/Sofa/GUI/Qt/Sofa.GUI.QtConfig.cmake.in +++ /dev/null @@ -1,62 +0,0 @@ -# CMake package configuration file for the @PROJECT_NAME@ module - -@PACKAGE_GUARD@ -@PACKAGE_INIT@ - -set(SOFA_GUI_QT_HAVE_QT5 @SOFA_GUI_QT_HAVE_QT5@) -set(SOFA_GUI_QT_HAVE_QT6 @SOFA_GUI_QT_HAVE_QT6@) - -set(SOFA_GUI_QT_ENABLE_QTVIEWER @SOFA_GUI_QT_ENABLE_QTVIEWER@) -set(SOFA_GUI_QT_ENABLE_QGLVIEWER @SOFA_GUI_QT_ENABLE_QGLVIEWER@) -set(SOFA_GUI_QT_ENABLE_NATIVE_MENU @SOFA_GUI_QT_ENABLE_NATIVE_MENU@) -set(SOFA_GUI_QT_ENABLE_VSYNC @SOFA_GUI_QT_ENABLE_VSYNC@) - -set(SOFA_GUI_QT_HAVE_QT5_CHARTS @SOFA_GUI_QT_HAVE_QT5_CHARTS@) -set(SOFA_GUI_QT_HAVE_QT5_WEBENGINE @SOFA_GUI_QT_HAVE_QT5_WEBENGINE@) -set(SOFA_GUI_QT_HAVE_NODEEDITOR @SOFA_GUI_QT_HAVE_NODEEDITOR@) -set(SOFA_GUI_QT_HAVE_TINYXML @SOFA_GUI_QT_HAVE_TINYXML@) - -set(SOFA_GUI_QT_HAVE_QT6_CHARTS @SOFA_GUI_QT_HAVE_QT6_CHARTS@) -set(SOFA_GUI_QT_HAVE_QT6_WEBENGINECORE @SOFA_GUI_QT_HAVE_QT6_WEBENGINECORE@) - -# This is needed to be able to find plugins/SofaGuiQt/lib/cmake/QGLViewer -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/..") - -find_package(Sofa.GUI.Common QUIET REQUIRED) -find_package(Sofa.Component.Visual QUIET REQUIRED) -find_package(Sofa.Component.SceneUtility QUIET REQUIRED) - -if(SOFA_GUI_QT_HAVE_QT5) - find_package(Qt5 QUIET REQUIRED Core Gui OpenGL) - if(SOFA_GUI_QT_HAVE_QT5_CHARTS) - find_package(Qt5 QUIET REQUIRED Charts) - endif() - if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - find_package(Qt5 QUIET REQUIRED WebEngine WebEngineWidgets) - endif() - if(SOFA_GUI_QT_ENABLE_QGLVIEWER) - find_package(QGLViewer QUIET REQUIRED) - endif() -elseif(SOFA_GUI_QT_HAVE_QT6) - find_package(Qt6 COMPONENTS Widgets OpenGLWidgets QUIET REQUIRED) - if(SOFA_GUI_QT_HAVE_QT6_CHARTS) - find_package(Qt6 QUIET REQUIRED Charts) - endif() - if(SOFA_GUI_QT_HAVE_QT6_WEBENGINECORE) - find_package(Qt6 QUIET REQUIRED Positioning WebChannel WebEngineCore WebEngineWidgets) - endif() - if(SOFA_GUI_QT_ENABLE_QGLVIEWER) - find_package(QGLViewer QUIET REQUIRED) - endif() -endif() - -if(SOFA_GUI_QT_HAVE_NODEEDITOR) - find_package(NodeEditor QUIET REQUIRED) -endif() - - -if(NOT TARGET @PROJECT_NAME@) - include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") -endif() - -check_required_components(@PROJECT_NAME@) diff --git a/Sofa/GUI/Qt/etc/Sofa.GUI.Qt.ini.in b/Sofa/GUI/Qt/etc/Sofa.GUI.Qt.ini.in deleted file mode 100644 index 27a0653ccb6..00000000000 --- a/Sofa/GUI/Qt/etc/Sofa.GUI.Qt.ini.in +++ /dev/null @@ -1,2 +0,0 @@ -RESOURCES_DIR=@RESOURCES_DIR@ -FFMPEG_EXEC_PATH=@FFMPEG_EXEC_PATH@ diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutDialog.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/AboutDialog.ui deleted file mode 100644 index 83fa0b0cb74..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutDialog.ui +++ /dev/null @@ -1,209 +0,0 @@ - - - AboutDialog - - - true - - - - 0 - 0 - 464 - 543 - - - - - 0 - 0 - - - - About - - - false - - - false - - - - QLayout::SetFixedSize - - - - - - - - Qt::AlignCenter - - - false - - - - - - - 0 - 0 - - - - - - - SOFA is an open-source framework for interactive physics simulation, with an emphasis on soft body dynamics. After years of research and development, the project remains open-source under the LGPL v2.1 license, fostering both research and development. - - - false - - - true - - - - - - - Open-source is kept thriving thanks to partners supporting us: be part of the community and get involved your own way! - - - Qt::AutoText - - - true - - - - - - - - 0 - 0 - - - - - - - Qt::LeftToRight - - - - - - Qt::PlainText - - - Qt::AlignCenter - - - false - - - 0 - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - 150 - 40 - - - - Support us - - - false - - - true - - - true - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - SOFA, Simulation Open-Framework Architecture (c) 2006 INRIA, USTL, UJF, CNRS, MGH - - - Qt::AlignCenter - - - true - - - - - - - - - - buttonOk - clicked() - AboutDialog - accept() - - - 223 - 226 - - - 20 - 20 - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.cpp deleted file mode 100644 index e6d2edd9521..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "AboutSOFADialog.h" -#include - -#include -#include -#include - -#include -using sofa::helper::system::DataRepository; - -namespace sofa::gui::qt -{ - -AboutSOFADialog::AboutSOFADialog(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - connect(buttonOk, &QPushButton::clicked, this, &AboutSOFADialog::clickSupportUs); - - std::string file = "icons/AboutSOFA.png"; - if (DataRepository.findFile(file)) - { - const QPixmap pix(QPixmap::fromImage(QImage(DataRepository.getFile ( file ).c_str()))); - label_2->setPixmap(pix); - } -} - -void AboutSOFADialog::clickSupportUs() -{ - QDesktopServices::openUrl(QUrl("https://www.sofa-framework.org/consortium/support-us/")); -} - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.h b/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.h deleted file mode 100644 index 122bc5738da..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/AboutSOFADialog.h +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API AboutSOFADialog: public QDialog, public Ui_AboutDialog -{ - Q_OBJECT -public: - AboutSOFADialog(QWidget *parent); - -public slots: - void clickSupportUs(); -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/BaseGenGraphForm.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/BaseGenGraphForm.ui deleted file mode 100644 index ac73925ed81..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/BaseGenGraphForm.ui +++ /dev/null @@ -1,1065 +0,0 @@ - - - BaseGenGraphForm - - - - 0 - 0 - 382 - 654 - - - - Sofa Graph Export - - - - - - - - - 1 - 0 - - - - Output DOT &File - - - false - - - filename - - - - - - - Browse... - - - - - - - untitled - - - - - - - - - - - Layout - - - - - - Directed Vertically - - - true - - - - - - - Directed Horizontally - - - - - - - Undirected Spring - - - - - - - Undirected Radial - - - - - - - - - - Outputs - - - - - - Generate PNG - - - true - - - - - - - Generate PS - - - - - - - Generate FIG - - - - - - - Generate SVG - - - - - - - - - - - - - - Presets - - - false - - - - - - - - 1 - 0 - - - - true - - - QComboBox::InsertAtTop - - - false - - - true - - - - Full Graph - - - - - All Objects - - - - - All Nodes - - - - - Mechanical Graph - - - - - Mechanical Objects - - - - - Visual Graph - - - - - Visual Objects - - - - - Collision Graph - - - - - Collision Objects - - - - - Collision Response Graph - - - - - Collision Response Objects - - - - - - - - - - Filter - - - - - - Solvers - - - true - - - - - - - Mechanical Models - - - true - - - - - - - Force Fields - - - true - - - - - - - Interaction Force Fields - - - true - - - - - - - Constraints - - - true - - - - - - - Mass - - - true - - - - - - - Mechanical Mappings - - - true - - - - - - - Topology - - - true - - - - - - - Mappings - - - true - - - - - - - Collision Models - - - true - - - - - - - Visual Models - - - true - - - - - - - Collision Pipeline - - - true - - - - - - - Behavior Models - - - true - - - - - - - Context - - - true - - - - - - - Objects - - - true - - - - - - - Nodes - - - true - - - - - - - - - - - - Nodes Labels - - - - - - Name - - - true - - - - - - - Class - - - - - - - - - - Objects Labels - - - - - - Name - - - true - - - - - - - Class - - - true - - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 16 - 20 - - - - - - - - false - - - &Display - - - Alt+D - - - - - - - &Export - - - Alt+E - - - true - - - - - - - &Close - - - Alt+C - - - - - - - - - - filename - browseButton - layoutDirV - layoutDirH - layoutSpring - layoutRadial - genPNG - genPS - genFIG - genSVG - showSolvers - showMechanicalStates - showForceFields - showInteractionForceFields - showConstraints - showMass - showMechanicalMappings - showTopology - showMappings - showCollisionModels - showVisualModels - showCollisionPipeline - showBehaviorModels - showContext - showObjects - showNodes - labelNodeName - labelNodeClass - labelObjectName - labelObjectClass - displayButton - exportButton - - - - - showObjects - toggled(bool) - showBehaviorModels - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showCollisionModels - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showVisualModels - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showMappings - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showContext - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showCollisionPipeline - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showSolvers - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showMechanicalStates - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showForceFields - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showInteractionForceFields - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showConstraints - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showMass - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showTopology - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - showMechanicalMappings - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - groupObjectLabel - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showNodes - toggled(bool) - groupNodeLabel - setEnabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - showNodes - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showObjects - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showBehaviorModels - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showCollisionModels - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showVisualModels - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showMappings - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showContext - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showCollisionPipeline - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showSolvers - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showMechanicalStates - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showForceFields - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showInteractionForceFields - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showConstraints - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showMass - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showTopology - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - showMechanicalMappings - toggled(bool) - presetFilter - clearEditText() - - - 20 - 20 - - - 20 - 20 - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.cpp deleted file mode 100644 index fa1575132ec..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "DataFilenameWidget.h" -#include - -#include "FileManagement.h" //static functions to manage opening/ saving of files -#include -#include - - -#include - -namespace sofa::gui::qt -{ - -helper::Creator DW_Datafilename("widget_filename",false); - - - -bool DataFileNameWidget::createWidgets() -{ - QHBoxLayout* layout = new QHBoxLayout(this); - - openFilePath = new QLineEdit(this); - const std::string& filepath = this->getData()->getValue(); - openFilePath->setText( QString(filepath.c_str()) ); - - openFileButton = new QPushButton(this); - openFileButton->setText("..."); - - layout->addWidget(openFilePath); - layout->addWidget(openFileButton); - connect( openFileButton, &QPushButton::clicked, this, &DataFileNameWidget::raiseDialog ); - connect( openFilePath, &QLineEdit::textChanged, [=](const QString &){ setWidgetDirty(); } ); - return true; -} - -void DataFileNameWidget::setDataReadOnly(bool readOnly) -{ - openFilePath->setReadOnly(readOnly); - openFileButton->setEnabled(!readOnly); -} - -void DataFileNameWidget::readFromData() -{ - const std::string& filepath = this->getData()->getValue(); - if (openFilePath->text().toStdString() != filepath) - openFilePath->setText(QString(filepath.c_str()) ); -} - -void DataFileNameWidget::writeToData() -{ - const std::string fileName( openFilePath->text().toStdString() ); - if (this->getData()->getValueString() != fileName) - this->getData()->setValue(fileName); - -} - - -void DataFileNameWidget::raiseDialog() -{ - std::string fileName( openFilePath->text().toStdString() ); - - if (sofa::helper::system::DataRepository.findFile(fileName)) - fileName=sofa::helper::system::DataRepository.getFile(fileName); - else - fileName=sofa::helper::system::DataRepository.getFirstPath(); - - const QString s = getOpenFileName(this, QString(fileName.c_str()), "All (*)", "open file dialog", "Choose a file to open" ); - const std::string SofaPath = sofa::helper::system::DataRepository.getFirstPath(); - - if (s.isNull() ) return; - fileName=std::string (s.toStdString()); - fileName = sofa::helper::system::FileRepository::relativeToPath(fileName,SofaPath); - - openFilePath->setText( QString( fileName.c_str() ) ); -} - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.h deleted file mode 100644 index f471ddc431b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DataFilenameWidget.h +++ /dev/null @@ -1,59 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include - -#include "DataWidget.h" - - -namespace sofa::gui::qt -{ - -class DataFileNameWidget : public TDataWidget -{ - Q_OBJECT -public: - - DataFileNameWidget( - QWidget* parent, - const char* name, - core::objectmodel::Data* data): - TDataWidget(parent,name,data) {} - - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); -protected: - ///Implements how update the widgets knowing the data value. - virtual void readFromData(); - ///Implements how to update the data, knowing the widget value. - virtual void writeToData(); - - QLineEdit* openFilePath; - QPushButton* openFileButton; - -protected slots : - virtual void raiseDialog(); -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.cpp deleted file mode 100644 index c51dbb3040f..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#define SOFA_GUI_QT_DATAWIDGET_CPP - -#include "DataWidget.h" -#include "ModifyObject.h" -#include -#include -#include -#include -#include - -#include - -#define SIZE_TEXT 60 - -namespace sofa::helper -{ -template class SOFA_GUI_QT_API Factory; -} // namespace sofa::helper - -namespace sofa::gui::qt -{ - -using namespace core::objectmodel; - -DataWidget::DataWidget(QWidget* parent,const char* name, MyData* d) - : QWidget(parent /*,name */) - , baseData(d) - , dirty(false) - , counter(-1) - , m_isFilled(true) - , m_toFill(false) -{ - this->setObjectName(name); -} - -DataWidget::~DataWidget() -{ -} - -void -DataWidget::setData( MyData* d) -{ - baseData = d; - readFromData(); -} - -void -DataWidget::updateVisibility() -{ - parentWidget()->setVisible(baseData->isDisplayed()); -} - -void -DataWidget::updateDataValue() -{ - if (dirty) - { - const bool hasOwner = baseData->getOwner(); - std::string previousName; - if ( hasOwner ) previousName = baseData->getOwner()->getName(); - writeToData(); - - if (hasOwner) - { - std::string path; - const BaseNode* ownerAsNode = dynamic_cast(baseData->getOwner() ); - BaseObject* ownerAsObject = dynamic_cast(baseData->getOwner() ); - - if (ownerAsNode) - { - path = ownerAsNode->getPathName() + "." + baseData->getName(); - } - else if (ownerAsObject) - { - std::string objectPath = ownerAsObject->getName(); - sofa::core::objectmodel::BaseObject* master = ownerAsObject->getMaster(); - while (master) - { - objectPath = master->getName() + "/" + objectPath; - master = master->getMaster(); - } - const BaseNode* n = dynamic_cast(ownerAsObject->getContext()); - if (n) - { - path = n->getPathName() + std::string("/") + objectPath + std::string(".") + baseData->getName(); // TODO: compute relative path - } - else - { - path = objectPath + "." + baseData->getName(); - } - } - else - { - msg_error("DataWidget") << "updateDataValue: " << baseData->getName() << " has an owner that is neither a Node nor an Object. Something went wrong..."; - } - - const QString dataString = (path + " = " + baseData->getValueString()).c_str(); - Q_EMIT dataValueChanged(dataString); - - } - - updateVisibility(); - if(hasOwner && baseData->getOwner()->getName() != previousName) - { - Q_EMIT DataOwnerDirty(true); - } - } - - dirty = false; - counter = baseData->getCounter(); - -} - -void DataWidget::fillFromData() -{ - if (!m_isFilled) // only activate toFill if only is not already filled - { - m_toFill = true; - } - else - { - m_toFill = false; - } -} - -void -DataWidget::updateWidgetValue() -{ - if(!dirty) - { - if(m_toFill || counter != baseData->getCounter()) - { - readFromData(); - this->update(); - - if (m_toFill) // update parameters to avoid other force fill - { - m_toFill = false; - m_isFilled = true; - } - } - } -} - -void -DataWidget::setWidgetDirty(bool b) -{ - dirty = b; - Q_EMIT WidgetDirty(b); -} - -typedef sofa::helper::Factory DataWidgetFactory; - -DataWidget *DataWidget::CreateDataWidget(const DataWidget::CreatorArgument &dwarg) -{ - DataWidget *datawidget_ = nullptr; - const std::string &widgetName=dwarg.data->getWidget(); - if (widgetName.empty()) - datawidget_ = DataWidgetFactory::CreateAnyObject(dwarg); - else - datawidget_ = DataWidgetFactory::CreateObject(widgetName, dwarg); - - return datawidget_; -} - - -/*QDisplayDataInfoWidget definitions */ - -QDisplayDataInfoWidget::QDisplayDataInfoWidget(QWidget* parent, const std::string& helper, - core::objectmodel::BaseData* d, bool modifiable, const ModifyObjectFlags& modifyObjectFlags):QWidget(parent), data(d), numLines_(1) -{ - setMinimumHeight(25); - - QHBoxLayout* layout = new QHBoxLayout(this); - layout->setContentsMargins(0,0,0,0); - layout->setSpacing(0); - - std::string final_str; - formatHelperString(helper,final_str); - const std::string ownerClass=data->getOwner()->getName(); - if (modifiable) - { - QPushButton *helper_button = new QPushButton(this); - helper_button->setIcon(LinkIcon()); - helper_button->setFixedSize(QSize(16, 16)); - helper_button->setToolTip(QString(final_str.c_str())); - helper_button->setAutoDefault(false); - layout->addWidget(helper_button, 0, Qt::AlignLeft); - connect(helper_button, &QPushButton::clicked, this, &QDisplayDataInfoWidget::linkModification); - if (!ownerClass.empty()) - helper_button->setToolTip( ("Data from "+ownerClass).c_str()); - } - if(data->getParent()) - { - const std::string linkvalue = data->getParent()->getLinkPath(); - linkpath_edit = new QLineEdit(this); - linkpath_edit->setContentsMargins(2, 0, 0, 0); - linkpath_edit->setText(QString(linkvalue.c_str())); - linkpath_edit->setReadOnly(!modifiable); - layout->addWidget(linkpath_edit); - linkpath_edit->setVisible(!linkvalue.empty()); - if(modifyObjectFlags.PROPERTY_WIDGET_FLAG) - connect(linkpath_edit, &QLineEdit::textChanged, [=](){ WidgetDirty(); }); - else - connect(linkpath_edit, &QLineEdit::editingFinished, this, &QDisplayDataInfoWidget::linkEdited); - } - else - { - linkpath_edit=nullptr; - } -} - -void QDisplayDataInfoWidget::linkModification() -{ - if (linkpath_edit->isVisible() && linkpath_edit->text().isEmpty()) - linkpath_edit->setVisible(false); - else - { - linkpath_edit->setVisible(true); - //Open a dialog window to let the user select the data he wants to link - } -} -void QDisplayDataInfoWidget::linkEdited() -{ - data->setParent(linkpath_edit->text().toStdString() ); -} - -void QDisplayDataInfoWidget::formatHelperString(const std::string& helper, std::string& final_text) -{ - std::string label_text=helper; - numLines_ = 0; - while (!label_text.empty()) - { - const std::string::size_type pos = label_text.find('\n'); - std::string current_sentence; - if (pos != std::string::npos) - current_sentence = label_text.substr(0,pos+1); - else - current_sentence = label_text; - if (current_sentence.size() > SIZE_TEXT) - { - const std::size_t cut = current_sentence.size()/SIZE_TEXT; - for (std::size_t index_cut=1; index_cut<=cut; index_cut++) - { - const std::string::size_type numero_char=current_sentence.rfind(' ',SIZE_TEXT*index_cut); - current_sentence = current_sentence.insert(numero_char+1,1,'\n'); - numLines_++; - } - } - if (pos != std::string::npos) label_text = label_text.substr(pos+1); - else label_text = ""; - final_text += current_sentence; - numLines_++; - } -} - -unsigned int QDisplayDataInfoWidget::numLines(const std::string& str) -{ - std::string::size_type newline_pos; - unsigned int numlines = 1; - newline_pos = str.find('\n',0); - while( newline_pos != std::string::npos ) - { - numlines++; - newline_pos = str.find('\n',newline_pos+1); - } - return numlines; -} - - -/* QPushButtonUpdater definitions */ - -void QPushButtonUpdater::setDisplayed(bool b) -{ - - if (b) - { - this->setText(QString("Hide the values")); - } - else - { - this->setText(QString("Display the values")); - } - -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h deleted file mode 100644 index 7b068fedf58..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h +++ /dev/null @@ -1,311 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include -#include "ModifyObject.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -//If a table has higher than MAX_NUM_ELEM, its data won't be loaded at the creation of the window -//user has to click on the button update to see the content -#define MAX_NUM_ELEM 100 - - -namespace sofa::gui::qt -{ - -/** -*\brief Abstract Interface of a qwidget which allows to edit a data. -*/ -class SOFA_GUI_QT_API DataWidget : public QWidget -{ - Q_OBJECT -public: - // - // Factory related code - // - - struct CreatorArgument - { - std::string name; - core::objectmodel::BaseData* data; - QWidget* parent; - bool readOnly; - }; - - template - static T* create(T*, const CreatorArgument& arg) - { - typename T::MyData* data = dynamic_cast(arg.data); - if(!data) return nullptr; - T* instance = new T(arg.parent, arg.name.c_str(), data); - if ( !instance->createWidgets() ) - { - delete instance; - instance = nullptr; - } - if (instance) - { - instance->setDataReadOnly(arg.readOnly); - } - return instance; - } - - static DataWidget *CreateDataWidget(const DataWidget::CreatorArgument &dwarg); - - -public slots: - /// Checks that widget has been edited - /// emit DataOwnerDirty in case the name field has been modified - void updateDataValue(); - - /// First checks that the widget is not currently being edited - /// checks that the data has changed since the last time the widget - /// has read the data value. - /// ultimately read the data value. - void updateWidgetValue(); - - /// You call this slot anytime you want to specify that the widget - /// value is out of sync with the underlying data value. - void setWidgetDirty(bool b=true); - - /// slot to be called if DataWidget has not been filled at constructor and need to be filled - /// at first call. Will turn toFill to true only if isFilled == false - void fillFromData(); - -signals: - /// Emitted each time setWidgetDirty is called. You can also emit - /// it if you want to tell the widget value is out of sync with - /// the underlying data value. - void WidgetDirty(bool ); - /// Currently this signal is used to reflect the changes of the - /// component name in the sofaListview. - void DataOwnerDirty(bool ); - - void dataValueChanged(QString dataValueString ); -public: - typedef core::objectmodel::BaseData MyData; - - DataWidget(QWidget* parent,const char* name, MyData* d); - - ~DataWidget() override; - - virtual void setData( MyData* d); - - /// BaseData pointer accessor function. - inline const core::objectmodel::BaseData* getBaseData() const { return baseData; } - inline core::objectmodel::BaseData* getBaseData() { return baseData; } - - void updateVisibility(); - - inline bool isDirty() { return dirty; } - - /// return if DataWidget as been filled - bool isFilled() { return m_isFilled; } - /// method to warn if Data has not been filled at constructor. - void setFilled(bool value) { m_isFilled = value; } - - /// The implementation of this method holds the widget creation and the signal / slot - /// connections. - virtual bool createWidgets() = 0; - /// This method is called after createWidgets to configure whether the created widgets should be read-only - virtual void setDataReadOnly(bool readOnly) = 0; - /// Helper method to give a size. - virtual unsigned int sizeWidget() {return 1;} - /// Helper method for column. - virtual unsigned int numColumnWidget() {return 3;} - -protected: - /// The implementation of this method tells how the widget reads the value of the data. - virtual void readFromData() = 0; - /// The implementation of this methods needs to tell how the widget can write its value - /// in the data - virtual void writeToData() = 0; - - core::objectmodel::BaseData* baseData; - bool dirty; - int counter; - bool m_isFilled; ///< tell if DataWidget has been filled from Data true by default - bool m_toFill; ///< bool to warn action is needed to fill Data, false by default -}; - - - -/** -*\brief This class is basically the same as DataWidget, except that it -* takes a template parameter so the actual type of Data can be retrieved -* through the getData() accessor. In most cases you will need to derive -* from this class to implement the edition of your data in the GUI. -**/ -template -class TDataWidget : public DataWidget -{ - -public: - typedef sofa::core::objectmodel::Data MyTData; - - template - static RealObject* create( RealObject*, CreatorArgument& arg) - { - RealObject* obj = nullptr; - - typename RealObject::MyTData* realData = dynamic_cast< typename RealObject::MyTData* >(arg.data); - if (!realData) - { - if constexpr (std::is_constructible_v) - { - if (arg.data) - { - const void* rawPtr = arg.data->getValueVoidPtr(); - - //note that this cast is not type-safe. You need to check - //later in createWidget that the baseData is the expected - //type. You can use getValueTypeString for example - if (const T* castedPtr = static_cast(rawPtr)) - { - obj = new RealObject(arg.parent, arg.name.c_str(), arg.data, castedPtr); - } - } - } - } - else - { - if constexpr (std::is_constructible_v) - { - obj = new RealObject(arg.parent, arg.name.c_str(), realData); - } - } - - if (obj) - { - if( !obj->createWidgets() ) - { - delete obj; - obj = nullptr; - } - if (obj) - { - obj->setDataReadOnly(arg.readOnly); - } - } - return obj; - } - - TDataWidget(QWidget* parent,const char* name, core::objectmodel::BaseData* d, const T* object): - DataWidget(parent, name, d), - Tdata(nullptr) - { - SOFA_UNUSED(object); - } - - TDataWidget(QWidget* parent,const char* name, MyTData* d): - DataWidget(parent,name,d),Tdata(d) {} - - /// Accessor function. Gives you the actual data instead - /// of a BaseData pointer of it like in getBaseData(). - sofa::core::objectmodel::Data* getData() {return Tdata;} - const sofa::core::objectmodel::Data* getData() const {return Tdata;} - - using DataWidget::setData; - inline virtual void setData(MyTData* d) - { - Tdata = d; - } -protected: - MyTData* Tdata { nullptr }; -}; - - - - - -class SOFA_GUI_QT_API QPushButtonUpdater: public QPushButton -{ - Q_OBJECT -public: - - QPushButtonUpdater( const QString & text, QWidget * parent = nullptr ): QPushButton(text,parent) {}; - -public Q_SLOTS: - void setDisplayed(bool b); -}; - -//Widget used to display the name of a Data and if needed the link to another Data -class SOFA_GUI_QT_API QDisplayDataInfoWidget: public QWidget -{ - Q_OBJECT -public: - QDisplayDataInfoWidget(QWidget* parent, const std::string& helper, core::objectmodel::BaseData* d, bool modifiable, const ModifyObjectFlags& modifyObjectFlags); -public Q_SLOTS: - void linkModification(); - void linkEdited(); - unsigned int getNumLines() const { return numLines_;} - -signals: - void WidgetDirty(); - -protected: - static QIcon& LinkIcon() - { - static QIcon icon; - if(icon.isNull()) - { - std::string filename = "textures/link.png"; - sofa::helper::system::DataRepository.findFile(filename); - icon = QIcon(filename.c_str()); - } - return icon; - } - -protected: - void formatHelperString(const std::string& helper, std::string& final_text); - static unsigned int numLines(const std::string& str); - core::objectmodel::BaseData* data; - unsigned int numLines_; - QLineEdit *linkpath_edit; -}; - -typedef sofa::helper::Factory DataWidgetFactory; - -} //namespace sofa::gui::qt - -//MOC_SKIP_BEGIN -#if !defined(SOFA_BUILD_SOFA_GUI_QT) -namespace sofa::helper -{ -//delay load of the specialized Factory class. unique definition reside in the cpp file -extern template class SOFA_GUI_QT_API Factory; -} // namespace sofa::helper - -#endif -//MOC_SKIP_END diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DialogAddObject.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/DialogAddObject.ui deleted file mode 100644 index 97b4a58d5ef..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DialogAddObject.ui +++ /dev/null @@ -1,235 +0,0 @@ - - - DialogAddObject - - - - 0 - 0 - 556 - 264 - - - - - 0 - 0 - - - - Add a scene or an object - - - true - - - - - - - - Scale - - - false - - - - - - - - - - - - - - Open File - - - false - - - - - - - - - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - &OK - - - - - - true - - - true - - - - - - - &Cancel - - - - - - true - - - - - - - - - - - Initial Position - - - false - - - - - - - - - - - - - - - - - - - - Initial Rotation - - - false - - - - - - - - - - - - - - - - - - Objects - - - - - - custom - - - - - - - - - - - - - openFileButton - clicked() - DialogAddObject - fileOpen() - - - 20 - 20 - - - 20 - 20 - - - - - buttonOk - clicked() - DialogAddObject - accept() - - - 20 - 20 - - - 20 - 20 - - - - - buttonCancel - clicked() - DialogAddObject - reject() - - - 20 - 20 - - - 20 - 20 - - - - - - fileOpen() - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp deleted file mode 100644 index e09f283ef12..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -#include -#include - -namespace sofa::gui::qt -{ -using namespace sofa::core::objectmodel; -using namespace sofa::core::visual; - -helper::Creator DWClass_DisplayFlags("widget_displayFlags",true); - - - -DisplayFlagWidget::DisplayFlagWidget(QWidget* parent, const char* name, Qt::WindowFlags f ): - QTreeWidget(parent /*,name ,f*/) -{ - this->setWindowFlags(f); - this->setObjectName(name); - - //addColumn(QString::null); - setRootIsDecorated( true ); - //setTreeStepSize( 12 ); - header()->hide(); - clear(); - - - setMouseTracking(false); - - //setFocusPolicy(Qt::NoFocus); - - setFrameShadow(QFrame::Plain); - setFrameShape(QFrame::NoFrame ); - - this->setSortingEnabled(false); - //setSortColumn(-1); - QTreeWidgetItem* itemShowAll = new QTreeWidgetItem(this); - this->setTreeWidgetNodeCheckable(itemShowAll, "All"); - - QTreeWidgetItem* itemShowVisual = new QTreeWidgetItem(itemShowAll); - this->setTreeWidgetNodeCheckable(itemShowVisual, "Visual"); - - itemShowFlag[VISUALMODELS] = new QTreeWidgetItem(itemShowVisual); - this->setTreeWidgetCheckable(itemShowFlag[VISUALMODELS], "Visual Models"); - - QTreeWidgetItem* itemShowBehavior = new QTreeWidgetItem(itemShowAll); - this->setTreeWidgetNodeCheckable(itemShowBehavior, "Behavior"); - - itemShowFlag[BEHAVIORMODELS] = new QTreeWidgetItem(itemShowBehavior); - this->setTreeWidgetCheckable(itemShowFlag[BEHAVIORMODELS], "Behavior Models"); - itemShowFlag[FORCEFIELDS] = new QTreeWidgetItem(itemShowBehavior, itemShowFlag[BEHAVIORMODELS]); - this->setTreeWidgetCheckable(itemShowFlag[FORCEFIELDS], "Force Fields"); - itemShowFlag[INTERACTIONFORCEFIELDS] = new QTreeWidgetItem(itemShowBehavior, itemShowFlag[FORCEFIELDS]); - this->setTreeWidgetCheckable(itemShowFlag[INTERACTIONFORCEFIELDS], "Interactions"); - - QTreeWidgetItem* itemShowCollision = new QTreeWidgetItem(itemShowAll, itemShowBehavior); - this->setTreeWidgetNodeCheckable(itemShowCollision, "Collision"); - itemShowFlag[COLLISIONMODELS] = new QTreeWidgetItem(itemShowCollision); - this->setTreeWidgetCheckable(itemShowFlag[COLLISIONMODELS], "Collision Models"); - itemShowFlag[BOUNDINGCOLLISIONMODELS] = new QTreeWidgetItem(itemShowCollision, itemShowFlag[COLLISIONMODELS]); - this->setTreeWidgetCheckable(itemShowFlag[BOUNDINGCOLLISIONMODELS], "Bounding Collision Models"); - itemShowFlag[DETECTIONOUTPUTS] = new QTreeWidgetItem(itemShowCollision, itemShowFlag[COLLISIONMODELS]); - this->setTreeWidgetCheckable(itemShowFlag[DETECTIONOUTPUTS], "Detection Outputs"); - QTreeWidgetItem* itemShowMapping = new QTreeWidgetItem(itemShowAll, itemShowCollision); - this->setTreeWidgetNodeCheckable(itemShowMapping, "Mapping"); - itemShowFlag[MAPPINGS] = new QTreeWidgetItem(itemShowMapping); - this->setTreeWidgetCheckable(itemShowFlag[MAPPINGS], "Visual Mappings"); - itemShowFlag[MECHANICALMAPPINGS] = new QTreeWidgetItem(itemShowMapping, itemShowFlag[MAPPINGS]); - this->setTreeWidgetCheckable(itemShowFlag[MECHANICALMAPPINGS], "Mechanical Mappings"); - QTreeWidgetItem* itemShowOptions = new QTreeWidgetItem(this, itemShowAll); - this->setTreeWidgetNodeCheckable(itemShowOptions, "Options"); - itemShowFlag[RENDERING] = new QTreeWidgetItem(itemShowOptions); - this->setTreeWidgetCheckable(itemShowFlag[RENDERING], "Advanced Rendering"); - itemShowFlag[WIREFRAME] = new QTreeWidgetItem(itemShowOptions); - this->setTreeWidgetCheckable(itemShowFlag[WIREFRAME], "Wire Frame"); - itemShowFlag[NORMALS] = new QTreeWidgetItem(itemShowOptions, itemShowFlag[WIREFRAME]); - this->setTreeWidgetCheckable(itemShowFlag[NORMALS], "Normals"); - this->addTopLevelItem(itemShowAll); - itemShowAll->setExpanded(true); - itemShowAll->addChild(itemShowVisual); - itemShowVisual->addChild(itemShowFlag[VISUALMODELS]); - itemShowAll->addChild(itemShowBehavior); - itemShowBehavior->addChild(itemShowFlag[BEHAVIORMODELS]); - itemShowBehavior->addChild(itemShowFlag[FORCEFIELDS]); - itemShowBehavior->addChild(itemShowFlag[INTERACTIONFORCEFIELDS]); - itemShowAll->addChild(itemShowCollision); - itemShowCollision->addChild(itemShowFlag[COLLISIONMODELS]); - itemShowCollision->addChild(itemShowFlag[BOUNDINGCOLLISIONMODELS]); - itemShowCollision->addChild(itemShowFlag[DETECTIONOUTPUTS]); - itemShowAll->addChild(itemShowMapping); - itemShowMapping->addChild(itemShowFlag[MAPPINGS]); - itemShowMapping->addChild(itemShowFlag[MECHANICALMAPPINGS]); - - this->addTopLevelItem(itemShowOptions); - itemShowOptions->setExpanded(true); - itemShowOptions->addChild(itemShowFlag[RENDERING]); - itemShowOptions->addChild(itemShowFlag[WIREFRAME]); - itemShowOptions->addChild(itemShowFlag[NORMALS]); - for (int i=0; isetText(0, name); - w->setExpanded(true); - w->setFlags(w->flags() | Qt::ItemIsUserCheckable); - -} - -void DisplayFlagWidget::setTreeWidgetNodeCheckable(QTreeWidgetItem* w, const char* name) -{ - w->setText(0, name); - w->setExpanded(true); - w->setFlags(w->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate); - -} - -void DisplayFlagWidget::findChildren(QTreeWidgetItem *item, std::vector &children) -{ - for(int i=0; ichildCount() ; i++) - { - QTreeWidgetItem * child = (QTreeWidgetItem * )item->child(i); - children.push_back(child); - findChildren(child,children); - } -} - -void DisplayFlagWidget::mouseReleaseEvent ( QMouseEvent * e ) -{ - //if ( QTreeWidgetItem *item = dynamic_cast(itemAt(contentsToViewport(e->pos()))) ) - QTreeWidgetItem *item = this->itemAt(e->pos()); - - if ( e->button() == Qt::LeftButton && item ) - { - const bool value = !(item->checkState(0) == Qt::Checked); - item->setCheckState(0, ( (value) ? Qt::Checked : Qt::Unchecked) ); - - emit clicked(); - } -} - -bool DisplayFlagsDataWidget::createWidgets() -{ - flags = new DisplayFlagWidget(this); - QVBoxLayout* layout = new QVBoxLayout(this); - layout->addWidget(flags); - connect(flags, &DisplayFlagWidget::clicked, [=](){ setWidgetDirty(true); }); - setMinimumSize(QSize(50,400)); - layout->setContentsMargins(2,2,4,4); - return true; -} - -void DisplayFlagsDataWidget::setDataReadOnly(bool readOnly) -{ - flags->setEnabled(!readOnly); -} - -void DisplayFlagsDataWidget::readFromData() -{ - const DisplayFlags& displayFlags = this->getData()->getValue(); - if (isRoot) - flags->setFlag(DisplayFlagWidget::VISUALMODELS, sofa::core::visual::merge_tristate(true,displayFlags.getShowVisualModels())); - else - flags->setFlag(DisplayFlagWidget::VISUALMODELS, displayFlags.getShowVisualModels()); - flags->setFlag(DisplayFlagWidget::BEHAVIORMODELS, displayFlags.getShowBehaviorModels()); - flags->setFlag(DisplayFlagWidget::COLLISIONMODELS, displayFlags.getShowCollisionModels()); - flags->setFlag(DisplayFlagWidget::BOUNDINGCOLLISIONMODELS, displayFlags.getShowBoundingCollisionModels()); - flags->setFlag(DisplayFlagWidget::DETECTIONOUTPUTS, displayFlags.getShowDetectionOutputs()); - flags->setFlag(DisplayFlagWidget::MAPPINGS, displayFlags.getShowMappings()); - flags->setFlag(DisplayFlagWidget::MECHANICALMAPPINGS, displayFlags.getShowMechanicalMappings()); - flags->setFlag(DisplayFlagWidget::FORCEFIELDS, displayFlags.getShowForceFields()); - flags->setFlag(DisplayFlagWidget::INTERACTIONFORCEFIELDS, displayFlags.getShowInteractionForceFields()); - flags->setFlag(DisplayFlagWidget::RENDERING, displayFlags.getShowAdvancedRendering()); - flags->setFlag(DisplayFlagWidget::WIREFRAME, displayFlags.getShowWireFrame()); - flags->setFlag(DisplayFlagWidget::NORMALS, displayFlags.getShowNormals()); -} - -void DisplayFlagsDataWidget::writeToData() -{ - DisplayFlags& displayFlags = *this->getData()->beginEdit(); - - displayFlags.setShowVisualModels(flags->getFlag(DisplayFlagWidget::VISUALMODELS)); - displayFlags.setShowBehaviorModels(flags->getFlag(DisplayFlagWidget::BEHAVIORMODELS)); - displayFlags.setShowCollisionModels(flags->getFlag(DisplayFlagWidget::COLLISIONMODELS)); - displayFlags.setShowBoundingCollisionModels(flags->getFlag(DisplayFlagWidget::BOUNDINGCOLLISIONMODELS)); - displayFlags.setShowDetectionOutputs(flags->getFlag(DisplayFlagWidget::DETECTIONOUTPUTS)); - displayFlags.setShowMappings(flags->getFlag(DisplayFlagWidget::MAPPINGS)); - displayFlags.setShowMechanicalMappings(flags->getFlag(DisplayFlagWidget::MECHANICALMAPPINGS)); - displayFlags.setShowForceFields(flags->getFlag(DisplayFlagWidget::FORCEFIELDS)); - displayFlags.setShowInteractionForceFields(flags->getFlag(DisplayFlagWidget::INTERACTIONFORCEFIELDS)); - displayFlags.setShowAdvancedRendering(flags->getFlag(DisplayFlagWidget::RENDERING)); - displayFlags.setShowWireFrame(flags->getFlag(DisplayFlagWidget::WIREFRAME)); - displayFlags.setShowNormals(flags->getFlag(DisplayFlagWidget::NORMALS)); - this->getData()->endEdit(); - -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.h deleted file mode 100644 index 0f007836d8b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.h +++ /dev/null @@ -1,112 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - - -class SOFA_GUI_QT_API DisplayFlagWidget : public QTreeWidget -{ - Q_OBJECT; -public: - - enum VISUAL_FLAG - { - VISUALMODELS, - BEHAVIORMODELS, - COLLISIONMODELS, - BOUNDINGCOLLISIONMODELS, - DETECTIONOUTPUTS, - MAPPINGS,MECHANICALMAPPINGS, - FORCEFIELDS, - INTERACTIONFORCEFIELDS, - RENDERING, - WIREFRAME, - NORMALS, - ALLFLAGS - }; - - - DisplayFlagWidget(QWidget* parent, const char* name= nullptr, Qt::WindowFlags f = Qt::WindowType::Widget ); - - bool getFlag(int idx) {return itemShowFlag[idx]->checkState(0) == Qt::Checked;} - void setFlag(int idx, bool value) - { - itemShowFlag[idx]->setCheckState(0, (value) ? Qt::Checked : Qt::Unchecked) ; - } - -Q_SIGNALS: - void change(int,bool); - void clicked(); - - -protected: - void setTreeWidgetNodeCheckable(QTreeWidgetItem* w, const char* name); - void setTreeWidgetCheckable(QTreeWidgetItem* w, const char* name); - - void mouseReleaseEvent ( QMouseEvent * e ) override; - - void findChildren(QTreeWidgetItem *, std::vector &children); - - - QTreeWidgetItem* itemShowFlag[ALLFLAGS]; - std::map< QTreeWidgetItem*, int > mapFlag; -}; - - -class SOFA_GUI_QT_API DisplayFlagsDataWidget : public TDataWidget< sofa::core::visual::DisplayFlags > -{ - Q_OBJECT; -public: - typedef sofa::core::visual::DisplayFlags DisplayFlags; - DisplayFlagsDataWidget(QWidget* parent, const char* name, core::objectmodel::Data* data, bool root = false) - :TDataWidget(parent,name,data), isRoot(root) - { - } - - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - -protected: - - virtual void readFromData(); - virtual void writeToData(); - virtual unsigned int sizeWidget() {return 8;} - virtual unsigned int numColumnWidget() {return 1;} - - DisplayFlagWidget* flags; - bool isRoot; - - -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index.html b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index.html deleted file mode 100644 index cb83d966dcd..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - - - - - - - -

The Graphic User -Interface in SOFA

- -

I) An overview of the GUI
-II) Structure
-III) Viewers
-IV) QtOgreViewer
-

-
-

-
- -


-
-

-
    -
  1. An Overview of the GUI
    -
    -
    The main - program is divided in two main parts, a rendering window and a control - panel. A slider between them sets their - dimension.

    -
  2. -
-
    -

    -
    -
    -

    - -

    Common Interactions:

    -
      -
    1. ANIM: launch the Simulation. - The text field, DTsets the step of time used during the - simulation.

      -
    2. -
    3. STEP: the simulation will - compute its state at the time: t+DT.

      -
    4. -
    5. Reset Scene: reset the - Simulation to the initial time, t=0.

      -
    6. -
    7. Reset View: set your camera at - initial configuration found in a view file, or default - configuration.

      -
    8. -
    9. Save View: keep in memory the - position and orientation of the camera, for the next time you will load - the scene.

      -
    10. -
    11. Save Screenshot: take a picture - of the current scene.

      -
    12. -
    13. Direct interaction with the scene is - possible. To do so, maintain SHIFT button pressed and click on a - collision model present in the scene; A “Pick Interactor” will be - created, and attached to the picked collision model, if any, with a - spring.

      -

      If - you release the mouse button first, the spring is removed.

      -

      If - you release the SHIFT button first, the spring is fixed and exists - until you pick another point in the scene.

      -
    14. -
    15. Several tabs give more information - about the current scene:
      - This images were taken for the scene shown above.

      -

      - - -
      -

      -
      -
      -
      -
      -

      -

      -


      -
      -
      - - depending on the viewer, you can control what is displayed, and the - way it is.
      - - statistical outputs during the simulation (position and velocity for - each elements, time passed at each branch of the graph, gnuplot files) -
      - - the graph of the scene, with all the nodes. You can export this graph - into a nice png file.
      - - the last tab, “
      Viewergives the name and information about - the possibilities of the current viewer, and the shortcuts.
      -
      - Double clicking on a node allows you to modify several values and - change dynamically the simulation (here, the TetrahedronFEMForceField - node). In some cases, you need to press the update button - to apply the changes.

      -

      -
      -

      -
    16. -
    -
-
    -
  1. Structure
    -
    The main interface uses a Qt - environment (Qt3.3 for Linux and Qt4 for Windows). The Main window, - providing all the interactions possible with the simulation,was created - using QtDesigner. The RealGUI contains the viewer which can be selected - directly in the main window. The possible choices depends on the - configuration file, sofa-default.cfg.

    -
      -

      -
      - The RealGUI gets a pointer to the root of the scene graph, and controls - the application by calling class - sofa::simulation::tree:Simulation.

      -

      The RealGUI uses an internal timer to repeatedly call - method sofa::simulation::tree:Simulation::animate(GNode* root, double - dt) and then update the viewer.

      -


      - To select the - viewers:

      -
    -
      -

      sofa-default.cfg located in - your Sofa main directory allows to define what kind of viewer you are - willing to have.
      - By commenting (adding a“#” in front of the line) or uncommenting - (removing the “#”) lines, you can allow multiple kind of viewer.
      - For example, if you want to have the choice to render the scene with - QtGLViewer and QtOgreViewer, just modify sofa-default.cfg as below:
      -
      - # DEFINES += SOFA_GUI_QT
      - DEFINES += SOFA_GUI_QTOGREVIEWER
      - DEFINES += SOFA_GUI_QGLVIEWER

      -
      -
      Then, in the main window, you select the kind of viewer you - want. Qt will appear in gray, whereas QGLViewer and Ogre will be - available.
      - Warning, you must reload the scene when this change is made!

      -
      -
    -
  2. -
  3. Viewers

    -
  4. -
-
    -

    -
    -
    - The Viewers available now are:

    -
      -
    1. QtViewer: uses openGL, derives a - QGLWidget in order to be embedded within Qt. This class will probably - not be maintained. Use QtGLViewer instead.

      -
    2. -
    3. QtGLViewer: uses the library - QGLViewer. Provides lots of functions to navigate through the scene.
      - More information at QGLViewer - Website.

      -
    4. -
    5. QtOgreViewer: Embed Ogre within a - Qwidget. Allows to get great visuals, through an intensive use of - shaders, materials.
      - Shadows are provided, but all the controls (show the mechanical - objects, force fields...) are disabled.
      - Warning: Ogre is not provided by Sofa, you have to previously install - Ogre on your computer.
      - The support works with Windows, Linux.
      - - For Windows, the easiest way to proceed is to download and install - the SDK.
      - - For Linux, you have to compile from the source. If Ogre's library - aren't installed in the default directory “
      /usr/local/lib/Ogre” - then, you have to set the - correct path in “YourSofaDirectory/share/config/plugins_unix.cfg
      - To get it: Ogre - Website

      -
    6. -
    -
-
    -
  1. QtOgreViewer

    -

    To - use this viewer, you must have Ogre installed on your computer.
    - The configuration files are located in: “
    YourSofaDirectory/share/config/. plugins.cfgdescribes the plugins used by Ogre for - Windows, and “plugins_unix.cfgfor... Linux.
    - By creating a .scene file with the same name as the simulation, you can - provide additional models, lights, visuals to the simulation( see Ogre - documentation for mode details ). This won't interact with Sofa, but - allows you to get a better render.

    -

    Additional textures, materials, - shaders... in Ogre, have to be put in “ - YourSofaDirectory/share/textures” or “ - YourSofaDirectory/share/materials” or - “YourSofaDirectory/share/shaders” ... They are loaded at the - start-up of the viewer.

    -

    -
    -
    -

    -
    -

    -
  2. -
- -


-

- -


-

- -


-

- -


-

- -


-

- -


-

- -


-

- -


-

- - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI.png b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI.png deleted file mode 100644 index ad4d140c97d691db53939ecfc92bd86de967fe02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8483 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 Y85OcVyhZ;U+cki)g2wZTXXfwz4N35EApigX diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI_caption0.png b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/GUI_caption0.png deleted file mode 100644 index 940789a539b370a462ebd632a567a6ab11c7a6b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69466 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μ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 usCE{;zKB=(+w-i+9&*_?_h^9~ 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⋘}lJCrJ?o(x?4n$|^7w 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 z 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%0Af!}UG>bagmbG~u~B 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 diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_graph.png b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_graph.png deleted file mode 100644 index 7978131a0fdb6ed088b27107862ee4e8b4be7405..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7561 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 h5|vt@ir0Rm=I)0xRca2={{{XhHthfa diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_show.png b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Tab_show.png deleted file mode 100644 index 3a127dff5c2adec33b8fe2526111d23ef2fc6901..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9293 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
  • !v{aq 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 z zn^k<*5qQZ;z@=H+N=vG2v-S-|XG^EJ7Eijb^X0<;{o z$^{A0lk`#oPvIWd8It;26?N6|e|5i5zGZWTYL$zO{;n=M{<;dN^(s<+fA83L0W$DIq z==gapn?Ex7vz?3_CO)Dc27!z_Uf@Q@5^{yal0-Hny{8NRO8{<3ebKg;qJW73$>7H? zT;;<6yhFDZ(h`)L&?k0Y=B#y_C{xXp&#kbZ;?kMhA`#^pPgEgI`7l1q{oh&S6g+LJ zq^;v0UY`tsDP}mN&!%U9`sG&bAzDarie3xL#SWl zG9)ClWG+$UxMe(s8o(g^sl|37?N|!J>U+hv_{bo0BkHWy;U4Fpdbeoi z<@z_o429YJWzJUBBvkAtb84`ND$`FurTibHF@f6~VaD{|J?cDRO*H$+{yIgImpZht zYDLh0D0$OBs7_QHLudQ{STyKAqcedbKeA_{o5B}wN(v}O_17AMQ~OK6^5Az+Qm{u0 zx_kU~#Z>�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
    Collision Elements present:
      "); - std::map< std::string, int >::const_iterator it; - - for (it=mapElement.begin(); it!=mapElement.end(); ++it) - { - if (it->second) - { - char buf[100]; - sprintf ( buf, "
    • %s: %d
    • ", it->first.c_str(), it->second ); - textStats += buf; - } - } - textStats += "

    "; - statsLabel->setText( textStats.c_str()); - statsLabel->update(); -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.h deleted file mode 100644 index 7030d999841..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.h +++ /dev/null @@ -1,66 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace sofa::core -{ - class CollisionModel; -} // namespace sofa::core - -namespace sofa::core::objectmodel -{ - class Base; -} // namespace sofa::core::objectmodel - -namespace sofa::simulation -{ - class Node; -} // namespace sofa::core - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QSofaStatWidget : public QWidget -{ - Q_OBJECT -public: - QSofaStatWidget(QWidget* parent); - void CreateStats(sofa::simulation::Node* root); -protected: - QLabel* statsLabel; - QTreeWidget* statsCounter; - void addSummary(); - void addCollisionModelsStat(const sofa::type::vector< sofa::core::CollisionModel* >& v); - std::vector > items_stats; - -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTableDataContainer.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QTableDataContainer.h deleted file mode 100644 index cfb2fe62159..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTableDataContainer.h +++ /dev/null @@ -1,736 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "SimpleDataWidget.h" -#include "StructDataWidget.h" - -#include "QTableUpdater.h" -#include - -namespace sofa::gui::qt -{ - -enum -{ - TYPE_SINGLE = 0, - TYPE_VECTOR = 1, - TYPE_STRUCT = 2, -}; - -template -class flat_data_trait; - -template -class default_flat_data_trait : public flat_data_trait< T, ( (struct_data_trait::NVAR >1 ) ? TYPE_STRUCT : ( (vector_data_trait::NDIM > 0) ? TYPE_VECTOR : TYPE_SINGLE ) ) > {}; - - - -template inline std::string toString(const T& v) -{ - std::ostringstream o; - o << v; - return o.str(); -} - -inline std::string toString(const std::string& s) -{ - return s; -} - -template inline void fromString(const std::string& s, T& v) -{ - std::istringstream i(s); - i >> v; -} - -inline void fromString(const std::string& s, std::string& v) -{ - v = s; -} - -template -class flat_data_trait -{ -public: - enum { is_struct = 0 }; - enum { is_vector = 0 }; - enum { is_single = 1 }; - typedef T data_type; - typedef T value_type; - static int size() { return 1; } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return NULL; - } - static const value_type* get(const data_type& d, int /*i*/ = 0) { return &d; } - static void set(const value_type& v, data_type& d, int /*i*/ = 0) { d = v; } - static void setS(const std::string& v, data_type& d, int /*i*/ = 0) - { - fromString(v, d); - } -}; - -template::NVAR> -class flat_struct_data_trait -{ -public: - enum { is_struct = 1 }; - enum { is_vector = 0 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR > 1) ? 1 : 0) }; - typedef T data_type; - typedef std::string value_type; - typedef struct_data_trait shelper; - typedef struct_data_trait_var vhelper; - typedef typename vhelper::value_type vtype; - typedef default_flat_data_trait vtrait; - typedef typename vtrait::value_type iotype; - typedef flat_struct_data_trait prev; - static int size() { return prev::size() + vtrait::size(); } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& d, int i = 0) - { - int s = prev::size(); - if (i < s) - return prev::header(d, i); - else - { - const char* h1 = vhelper::shortname(); - const char* h2 = vtrait::header(*vhelper::get(d), i-s); - if (h2 == NULL) return h1; - else if (h1 == NULL) return h2; - else - { - static std::string t; - t = h1; - t += " "; - t += h2; - return t.c_str(); - } - } - } - static value_type* get(const data_type& d, int i = 0) - { - int s = prev::size(); - if (i < s) - return prev::get(d, i); - else - { - static std::string t; - t = toString(*vtrait::get(*vhelper::get(d), i-s)); - return &t; - } - } - static void setS(const std::string& v, data_type& d, int i = 0) - { - int s = prev::size(); - if (i < s) - prev::setS(v, d, i); - else - { - vtype var = *vhelper::get(d); - vtrait::setS(v, var,i-s); - vhelper::set(var, d); - } - } - static void set(const value_type& v, data_type& d, int i = 0) - { - setS(v, d, i); - } -}; - -template -class flat_struct_data_trait -{ -public: - enum { is_struct = 1 }; - enum { is_vector = 0 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR > 1) ? 1 : 0) }; - typedef T data_type; - typedef std::string value_type; - typedef struct_data_trait shelper; - static int size() { return 0; } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return NULL; - } - static value_type* get(const data_type& /*d*/, int /*i*/ = 0) - { - return NULL; - } - static void setS(const std::string& /*v*/, data_type& /*d*/, int /*i*/ = 0) - { - } - static void set(const value_type& /*v*/, data_type& /*d*/, int /*i*/ = 0) - { - } -}; - -template -class flat_data_trait : public flat_struct_data_trait -{ -}; - -template -class flat_vector_data_trait -{ -public: - enum { is_struct = 0 }; - enum { is_vector = 1 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR == 1 && vector_data_trait::NDIM >= 1) ? 1 : 0) }; - typedef T data_type; - typedef vector_data_trait vhelper; - typedef typename vhelper::value_type vtype; - typedef default_flat_data_trait vtrait; - typedef typename vtrait::value_type value_type; - static int size() { return vhelper::SIZE * vtrait::size(); } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& d, int i = 0) - { - int s = vtrait::size(); - int j = i / s; - i = i % s; - const char* h1 = vhelper::header(d, j); - const char* h2 = vtrait::header(*vhelper::get(d, j), i); - if (h2 == NULL) return h1; - else if (h1 == NULL) return h2; - else - { - static std::string t; - t = h1; - t += " "; - t += h2; - return t.c_str(); - } - } - static const value_type* get(const data_type& d, int i = 0) - { - int s = vtrait::size(); - int j = i / s; - i = i % s; - return vtrait::get(*vhelper::get(d, j), i); - } - static void set(const value_type& v, data_type& d, int i = 0) - { - int s = vtrait::size(); - int j = i / s; - i = i % s; - vtype t = *vhelper::get(d, j); - vtrait::set(v, t, i); - vhelper::set(t, d, j); - } - static void setS(const std::string& v, data_type& d, int i = 0) - { - int s = vtrait::size(); - int j = i / s; - i = i % s; - vtype t = *vhelper::get(d, j); - vtrait::setS(v, t, i); - vhelper::set(t, d, j); - } -}; - -template -class flat_data_trait : public flat_vector_data_trait -{ -}; - -enum -{ - TABLE_NORMAL = 0, - TABLE_HORIZONTAL = 1 << 0, - TABLE_FIXEDSIZE = 1 << 1, -}; - -template -class table_data_widget_container -{ -public: - typedef T data_type; - typedef vector_data_trait rhelper; - typedef typename rhelper::value_type row_type; - //typedef vector_data_trait vhelper; - typedef default_flat_data_trait vhelper; - typedef typename vhelper::value_type value_type; - typedef QVBoxLayout Layout; - - QSpinBox* wSize; - QTableUpdater* wTable; - QPushButtonUpdater* wDisplay; - DataWidget * widget; - Layout* container_layout; - - int rows; - int cols; - - table_data_widget_container() : wSize(NULL), wTable(NULL), wDisplay(NULL), widget(NULL), container_layout(NULL) {} - - - bool createLayout( DataWidget* parent ) - { - if( parent->layout() != NULL || container_layout != NULL) return false; - container_layout = new Layout(parent); - return true; - } - - bool createLayout( QLayout* layout) - { - if ( container_layout != NULL ) return false; - container_layout = new Layout(layout); - return true; - } - - - void setRowHeader(int r, const std::string& s) - { - if (FLAGS & TABLE_HORIZONTAL) - wTable->horizontalHeader()->setLabel(r, QString(s.c_str())); - else - wTable->verticalHeader()->setLabel(r, QString(s.c_str())); - } - void setColHeader(int c, const std::string& s) - { - if (FLAGS & TABLE_HORIZONTAL) - wTable->verticalHeader()->setLabel(c, QString(s.c_str())); - else - wTable->horizontalHeader()->setLabel(c, QString(s.c_str())); - } - void setCellText(int r, int c, const std::string& s) - { - if (FLAGS & TABLE_HORIZONTAL) - wTable->setText(c, r, QString(s.c_str())); - else - wTable->setText(r, c, QString(s.c_str())); - } - std::string getCellText(int r, int c) - { - QString text; - if (FLAGS & TABLE_HORIZONTAL) - text=wTable->text(c, r); - else - text=wTable->text(r, c); - if (!text.isNull()) - return std::string(text.ascii()); - else - return std::string(""); - } - template - void setCell(int r, int c, const V& v) - { - std::ostringstream o; - o << v; - setCellText(r,c, o.str()); - } - void setCell(int r, int c, const std::string& s) - { - setCellText(r, c, s); - } - template - void getCell(int r, int c, V& v) - { - std::istringstream i(getCellText(r,c)); - i >> v; - } - void getCell(int r, int c, const std::string& s) - { - s = getCellText(r,c); - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool readOnly) - { - rows = 0; - int dataRows = rhelper::size(d); - - wSize = new QSpinBox(0, INT_MAX, 1, parent); - wDisplay = new QPushButtonUpdater( QString("Display the values"), parent); - - if (dataRows > 0) - cols = vhelper::size(*rhelper::get(d,0)); - else - cols = vhelper::size(row_type()); - - if (FLAGS & TABLE_HORIZONTAL) - wTable = new QTableUpdater(cols, dataRows, parent); - else - wTable = new QTableUpdater(dataRows, cols, parent); - - widget=parent; - - - - - wDisplay->setToggleButton(true); - wDisplay->setOn(dataRows < MAX_NUM_ELEM && dataRows != 0 ); - wDisplay->setAutoDefault(false); - - wSize->setValue(dataRows); - - if (isDisplayed()) - { - processTableModifications(d); - fillTable(d); - rows = dataRows; - } - - - wTable->setDisplayed(isDisplayed()); - - - - if (readOnly) - { - wSize->setEnabled(false); - wTable->setEnabled(false); - } - else - { - if (!(FLAGS & TABLE_FIXEDSIZE)) - { - parent->connect(wSize, SIGNAL( valueChanged(int) ), parent, SLOT( setWidgetDirty() )); - //_widget->connect(wSize, SIGNAL( valueChanged(int) ), _widget, SLOT(updateDataValue()) ); - - - if( FLAGS & TABLE_HORIZONTAL) - parent->connect(wSize, SIGNAL( valueChanged(int) ), wTable, SLOT(resizeTableH(int) ) ); - else - parent->connect(wSize, SIGNAL( valueChanged(int) ), wTable, SLOT(resizeTableV(int) ) ); - } - else - { - wSize->setEnabled(false); - } - parent->connect(wTable, SIGNAL( valueChanged(int,int) ), parent, SLOT(setWidgetDirty()) ); - } - parent->connect(wDisplay, SIGNAL( toggled(bool) ), wTable, SLOT(setDisplayed(bool))); - parent->connect(wDisplay, SIGNAL( toggled(bool) ), wDisplay, SLOT(setDisplayed(bool))); - parent->connect(wDisplay, SIGNAL( toggled(bool) ), parent, SLOT( updateWidgetValue() )); - return true; - } - - - void setReadOnly(bool readOnly) - { - wSize->setEnabled(!readOnly); - wTable->setEnabled(!readOnly); - } - - bool isDisplayed() - { - return (wDisplay->isOn()); - } - - - void readFromData(const data_type& d) - { - if (isDisplayed()) - { - processTableModifications(d); - fillTable(d); - } - } - void writeToData(data_type& d) - { - rows = wSize->value(); - if (!(FLAGS & TABLE_FIXEDSIZE)) - { - int oldrows = rhelper::size(d); - if( rows != oldrows) - { - rhelper::resize(rows,d); - } - int newrows = rhelper::size(d); - if( rows != newrows) - { - wSize->setValue(newrows); - rows = newrows; - if (FLAGS & TABLE_HORIZONTAL) - wTable->setNumCols(newrows); - else - wTable->setNumRows(newrows); - } - } - processTableModifications(d); - - if (isDisplayed()) - { - for (int y=0; ynumCols(); - else - currentTableNumRows=wTable->numRows(); - - int rows = wSize->value(); - - - for (int x=0; x 0) ? vhelper::header(*rhelper::get(d,0),x) : vhelper::header(row_type(),x); - if (h && *h) - setColHeader(x,h); - else - { - std::ostringstream o; - o << x; - setColHeader(x,o.str()); - } - } - for (int y=0; ysetNumCols(rows); - else - wTable->setNumRows(rows); - - for (int y=currentTableNumRows; ynumCols() > dsize ? dsize : wTable->numCols(); - else - currentNum=wTable->numRows() > dsize ? dsize : wTable->numRows(); - - for (int y=0; yadd(wSize); - container_layout->add(wTable); - container_layout->add(wDisplay); - } - -}; - - -//////////////////////////////////////////////////////////////// -/// variable-sized vectors support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < std::vector > -{ -public: - typedef std::vector data_type; - typedef T value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return NULL; - } - static const value_type* get(const data_type& d, int i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : NULL; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( int s, data_type& d) - { - d.resize(s); - } -}; - - - - -template -class vector_data_trait < sofa::type::vector > : public vector_data_trait< std::vector > -{ -}; - - -// template -// class vector_data_trait < sofa::component::topology::PointData > //: public vector_data_trait < sofa::type::vector > -// { -// public: -// typedef sofa::component::topology::PointData data_type; -// typedef T value_type; -// enum { NDIM = 1 }; -// -// static int size(const data_type& d) { return d.getValue().size(); } -// static const char* header(const data_type& /*d*/, int /*i*/ = 0) -// { -// return NULL; -// } -// static const value_type* get(const data_type& d, int i = 0) -// { -// return ((unsigned)i < (unsigned)size(d.getValue())) ? &(d.getValue()[i]) : NULL; -// } -// static void set( const value_type& v, data_type& d, int i = 0) -// { -// if ((unsigned)i < (unsigned)size(d.getValue())) -// { -// sofa::type::vector& d_data = *(d.beginEdit()); -// d_data[i] = v; -// d.endEdit(); -// } -// } -// static void resize( int s, data_type& d) -// { -// sofa::type::vector& d_data = *(d.beginEdit()); -// d_data.resize(s); -// d.endEdit(); -// } -// }; - - -//////////////////////////////////////////////////////////////// -/// PointSubset support -//////////////////////////////////////////////////////////////// - -template<> -class vector_data_trait < sofa::component::topology::PointSubset > -{ -public: - typedef sofa::component::topology::PointSubset data_type; - typedef unsigned int value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return NULL; - } - static const value_type* get(const data_type& d, int i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : NULL; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( int s, data_type& d) - { - d.resize(s); - } -}; - -//////////////////////////////////////////////////////////////// -/// std::map from strings support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < std::map > -{ -public: - typedef std::map data_type; - typedef T value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& d, int i = 0) - { - typename data_type::const_iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) return it->first.c_str(); - else return NULL; - } - static const value_type* get(const data_type& d, int i = 0) - { - typename data_type::const_iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) return &(it->second); - else return NULL; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - typename data_type::iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) it->second = v; - } - static void resize( int /*s*/, data_type& /*d*/) - { - //d.resize(s); - } -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTableUpdater.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QTableUpdater.h deleted file mode 100644 index 608f4b7a22d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTableUpdater.h +++ /dev/null @@ -1,80 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include - - -#include -#include - - - -namespace sofa::gui::qt -{ - - -class QTableUpdater : virtual public QTable -{ - Q_OBJECT -public: - QTableUpdater ( int numRows, int numCols, QWidget * parent = 0, const char * name = 0 ): - QTable(numRows, numCols, parent, name) - {}; -public slots: - void setDisplayed(bool b) {this->setShown(b);} - void resizeTableV( int number ) - { - QSpinBox *spinBox = (QSpinBox *) sender(); - QString header; - if( spinBox == NULL) - { - return; - } - if (number != numRows()) - { - setNumRows(number); - } - } - - void resizeTableH( int number ) - { - QSpinBox *spinBox = (QSpinBox *) sender(); - QString header; - if( spinBox == NULL) - { - return; - } - if (number != numCols()) - { - setNumCols(number); - - } - } - -}; - -} -} -} - -#endif diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.cpp deleted file mode 100644 index da863e35ab2..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QTabulationModifyObject.h" - -#include "QDisplayDataWidget.h" -#include "QDisplayLinkWidget.h" - -#include "ModifyObject.h" -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -QTabulationModifyObject::QTabulationModifyObject(QWidget* parent, - core::objectmodel::Base *o, QTreeWidgetItem* i, - unsigned int idx): - QWidget(parent), object(o), item(i), index(idx), size(0), dirty(false), pixelSize(0), pixelMaxSize(600) -{ - const int screenHeight = QGuiApplication::primaryScreen()->availableGeometry().height(); - - QVBoxLayout* vbox = new QVBoxLayout(); - vbox->setObjectName("tabVisualizationLayout"); - vbox->setContentsMargins(0, 0, 0, 0); - vbox->setSpacing(0); - - this->setLayout(vbox); - - //find correct maxPixelSize according to the current screen resolution - pixelMaxSize = screenHeight - 300; -} - -void QTabulationModifyObject::addData(sofa::core::objectmodel::BaseData *data, const ModifyObjectFlags& flags) -{ - - if ( (!data->isDisplayed()) && flags.HIDE_FLAG ) - { - return; - } - - data->setDisplayed(true); - - const std::string name=data->getName(); - QDisplayDataWidget* displaydatawidget = new QDisplayDataWidget(this,data,flags); - this->layout()->addWidget(displaydatawidget); - - size += displaydatawidget->getNumWidgets(); - pixelSize += displaydatawidget->sizeHint().height(); - displaydatawidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - connect(displaydatawidget, SIGNAL( WidgetDirty(bool) ), this, SLOT( setTabDirty(bool) ) ); - connect(this, SIGNAL(UpdateDatas()), displaydatawidget, SLOT( UpdateData())); - connect(this, SIGNAL(UpdateDataWidgets()), displaydatawidget, SLOT( UpdateWidgets())); - connect(displaydatawidget, SIGNAL( dataValueChanged(QString) ), SLOT(dataValueChanged(QString) ) ); -} - - -void QTabulationModifyObject::addLink(sofa::core::objectmodel::BaseLink *link, const ModifyObjectFlags& flags) -{ - const std::string name=link->getName(); - QDisplayLinkWidget* displaylinkwidget = new QDisplayLinkWidget(this,link,flags); - this->layout()->addWidget(displaylinkwidget); - - size += displaylinkwidget->getNumWidgets(); - pixelSize += displaylinkwidget->sizeHint().height(); - - connect(displaylinkwidget, SIGNAL( WidgetDirty(bool) ), this, SLOT( setTabDirty(bool) ) ); - connect(this, SIGNAL(UpdateDatas()), displaylinkwidget, SLOT( UpdateLink())); - connect(this, SIGNAL(UpdateDataWidgets()), displaylinkwidget, SLOT( UpdateWidgets())); -} - -void QTabulationModifyObject::dataValueChanged(QString dataValue) -{ - m_dataValueModified[sender()] = dataValue; -} - -QString QTabulationModifyObject::getDataModifiedString() const -{ - if (m_dataValueModified.empty()) - { - return QString(); - } - - QString dataModifiedString; - std::map< QObject*, QString>::const_iterator it_map; - std::map< QObject*, QString>::const_iterator it_last = m_dataValueModified.end(); - --it_last; - - for (it_map = m_dataValueModified.begin(); it_map != m_dataValueModified.end(); ++it_map) - { - const QString& lastDataValue = it_map->second; - dataModifiedString += lastDataValue; - if (it_map != it_last) - { - dataModifiedString += "\n"; - } - } - - return dataModifiedString; -} - -void QTabulationModifyObject::setTabDirty(bool b) -{ - dirty=b; - emit TabDirty(b); -} - -bool QTabulationModifyObject::isDirty() const -{ - return dirty; -} - -bool QTabulationModifyObject::isFull() const -{ - return pixelSize >= pixelMaxSize; -} - -bool QTabulationModifyObject::isEmpty() const -{ - return size==0; -} - -void QTabulationModifyObject::updateDataValue() -{ - emit UpdateDatas(); -} - -void QTabulationModifyObject::updateWidgetValue() -{ - emit UpdateDataWidgets(); -} - -void QTabulationModifyObject::addStretch() -{ - dynamic_cast(this->layout())->addStretch(); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.h deleted file mode 100644 index 79312be505d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTabulationModifyObject.h +++ /dev/null @@ -1,93 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -namespace sofa::gui::qt -{ - -struct ModifyObjectFlags; -class DataWidget; - -class QTabulationModifyObject : public QWidget -{ - Q_OBJECT -public: - QTabulationModifyObject(QWidget* parent, - core::objectmodel::Base *object, QTreeWidgetItem* item, - unsigned int idx=1); - - void externalWidgetAddition(int num) {size+=num;} - void addData(sofa::core::objectmodel::BaseData *data, const ModifyObjectFlags& flags); - void addLink(sofa::core::objectmodel::BaseLink *link, const ModifyObjectFlags& flags); - void addStretch(); - - unsigned int getIndex() const {return index;} - bool isFull() const; - void setFull() {pixelSize=pixelMaxSize;} - bool isEmpty() const; - bool isDirty() const; - - QString getDataModifiedString() const; - -public slots: - void setTabDirty(bool=true); - void updateDataValue(); - void updateWidgetValue(); - void dataValueChanged(QString dataValue); - -signals: - void UpdateDatas(); - void UpdateDataWidgets(); - void TabDirty(bool); - void nodeNameModification(simulation::Node *); - - - -protected: - core::objectmodel::Base *object; - QTreeWidgetItem* item; - - - const unsigned int index; - unsigned int size; - - bool dirty; - std::map< QObject*, QString> m_dataValueModified; - - unsigned int pixelSize; - unsigned int pixelMaxSize; - -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.cpp deleted file mode 100644 index 1103da46d4c..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QTransformationWidget.h" -#include -#include -#include -#include -#include -#include - -#if !defined(INFINITY) -#define INFINITY 9.0e10 -#endif - - -namespace sofa::gui::qt -{ -QTransformationWidget::QTransformationWidget(QWidget* parent, QString name):QGroupBox(parent), numWidgets_(2) - -{ - //this->setColumns(4); - - this->setTitle(name); - //******************************************************************************** - //Translation - new QLabel(QString("Translation"), this); - translation[0] = new WDoubleLineEdit( this, "translation[0]" ); - translation[0]->setMinValue( (double)-INFINITY ); - translation[0]->setMaxValue( (double)INFINITY ); - - translation[1] = new WDoubleLineEdit( this, "translation[1]" ); - translation[1]->setMinValue( (double)-INFINITY ); - translation[1]->setMaxValue( (double)INFINITY ); - - translation[2] = new WDoubleLineEdit( this, "translation[2]" ); - translation[2]->setMinValue( (double)-INFINITY ); - translation[2]->setMaxValue( (double)INFINITY ); - - - //******************************************************************************** - //Rotation - new QLabel(QString("Rotation"), this); - rotation[0] = new WDoubleLineEdit( this, "rotation[0]" ); - rotation[0]->setMinValue( (double)-INFINITY ); - rotation[0]->setMaxValue( (double)INFINITY ); - - rotation[1] = new WDoubleLineEdit( this, "rotation[1]" ); - rotation[1]->setMinValue( (double)-INFINITY ); - rotation[1]->setMaxValue( (double)INFINITY ); - - rotation[2] = new WDoubleLineEdit( this, "rotation[2]" ); - rotation[2]->setMinValue( (double)-INFINITY ); - rotation[2]->setMaxValue( (double)INFINITY ); - - - //******************************************************************************** - //Scale - QLabel *textScale = new QLabel(QString("Scale"), this); - scale[0] = new WDoubleLineEdit( this, "scale[0]" ); - scale[0]->setMinValue( (double)-INFINITY ); - scale[0]->setMaxValue( (double)INFINITY ); - - scale[1] = new WDoubleLineEdit( this, "scale[1]" ); - scale[1]->setMinValue( (double)-INFINITY ); - scale[1]->setMaxValue( (double)INFINITY ); - - scale[2] = new WDoubleLineEdit( this, "scale[2]" ); - scale[2]->setMinValue( (double)-INFINITY ); - scale[2]->setMaxValue( (double)INFINITY ); - - setDefaultValues(); - - connect( translation[0], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( translation[1], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( translation[2], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( rotation[0], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( rotation[1], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( rotation[2], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( scale[0], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( scale[1], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - connect( scale[2], SIGNAL( textChanged(const QString&) ), this, SLOT( changeValue() ) ); - - - //Option still experimental : disabled !!!! - textScale->hide(); - scale[0]->hide(); - scale[1]->hide(); - scale[2]->hide(); -} - -void QTransformationWidget::setDefaultValues() -{ - //******************************************************************************** - //Default values - translation[0]->setValue(0); - translation[1]->setValue(0); - translation[2]->setValue(0); - - rotation[0]->setValue(0); - rotation[1]->setValue(0); - rotation[2]->setValue(0); - - scale[0]->setValue(1); - scale[1]->setValue(1); - scale[2]->setValue(1); -} - -bool QTransformationWidget::isDefaultValues() const -{ - return ( (translation[0]->getValue() == 0 && translation[1]->getValue() == 0 && translation[2]->getValue() == 0 ) && - (rotation[0]->getValue() == 0 && rotation[1]->getValue() == 0 && rotation[2]->getValue() == 0 ) && - (scale[0]->getValue() == 1 && scale[1]->getValue() == 1 && scale[2]->getValue() == 1 ) ); -} - -void QTransformationWidget::applyTransformation(simulation::Node *node) -{ - sofa::simulation::TransformationVisitor transform(sofa::core::execparams::defaultInstance()); - transform.setTranslation(translation[0]->getValue(),translation[1]->getValue(),translation[2]->getValue()); - transform.setRotation(rotation[0]->getValue(),rotation[1]->getValue(),rotation[2]->getValue()); - transform.setScale(scale[0]->getValue(),scale[1]->getValue(),scale[2]->getValue()); - transform.execute(node); -} - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.h deleted file mode 100644 index 9cc7cc5edef..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QTransformationWidget.h +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include "WDoubleLineEdit.h" - -#include -#include -#include - -namespace sofa::gui::qt -{ - -struct ModifyObjectFlags; -class QTransformationWidget : public QGroupBox -{ - Q_OBJECT -public: - QTransformationWidget(QWidget* parent, QString name); - unsigned int getNumWidgets() const { return numWidgets_;}; - - void setDefaultValues(); - bool isDefaultValues() const; - void applyTransformation(simulation::Node *node); -public slots: - void changeValue() {emit TransformationDirty(true);} -signals: - void TransformationDirty(bool); -protected: - const unsigned int numWidgets_; - - WDoubleLineEdit* translation[3]; - WDoubleLineEdit* rotation[3]; - WDoubleLineEdit* scale[3]; -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.cpp deleted file mode 100644 index 98589716b37..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QVisitorControlPanel.h" -#include - -#include -#include -#include -#include -#include - -#if !defined(INFINITY) -#define INFINITY 9.0e10 -#endif - - -namespace sofa::gui::qt -{ - -QVisitorControlPanel::QVisitorControlPanel(QWidget* parent): QWidget(parent) -{ - QVBoxLayout *vbox=new QVBoxLayout(this); - vbox->setMargin(0); - vbox->setSpacing(0); - - //Filter the results to quickly find a visitor - QWidget *filterResult = new QWidget(this); - QHBoxLayout *hboxFilers=new QHBoxLayout(filterResult); - - textFilter = new QLineEdit(filterResult); - QPushButton *findFilter = new QPushButton(QString("Find"), filterResult); - findFilter->setAutoDefault(true); - - hboxFilers->addWidget(new QLabel(QString("Focus on:"), filterResult)); - hboxFilers->addWidget(textFilter); - hboxFilers->addWidget(findFilter); - - connect(findFilter, SIGNAL(clicked()), this, SLOT(filterResults())); - connect(textFilter, SIGNAL(returnPressed()), this, SLOT(filterResults())); - - //Clear Button - QPushButton *clearButton = new QPushButton(QString("Clear"), this); - clearButton->setAutoDefault(false); - connect(clearButton, SIGNAL(clicked()), this, SIGNAL(clearGraph())); - - - //Parameters to configure the export of the state vectors - QWidget *exportStateParameters = new QWidget(this); - - QHBoxLayout *hboxParameters=new QHBoxLayout(exportStateParameters); - - QCheckBox *activation=new QCheckBox(QString("Trace State Vector"), exportStateParameters); - - spinIndex = new WDoubleLineEdit(exportStateParameters, "index"); - spinIndex->setMinValue( (double)-INFINITY ); - spinIndex->setMaxValue( (double)INFINITY ); - spinIndex->setIntValue(sofa::simulation::Visitor::GetFirstIndexStateVector()); - spinIndex->setMaximumWidth(50); - spinRange = new WDoubleLineEdit(exportStateParameters, "range"); - spinRange->setMinValue( (double)-INFINITY ); - spinRange->setMaxValue( (double)INFINITY ); - spinRange->setIntValue(sofa::simulation::Visitor::GetRangeStateVector()); - spinRange->setMaximumWidth(50); - - connect(activation, SIGNAL(toggled(bool)), this, SLOT(activateTraceStateVectors(bool))); - connect(spinIndex, SIGNAL(editingFinished()), this, SLOT(changeFirstIndex())); - connect(spinRange, SIGNAL(editingFinished()), this, SLOT(changeRange())); - - - hboxParameters->addWidget(activation); - hboxParameters->addItem(new QSpacerItem(100,10)); - hboxParameters->addWidget(new QLabel(QString("First Index"), exportStateParameters)); - hboxParameters->addWidget(spinIndex); - - hboxParameters->addWidget(new QLabel(QString("Range"), exportStateParameters)); - hboxParameters->addWidget(spinRange); - - hboxParameters->addStretch(); - - //Configure the main window - vbox->addWidget(filterResult); - vbox->addWidget(exportStateParameters); - vbox->addWidget(clearButton); - - activateTraceStateVectors(sofa::simulation::Visitor::IsExportStateVectorEnabled()); - -} - -void QVisitorControlPanel::activateTraceStateVectors(bool active) -{ - sofa::simulation::Visitor::EnableExportStateVector(active); - spinIndex->setEnabled(active); - spinRange->setEnabled(active); -} -void QVisitorControlPanel::changeFirstIndex() -{ - WDoubleLineEdit *w=(WDoubleLineEdit *) sender(); - int value=w->getIntValue(); - changeFirstIndex(value); -} -void QVisitorControlPanel::changeRange() -{ - WDoubleLineEdit *w=(WDoubleLineEdit *) sender(); - int value=w->getIntValue(); - changeRange(value); -} - -void QVisitorControlPanel::changeFirstIndex(int idx) -{ - sofa::simulation::Visitor::SetFirstIndexStateVector(idx); -} -void QVisitorControlPanel::changeRange(int range) -{ - sofa::simulation::Visitor::SetRangeStateVector(range); -} -void QVisitorControlPanel::filterResults() -{ - emit focusOn(textFilter->text()); -} - - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.h deleted file mode 100644 index 80b29a5b69f..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QVisitorControlPanel.h +++ /dev/null @@ -1,54 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#include "WDoubleLineEdit.h" - -namespace sofa::gui::qt -{ - -class QVisitorControlPanel : public QWidget -{ - Q_OBJECT -public: - QVisitorControlPanel(QWidget* parent); - - void changeFirstIndex(int); - void changeRange(int); -public slots: - void activateTraceStateVectors(bool); - void changeFirstIndex(); - void changeRange(); - void filterResults(); -signals: - void focusOn(QString); - void clearGraph(); -protected: - QLineEdit *textFilter; - WDoubleLineEdit *spinIndex; - WDoubleLineEdit *spinRange; -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.cpp deleted file mode 100644 index 91cdcf25164..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "RGBAColorDataWidget.h" - -namespace sofa::gui::qt::rgbacolordatawidget_h -{ -helper::Creator DWClass("default",true); - -bool RGBAColorDataWidget::createWidgets() -{ - - m_colorPicker = new QRGBAColorPicker(this); - - QHBoxLayout* hlayout = new QHBoxLayout(this); - hlayout->addWidget(m_colorPicker); - - connect(m_colorPicker, SIGNAL( hasChanged() ), this, SLOT( setWidgetDirty() ) ); - - readFromData(); - - return true; -} - -void RGBAColorDataWidget::setDataReadOnly(bool readOnly) -{ - m_colorPicker->setEnabled(!readOnly); -} - -void RGBAColorDataWidget::readFromData() -{ - m_colorPicker->setColor( getData()->getValue() ); -} - -void RGBAColorDataWidget::writeToData() -{ - RGBAColor* color = getData()->beginEdit(); - (*color) = m_colorPicker->getColor() ; - - getData()->endEdit(); -} - -} //namespace sofa::gui::qt::rgbacolordatawidget_h diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.h deleted file mode 100644 index bbb4ba9e602..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/RGBAColorDataWidget.h +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "QRGBAColorPicker.h" -#include "DataWidget.h" - -namespace sofa::gui::qt::rgbacolordatawidget_h -{ -using sofa::type::RGBAColor ; -using sofa::core::objectmodel::Data ; -using sofa::gui::qt::QRGBAColorPicker ; - -class RGBAColorDataWidget : public TDataWidget -{ - Q_OBJECT - -public: - RGBAColorDataWidget(QWidget* parent, - const char* name, - Data* data): - TDataWidget(parent,name,data) {} - - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - virtual unsigned int numColumnWidget() {return 1;} - -protected: - virtual void readFromData(); - virtual void writeToData(); - QLineEdit* m_nameEdit; - QRGBAColorPicker* m_colorPicker; -}; - -} // namespace sofa::gui::qt::rgbacolordatawidget_h - -namespace sofa::gui::qt -{ - using sofa::gui::qt::rgbacolordatawidget_h::RGBAColorDataWidget; -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.cpp deleted file mode 100644 index e83572b0a84..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.cpp +++ /dev/null @@ -1,2335 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "RealGUI.h" -#include - -#ifdef SOFA_DUMP_VISITOR_INFO -#include "WindowVisitor.h" -#include "GraphVisitor.h" -#endif - -#if SOFA_GUI_QT_HAVE_QT_CHARTS -#include "SofaWindowProfiler.h" -#endif - -#if SOFA_GUI_QT_HAVE_NODEEDITOR -#include "SofaWindowDataGraph.h" -#endif - - -#include -#include -#include "QSofaListView.h" -#include "QDisplayPropertyWidget.h" -#include "FileManagement.h" -#include "DisplayFlagsDataWidget.h" -#include "SofaPluginManager.h" -#include "SofaMouseManager.h" -#include "SofaVideoRecorderManager.h" -#include "WDoubleLineEdit.h" -#include "QSofaStatWidget.h" -#include "viewer/SofaViewer.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -using sofa::helper::system::SetDirectory; - -#include -using sofa::helper::system::FileSystem; - -#include -using sofa::helper::Utils; - -#include -using sofa::helper::system::DataRepository; - -#include -using sofa::gui::common::GuiDataRepository; - -#include -using sofa::simulation::SceneLoaderFactory; - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0)) -#include -#endif - -#include -#include -#include -#include - -#include -using sofa::core::objectmodel::IdleEvent; - -#include -using sofa::simulation::SimulationStartEvent; - -#include -using sofa::simulation::SimulationStopEvent; - -#include -using sofa::helper::system::FileMonitor; - -#include -using sofa::core::ObjectFactory; - -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) -#include "panels/QDocBrowser.h" -using sofa::gui::qt::DocBrowser; -#endif - -using sofa::core::ExecParams; - -#include - - -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ - -using sofa::core::objectmodel::BaseObject; -using namespace sofa::helper::system::thread; -using namespace sofa::simulation; -using namespace sofa::core::visual; - -/// Custom QApplication class handling FileOpen events for MacOS -class QSOFAApplication : public QApplication -{ -public: - QSOFAApplication(int &argc, char ** argv) - : QApplication(argc,argv) - { - QCoreApplication::setOrganizationName("Sofa Consortium"); - QCoreApplication::setOrganizationDomain("sofa"); - QCoreApplication::setApplicationName("runSofa"); - } - -#if QT_VERSION < 0x050000 - static inline QString translate(const char * context, const char * key, const char * disambiguation, - QCoreApplication::Encoding encoding = QCoreApplication::UnicodeUTF8, int n = -1) - { return QApplication::translate(context, key, disambiguation, encoding, n); } -#else - static inline QString translate(const char * context, const char * key, - const char * disambiguation = Q_NULLPTR, int n = -1) - { return QApplication::translate(context, key, disambiguation, n); } -#endif - -protected: - bool event(QEvent *event) override - { - switch (event->type()) - { - case QEvent::FileOpen: - { - if(this->topLevelWidgets().count() < 1) - return false; - return true; - } - default: - return QApplication::event(event); - } - } -}; - -RealGUI* gui = nullptr; -QApplication* application = nullptr; - -const char* progname=""; - - - -class RealGUIFileListener : public sofa::helper::system::FileEventListener -{ -public: - RealGUIFileListener(RealGUI* realgui){ - m_realgui = realgui; - } - ~RealGUIFileListener() override{} - - void fileHasChanged(const std::string& filename) override - { - m_realgui->fileOpen(filename, false, true); - } - RealGUI* m_realgui; -}; - - -//======================= STATIC METHODS ========================= { - -void RealGUI::setupSurfaceFormat() -{ - static std::once_flag flag; - std::call_once(flag, [] - { - QSurfaceFormat format; - if(!SOFA_GUI_QT_ENABLE_VSYNC) - { - format.setSwapInterval(0); //Setting an interval value of 0 will turn the vertical refresh syncing off - } - - static constexpr int vmajor = 3, vminor = 2; - format.setVersion(vmajor,vminor); //Sets the desired major and minor OpenGL versions. - format.setProfile(QSurfaceFormat::CompatibilityProfile); //Sets the desired OpenGL context profile. CompatibilityProfile = Functionality from earlier OpenGL versions is available. - format.setOption(QSurfaceFormat::DeprecatedFunctions, true); //Used to request that deprecated functions be included in the OpenGL context profile. If not specified, you should get a forward compatible context without support functionality marked as deprecated. This requires OpenGL version 3.0 or higher. - format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - - if (mArgumentParser) - { - unsigned int viewerMSAANbSampling = 0; - mArgumentParser->getValueFromKey("msaa", viewerMSAANbSampling); - if (viewerMSAANbSampling > 1) - { - msg_info("RealGUI") << "Set multisampling anti-aliasing (MSAA) with " << viewerMSAANbSampling << " samples." ; - format.setSamples(static_cast(viewerMSAANbSampling)); - } - } - - QSurfaceFormat::setDefaultFormat(format); - }); -} - -BaseGUI* RealGUI::CreateGUI ( const char* name, sofa::simulation::Node::SPtr root, const char* filename ) -{ - setupSurfaceFormat(); - - CreateApplication(); - - // create interface - gui = new RealGUI ( name ); - if ( root ) - { - gui->setScene ( root, filename ); - gui->setWindowFilePath(QString(filename)); - } - - InitApplication(gui); - return gui; -} - -//------------------------------------ - -void RealGUI::SetPixmap(std::string pixmap_filename, QPushButton* b) -{ - if ( DataRepository.findFile ( pixmap_filename ) ) - pixmap_filename = DataRepository.getFile ( pixmap_filename ); - - b->setIcon(QIcon(QPixmap(QPixmap::fromImage(QImage(pixmap_filename.c_str()))))); -} - -//------------------------------------ - -void RealGUI::CreateApplication(int /*_argc*/, char** /*_argv*/) -{ - int *argc = new int; - char **argv=new char*[2]; - *argc = 1; - argv[0] = strdup ( BaseGUI::GetProgramName() ); - argv[1]=nullptr; - application = new QSOFAApplication ( *argc,argv ); - - //force locale to Standard C - //(must be done immediately after the QApplication has been created) - const QLocale locale(QLocale::C); - QLocale::setDefault(locale); -} - -//------------------------------------ - -void RealGUI::InitApplication( RealGUI* _gui) -{ - const QString pathIcon=(DataRepository.getFirstPath() + std::string( "/icons/SOFA.png" )).c_str(); - application->setWindowIcon(QIcon(pathIcon)); - - if(SOFA_GUI_QT_ENABLE_NATIVE_MENU) - { - // Use the OS'native menu instead of the Qt one - _gui->menubar->setNativeMenuBar(true); - } - else - { - // Use the qt menu instead of the native one in order to standardize the way the menu is showed on every OS - _gui->menubar->setNativeMenuBar(false); - } - // show the gui - _gui->show(); // adding extra line in the console? -} -//======================= STATIC METHODS ========================= } - - - - -//======================= CONSTRUCTOR - DESTRUCTOR ========================= { -RealGUI::RealGUI ( const char* viewername) - : - fpsLabel(nullptr), - timeLabel(nullptr), - - #ifdef SOFA_DUMP_VISITOR_INFO - windowTraceVisitor(nullptr), - handleTraceVisitor(nullptr), - #endif - - m_sofaMouseManager(nullptr), - #if SOFAGUIQT_HAVE_QT5_CHARTS - m_windowTimerProfiler(nullptr), - #endif - #if SOFAGUIQT_HAVE_NODEEDITOR - m_sofaWindowDataGraph(nullptr), - #endif - simulationGraph(nullptr), - m_dumpState(false), - m_dumpStateStream(nullptr), - m_exportGnuplot(false), - m_animateOBJ(false), - m_animationOBJcounter(0), - m_displayComputationTime(false), - m_fullScreen(false), - m_viewer(nullptr), - m_clockBeforeLastStep(0), - propertyWidget(nullptr), - currentTab ( nullptr ), - statWidget(nullptr), - timerStep(nullptr), - backgroundImage(nullptr), - pluginManagerDialog(nullptr), - recentlyOpenedFilesManager(BaseGUI::getConfigDirectoryPath() + "/runSofa.ini"), - m_saveReloadFile(false), - displayFlag(nullptr), -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - m_docbrowser(nullptr), -#endif - m_animationState(false), - m_frameCounter(0), - m_viewerMSAANbSampling(1) -{ - setupUi(this); - - ExpandAllButton->setIcon(QIcon(":/RealGUI/expandAll")); - CollapseAllButton->setIcon(QIcon(":/RealGUI/collapseAll")); - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh")); - for (auto* button : {ExpandAllButton, CollapseAllButton, sceneGraphRefreshToggleButton}) - { - button->setFixedWidth(button->height()); - } - - parseOptions(); - - createPluginManager(); - - createRecentFilesMenu(); // configure Recently Opened Menu - - QDoubleValidator *dtValidator = new QDoubleValidator(dtEdit); - dtValidator->setBottom(0.000000001); - dtEdit->setValidator(dtValidator); - - timerStep = new QTimer(this); - connect ( timerStep, SIGNAL ( timeout() ), this, SLOT ( step() ) ); - connect ( this, SIGNAL ( quit() ), this, SLOT ( fileExit() ) ); - connect ( startButton, SIGNAL ( toggled ( bool ) ), this , SLOT ( playpauseGUI ( bool ) ) ); - connect ( ReloadSceneButton, SIGNAL ( clicked() ), this, SLOT ( fileReload() ) ); - connect ( dtEdit, SIGNAL ( textChanged ( const QString& ) ), this, SLOT ( setDt ( const QString& ) ) ); - connect ( realTimeCheckBox, SIGNAL ( stateChanged ( int ) ), this, SLOT ( updateDtEditState() ) ); - connect ( stepButton, SIGNAL ( clicked() ), this, SLOT ( step() ) ); - connect ( dumpStateCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( dumpState ( bool ) ) ); - connect ( displayComputationTimeCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT ( displayComputationTime ( bool ) ) ); - connect ( exportGnuplotFilesCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportGnuplot ( bool ) ) ); - connect ( tabs, SIGNAL ( currentChanged ( int ) ), this, SLOT ( currentTabChanged ( int ) ) ); - - connect ( ResetViewButton, SIGNAL ( clicked() ), this, SLOT ( resetView() ) ); - connect ( SaveViewButton, SIGNAL ( clicked() ), this, SLOT ( saveView() ) ); - connect ( screenshotButton, SIGNAL ( clicked() ), this, SLOT ( screenshot() ) ); - connect ( sizeW, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeW ( int ) ) ); - connect ( sizeH, SIGNAL ( valueChanged ( int ) ), this, SLOT ( setSizeH ( int ) ) ); - - /// We activate this timer only if the interactive mode is enabled (ie livecoding+mouse mouve event). - if(m_enableInteraction){ - timerIdle = new QTimer(this); - connect ( timerIdle, SIGNAL ( timeout() ), this, SLOT ( emitIdle() ) ); - timerIdle->start(50); - } - - this->setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks); -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures); -#else - dockWidget->setFeatures(QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable); -#endif - dockWidget->setAllowedAreas(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea); - - connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(toolsDockMoved())); - - //Status Bar Configuration - fpsLabel = new QLabel ( "9999.9 FPS", statusBar() ); - fpsLabel->setMinimumSize ( fpsLabel->sizeHint() ); - fpsLabel->clear(); - - timeLabel = new QLabel ( "Time: 999.9999", statusBar() ); - timeLabel->setMinimumSize ( timeLabel->sizeHint() ); - timeLabel->clear(); - statusBar()->addWidget ( fpsLabel ); - statusBar()->addWidget ( timeLabel ); - - statWidget = new QSofaStatWidget(TabStats); - TabStats->layout()->addWidget(statWidget); - - // create al widgets first - m_sofaMouseManager = new SofaMouseManager(this); - - createSimulationGraph(); - - //disable widget, can be bothersome with objects with a lot of data - //createPropertyWidget(); - - //viewer - informationOnPickCallBack = InformationOnPickCallBack(this); - - viewerMap.clear(); - - createViewer(viewername, true); - - currentTabChanged ( tabs->currentIndex() ); - - createBackgroundGUIInfos(); // add GUI for Background Information - - createWindowVisitor(); - - createAdvancedTimerProfilerWindow(); - - m_sofaMouseManager->hide(); - SofaVideoRecorderManager::getInstance()->hide(); - - centerWindow(); - - tabs->removeTab(tabs->indexOf(TabVisualGraph)); - -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - m_docbrowser = new DocBrowser(this); - /// Signal to the realGUI that the visibility has changed (eg: to update the menu bar) - connect(m_docbrowser, SIGNAL(visibilityChanged(bool)), this, SLOT(docBrowserVisibilityChanged(bool))); -#endif - - // Trigger QDialog for "About" section - connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(showAbout())); - - m_filelistener = new RealGUIFileListener(this); -} - -//------------------------------------ - -RealGUI::~RealGUI() -{ - if( displayFlag != nullptr ) - delete displayFlag; - -#ifdef SOFA_DUMP_VISITOR_INFO - delete windowTraceVisitor; - delete handleTraceVisitor; -#endif - - removeViewer(); - - FileMonitor::removeListener(m_filelistener); - delete m_filelistener; -} -//======================= CONSTRUCTOR - DESTRUCTOR ========================= } - - - -//======================= OPTIONS DEFINITIONS ========================= { -#ifdef SOFA_DUMP_VISITOR_INFO -void RealGUI::setTraceVisitors(bool b) -{ - exportVisitorCheckbox->setChecked(b); -} -#endif - - -//------------------------------------ - - -//======================= OPTIONS DEFINITIONS ========================= } - - -//======================= METHODS ========================= { - -void RealGUI::docBrowserVisibilityChanged(bool visibility) -{ - if(visibility) - helpShowDocBrowser->setText("Hide doc browser"); - else - helpShowDocBrowser->setText("Show doc browser"); -} - -void RealGUI::stepMainLoop () { - application->processEvents(); -} - -int RealGUI::mainLoop() -{ - int retcode; - if (windowFilePath().isNull()) - { - retcode = application->exec(); - } - else - { - const std::string &filename=windowFilePath().toStdString(); - const std::string &extension=SetDirectory::GetExtension(filename.c_str()); - if (extension == "simu") fileOpenSimu(filename); - retcode = application->exec(); - } - return exitApplication(retcode); -} - -//------------------------------------ - -int RealGUI::closeGUI() -{ - QSettings settings; - QScreen* screen = widget->window()->windowHandle()->screen(); - settings.beginGroup("viewer"); - settings.setValue("screenNumber", QGuiApplication::screens().indexOf(screen)); - settings.endGroup(); - delete this; - return 0; -} - -//------------------------------------ - -sofa::simulation::Node* RealGUI::currentSimulation() -{ - return mSimulation.get(); -} - -//------------------------------------ - - -void RealGUI::fileOpen ( std::string filename, bool temporaryFile, bool reload ) -{ - std::vector expandedNodes; - - if(reload) - { - saveView(); - - if(simulationGraph) - simulationGraph->getExpandedNodes(expandedNodes); - } - - const std::string &extension=SetDirectory::GetExtension(filename.c_str()); - if (extension == "simu") - { - return fileOpenSimu(filename); - } - - startButton->setChecked(false); - startDumpVisitor(); - update(); - - //Hide all the dialogs to modify the graph - emit ( newScene() ); - - if ( DataRepository.findFile (filename) ) - filename = DataRepository.getFile ( filename ); - else - return; - - sofa::simulation::xml::numDefault = 0; - - if( currentSimulation() ) this->unloadScene(); - - const std::vector sceneArgs = ArgumentParser::extra_args(); - mSimulation = sofa::simulation::node::load ( filename, reload, sceneArgs ); - - sofa::simulation::node::initRoot(mSimulation.get()); - if ( mSimulation == nullptr ) - { - msg_warning("RealGUI")<<"Failed to load "<loadHtml( filename ) ; -#endif - } - - configureGUI(mSimulation.get()); - - this->setWindowFilePath(filename.c_str()); - setExportGnuplot(exportGnuplotFilesCheckbox->isChecked()); - stopDumpVisitor(); - - if(!expandedNodes.empty()) - { - simulationGraph->expandPathFrom(expandedNodes); - } - -#if SOFA_GUI_QT_HAVE_QT_CHARTS - if (m_windowTimerProfiler) - m_windowTimerProfiler->resetGraph(); -#endif - -#if SOFA_GUI_QT_HAVE_NODEEDITOR - if (m_sofaWindowDataGraph) - m_sofaWindowDataGraph->resetNodeGraph(currentSimulation()); -#endif - -} - - -//------------------------------------ - -void RealGUI::emitIdle() -{ - // Update all the registered monitor. - FileMonitor::updates(0); - - IdleEvent hb; - Node* groot = m_viewer->getScene(); - if (groot) - { - groot->propagateEvent(core::execparams::defaultInstance(), &hb); - } - - getSofaViewer()->getQWidget()->update(); -} - -/// This open popup the file selection windows. -void RealGUI::popupOpenFileSelector() -{ - const std::string filename(this->windowFilePath().toStdString()); - - // build the filter with the SceneLoaderFactory - std::string filter, allKnownFilters = "All known ("; - SceneLoaderFactory::SceneLoaderList* loaders = SceneLoaderFactory::getInstance()->getEntries(); - for (SceneLoaderFactory::SceneLoaderList::iterator it=loaders->begin(); it!=loaders->end(); ++it) - { - if (it!=loaders->begin()) filter +=";;"; - filter += (*it)->getFileTypeDesc(); - filter += " ("; - SceneLoader::ExtensionList extensions; - (*it)->getExtensionList(&extensions); - for (SceneLoader::ExtensionList::iterator itExt=extensions.begin(); itExt!=extensions.end(); ++itExt) - { - if (itExt!=extensions.begin()) filter +=" "; - filter+="*."; - filter+=(*itExt); - - allKnownFilters+="*."+(*itExt); - if (*it!=loaders->back() || itExt!=extensions.end()-1) allKnownFilters += " "; - } - filter+=")"; - } - allKnownFilters+=")"; - - filter += ";;Simulation (*.simu)"; - - filter = allKnownFilters+";;"+filter+";;All (*)"; // the first filter is selected by default - - QString selectedFilter( tr(allKnownFilters.c_str()) ); // this does not select the desired filter - - QString s = getOpenFileName ( this, filename.empty() ?nullptr:filename.c_str(), - filter.c_str(), - "open file dialog", "Choose a file to open", &selectedFilter - ); - if ( s.length() >0 ) - { - if (s.endsWith( ".simu") ) - fileOpenSimu(s.toStdString()); - else - fileOpen (s.toStdString()); - } -} - -//------------------------------------ - -void RealGUI::fileOpenSimu ( std::string s ) -{ - std::ifstream in(s.c_str()); - - if (!in.fail()) - { - std::string filename; - std::string initT, endT, dT, writeName; - in - >> filename - >> initT >> initT - >> endT >> endT >> endT - >> dT >> dT - >> writeName >> writeName; - in.close(); - - if ( DataRepository.findFile (filename) ) - { - filename = DataRepository.getFile ( filename ); - simulationName = s; - const std::string::size_type pointSimu = simulationName.rfind(".simu"); - simulationName.resize(pointSimu); - fileOpen(filename.c_str()); - - dtEdit->setText(QString(dT.c_str())); - } - } -} - -//------------------------------------ - -void RealGUI::setSceneWithoutMonitor (Node::SPtr root, const char* filename, bool temporaryFile) -{ - if (filename) - { - if (!temporaryFile) - recentlyOpenedFilesManager.openFile(filename); - m_saveReloadFile=temporaryFile; - setTitle ( filename ); -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - if (m_docbrowser && filename) - { - m_docbrowser->loadHtml( filename ); - } -#endif - } - - if (root) - { - //Check the validity of the BBox - const sofa::type::BoundingBox& nodeBBox = root->getContext()->f_bbox.getValue(); - if(nodeBBox.isNegligeable()) - { - msg_warning("RealGUI") << "Global Bounding Box seems very small; Your viewer settings (based on the bbox) are likely invalid, switching to default value of [-1,-1,-1,1,1,1]." - << "This is caused by using component which does not implement properly the computeBBox function." - << "You can remove this warning by manually forcing a value in the parameter bbox=\"minX minY minZ maxX maxY maxZ\" in your root node \n"; - const sofa::type::BoundingBox b(-1.0,-1.0,-1.0,1.0,1.0,1.0); - root->f_bbox.setValue(b); - } - - - mSimulation = root; - eventNewTime(); - startButton->setChecked(root->getContext()->getAnimate() ); - - dtEdit->setText ( QString::number ( root->getDt() ) ); - simulationGraph->setRoot(root.get()); - simulationGraph->collapseAll(); - simulationGraph->expandToDepth(0); - simulationGraph->resizeColumnToContents(0); - statWidget->CreateStats(root.get()); - - getViewer()->setScene( root, filename ); - getViewer()->load(); - getViewer()->resetView(); - createDisplayFlags( root ); - - getSofaViewer()->getQWidget()->setFocus(); - getSofaViewer()->getQWidget()->show(); - getSofaViewer()->getQWidget()->update(); - - resetScene(); - } -} - -void RealGUI::setScene(Node::SPtr root, const char* filename, bool temporaryFile) -{ - if(m_enableInteraction && filename){ - FileMonitor::removeListener(m_filelistener); - FileMonitor::addFile(filename, m_filelistener); - } - setSceneWithoutMonitor(root, filename, temporaryFile) ; -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - if (m_docbrowser && filename) - { - m_docbrowser->loadHtml( filename ) ; - } -#endif -} - -//------------------------------------ - -void RealGUI::unloadScene(bool _withViewer) -{ - if(_withViewer && getViewer()) - getViewer()->unload(); - - sofa::simulation::node::unload ( currentSimulation() ); - - if(_withViewer && getViewer()) - getViewer()->setScene(nullptr); -} - -//------------------------------------ - -void RealGUI::setTitle ( std::string windowTitle ) -{ - std::string str = "SOFA v" + std::string(SOFA_VERSION_STR); - if ( !windowTitle.empty() ) - { - str += " - "; - str += windowTitle; - } -#ifdef WIN32 - setWindowTitle ( str.c_str() ); -#else - this->setWindowTitle(QString(str.c_str()) ); -#endif - setWindowFilePath( windowTitle.c_str() ); -} - -//------------------------------------ - -void RealGUI::fileReload() -{ - std::string filename(this->windowFilePath().toStdString()); - QString s = filename.c_str(); - - if ( filename.empty() ) - { - msg_error("RealGUI") << "Reload failed: no file loaded."; - return; - } - - if (s.endsWith( ".simu") ) - fileOpenSimu(s.toStdString()); - else - fileOpen ( s.toStdString(),m_saveReloadFile ); -} - -//------------------------------------ - -void RealGUI::fileExit() -{ - //Hide all opened ModifyObject windows - emit ( newScene() ); - startButton->setChecked ( false); - this->close(); -} - -void RealGUI::editRecordDirectory() -{ - const std::string filename(this->windowFilePath().toStdString()); - std::string record_directory; - const QString s = getExistingDirectory ( this, filename.empty() ?nullptr:filename.c_str(), "open directory dialog", "Choose a directory" ); - if (s.length() > 0) - { - record_directory = s.toStdString(); - if (record_directory.at(record_directory.size()-1) != '/') - record_directory+="/"; - } -} - -//------------------------------------ - -void RealGUI::editGnuplotDirectory() -{ - const std::string filename(this->windowFilePath().toStdString()); - const QString s = getExistingDirectory ( this, filename.empty() ?nullptr:filename.c_str(), "open directory dialog", "Choose a directory" ); - if (s.length() > 0) - { - gnuplotDirectory = s.toStdString(); - if (gnuplotDirectory.at(gnuplotDirectory.size()-1) != '/') - gnuplotDirectory+="/"; - setExportGnuplot(exportGnuplotFilesCheckbox->isChecked()); - } -} - -//------------------------------------ - -void RealGUI::showDocBrowser() -{ -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - m_docbrowser->flipVisibility(); -#else - msg_warning("RealGUI") << "Doc browser has been disabled because Qt5WebEngine is not available"; -#endif -} - -//------------------------------------ - -void RealGUI::showAbout() -{ - //create the QDialog for About - AboutSOFADialog* aboutSOFA_dialog = new sofa::gui::qt::AboutSOFADialog(this); - aboutSOFA_dialog->show(); -} - -//------------------------------------ - -void RealGUI::showPluginManager() -{ - pluginManagerDialog->updatePluginsListView(); - pluginManagerDialog->show(); -} - -//------------------------------------ - -void RealGUI::showMouseManager() -{ - m_sofaMouseManager->updateContent(); - m_sofaMouseManager->show(); -} - -//------------------------------------ - -void RealGUI::showVideoRecorderManager() -{ - SofaVideoRecorderManager::getInstance()->show(); -} - -//------------------------------------ - -void RealGUI::showWindowDataGraph() -{ -#if SOFA_GUI_QT_HAVE_NODEEDITOR - std::cout << "RealGUI::showWindowDataGraph()" << std::endl; - //m_sofaMouseManager->createGraph(); - if (m_sofaWindowDataGraph == nullptr) - { - createSofaWindowDataGraph(); - } - m_sofaWindowDataGraph->show(); - -#endif -} - -//------------------------------------ - -void RealGUI::setViewerResolution ( int w, int h ) -{ - const QSize winSize = size(); - const QSize viewSize = ( getViewer() ) ? getSofaViewer()->getQWidget()->size() : QSize(0,0); - -#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0)) - const QRect screen = QApplication::desktop()->availableGeometry(QApplication::desktop()->screenNumber(this)); -#else - const QRect screen = QGuiApplication::primaryScreen()->availableGeometry(); -#endif - QSize newWinSize(winSize.width() - viewSize.width() + w, winSize.height() - viewSize.height() + h); - if (newWinSize.width() > screen.width()) newWinSize.setWidth(screen.width()-20); - if (newWinSize.height() > screen.height()) newWinSize.setHeight(screen.height()-20); - - this->resize(newWinSize); -} - -//------------------------------------ - -void RealGUI::setFullScreen (bool enable) -{ - if (enable == m_fullScreen) return; - - if (enable) - { - optionTabs->hide(); - } - else if (m_fullScreen) - { - optionTabs->show(); - } - - if (enable) - { - msg_info("RealGUI") << "Set Full Screen Mode"; - showFullScreen(); - m_fullScreen = true; - - dockWidget->setFloating(true); - dockWidget->setVisible(false); - } - else - { - msg_info("RealGUI") << "Set Windowed Mode"; - showNormal(); - m_fullScreen = false; - dockWidget->setVisible(true); - dockWidget->setFloating(false); - } - - if (enable) - { - menuBar()->hide(); - statusBar()->hide(); - } - else - { - menuBar()->show(); - statusBar()->show(); - } -} - -void RealGUI::centerWindow() -{ - //Center the application -#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0)) - const QRect screen = QApplication::desktop()->availableGeometry(QApplication::desktop()->primaryScreen()); -#else - const QRect screen = QGuiApplication::primaryScreen()->availableGeometry(); -#endif - this->move( ( screen.width() - this->width() ) / 2, ( screen.height() - this->height()) / 2 ); -} - -//------------------------------------ - -void RealGUI::setBackgroundColor(const sofa::type::RGBAColor& c) -{ - background[0]->setText(QString::number(c[0])); - background[1]->setText(QString::number(c[1])); - background[2]->setText(QString::number(c[2])); - updateBackgroundColour(); -} - -//------------------------------------ - -void RealGUI::setBackgroundImage(const std::string& c) -{ - backgroundImage->setText(QString(c.c_str())); - updateBackgroundImage(); -} - -//------------------------------------ - -void RealGUI::setViewerConfiguration(sofa::component::setting::ViewerSetting* viewerConf) -{ - const type::Vec<2,int> &res=viewerConf->d_resolution.getValue(); - - if (viewerConf->d_fullscreen.getValue()) - setFullScreen(); - else - setViewerResolution(res[0], res[1]); - getViewer()->configure(viewerConf); -} - -//------------------------------------ - -void RealGUI::setMouseButtonConfiguration(sofa::component::setting::MouseButtonSetting *button) -{ - m_sofaMouseManager->updateOperation(button); -} - -//------------------------------------ - -void RealGUI::setDumpState(bool b) -{ - dumpStateCheckBox->setChecked(b); -} - -//------------------------------------ - -void RealGUI::setLogTime(bool b) -{ - displayComputationTimeCheckBox->setChecked(b); -} - -//------------------------------------ - -void RealGUI::setExportState(bool b) -{ - exportGnuplotFilesCheckbox->setChecked(b); -} - -//------------------------------------ - -void RealGUI::setGnuplotPath(const std::string &path) -{ - gnuplotDirectory = path; -} - -//------------------------------------ - -void RealGUI::createViewer(const char* _viewerName, bool _updateViewerList/*=false*/) -{ - if(_updateViewerList) - { - this->updateViewerList(); - // the viewer with the key viewerName is already created - if( m_viewer != nullptr && !viewerMap.begin()->first.compare( std::string(_viewerName) ) ) - return; - } - - for (std::map< helper::SofaViewerFactory::Key, QAction*>::const_iterator iter_map = viewerMap.begin(); - iter_map != viewerMap.end(); ++iter_map ) - { - if( strcmp( iter_map->first.c_str(), _viewerName ) == 0 ) - { - removeViewer(); - ViewerQtArgument viewerArg = ViewerQtArgument("viewer", this->widget, m_viewerMSAANbSampling); - registerViewer( helper::SofaViewerFactory::CreateObject(iter_map->first, viewerArg) ); - //see to put on checkable - iter_map->second->setChecked(true); - } - else - iter_map->second->setChecked(false); - } - - mGuiName = _viewerName; - initViewer( getViewer() ); -} - -//------------------------------------ - -void RealGUI::registerViewer(BaseViewer* _viewer) -{ - // Change our viewer - if(_viewer == nullptr) - { - msg_error("RealGUI")<<"when registerViewer, the viewer is nullptr"; - return; - } - - sofa::gui::qt::viewer::SofaViewer* tmpViewer = dynamic_cast(_viewer); - if(tmpViewer != nullptr) - { - const sofa::gui::qt::viewer::SofaViewer* old = m_viewer; - m_viewer = tmpViewer; - delete old; - } - else - { - msg_error("RealGUI")<<"when registerViewer, the viewer can't be cast as sofa::gui::qt::viewer::SofaViewer*"; - } -} - -//------------------------------------ - -BaseViewer* RealGUI::getViewer() -{ - return m_viewer; -} - -//------------------------------------ - -sofa::gui::qt::viewer::SofaViewer* RealGUI::getSofaViewer() -{ - return m_viewer; -} - - -//------------------------------------ - -void RealGUI::removeViewer() -{ - if(m_viewer != nullptr) - { - getSofaViewer()->removeViewerTab(tabs); - delete m_viewer; - m_viewer = nullptr; - } -} - -//------------------------------------ - -void RealGUI::dragEnterEvent( QDragEnterEvent* event) -{ - event->accept(); -} - -//------------------------------------ - -void RealGUI::dropEvent(QDropEvent* event) -{ - QString text; - //Q3TextDrag::decode(event, text); - if (event->mimeData()->hasText()) - text = event->mimeData()->text(); - std::string filename(text.toStdString()); - -#ifdef WIN32 - filename = filename.substr(8); //removing file:/// -#else - filename = filename.substr(7); //removing file:// -#endif - - if (filename[filename.size()-1] == '\n') - { - filename.resize(filename.size()-1); - filename[filename.size()-1]='\0'; - } - - if (filename.rfind(".simu") != std::string::npos) - fileOpenSimu(filename); - else fileOpen(filename); -} - -//------------------------------------ - -void RealGUI::init() -{ - m_frameCounter = 0; - m_animateOBJ = false; - m_animationOBJcounter = 0; - m_dumpState = false; - m_dumpStateStream = 0; - m_displayComputationTime = false; - m_exportGnuplot = false; - gnuplotDirectory = ""; - m_fullScreen = false; -} - -//------------------------------------ - -void RealGUI::createDisplayFlags(Node::SPtr root) -{ - if( displayFlag != nullptr) - { - gridLayout1->removeWidget(displayFlag); - delete displayFlag; - displayFlag = nullptr; - } - - sofa::component::visual::VisualStyle* visualStyle = nullptr; - - if( root ) - { - root->get(visualStyle); - if(visualStyle) - { - displayFlag = new DisplayFlagsDataWidget(tabView, "displayFlagwidget", &visualStyle->d_displayFlags, true); - displayFlag->createWidgets(); - displayFlag->updateWidgetValue(); - connect( displayFlag, SIGNAL( WidgetDirty(bool) ), this, SLOT(showhideElements() )); - displayFlag->setMinimumSize(50,100); - gridLayout1->addWidget(displayFlag,0,0); - connect(tabs,SIGNAL(currentChanged(int)),displayFlag, SLOT( updateWidgetValue() )); - } - } -} - -//------------------------------------ - -// Update sofa Simulation with the time step -void RealGUI::eventNewStep() -{ - static ctime_t beginTime[10]; - static const ctime_t timeTicks = CTime::getRefTicksPerSec(); - const Node* root = currentSimulation(); - - if ( m_frameCounter==0 ) - { - const ctime_t t = CTime::getRefTime(); - for ( int i=0; i<10; i++ ) - beginTime[i] = t; - } - - ++m_frameCounter; - if ( ( m_frameCounter%10 ) == 0 ) - { - const ctime_t curtime = CTime::getRefTime(); - const int i = ( ( m_frameCounter/10 ) %10 ); - const double fps = ( ( double ) timeTicks / ( curtime - beginTime[i] ) ) * ( m_frameCounter<100?m_frameCounter:100 ); - showFPS(fps); - - beginTime[i] = curtime; - } - - if ( m_displayComputationTime && ( m_frameCounter%100 ) == 0 && root!=nullptr ) - { - /// @TODO: use AdvancedTimer in GUI to display time statistics - } -} - -void RealGUI::showFPS(double fps) -{ - if (fpsLabel) - { - char buf[100]; - sprintf ( buf, "%.1f FPS", fps ); - fpsLabel->setText ( buf ); - } -} - -//------------------------------------ - -void RealGUI::eventNewTime() -{ - const Node* root = currentSimulation(); - if (root && timeLabel) - { - const double time = root->getTime(); - char buf[100]; - sprintf ( buf, "Time: %.3g, Steps: %i", time, m_frameCounter ); - timeLabel->setText ( buf ); - } -} - -//------------------------------------ - -void RealGUI::keyPressEvent ( QKeyEvent * e ) -{ - if (e->modifiers()) return; - - // ignore if there are modifiers (i.e. CTRL of SHIFT) - switch ( e->key() ) - { - case Qt::Key_O: - // --- export to OBJ - { - exportOBJ ( currentSimulation() ); - break; - } - - case Qt::Key_P: - // --- export to a succession of OBJ to make a video - { - m_animateOBJ = !m_animateOBJ; - m_animationOBJcounter = 0; - break; - } - case Qt::Key_Space: - { - playpauseGUI(!startButton->isChecked()); - break; - } - case Qt::Key_Backspace: - { - resetScene(); - break; - } - case Qt::Key_F11: - // --- fullscreen mode - { - setFullScreen(!m_fullScreen); - break; - } - case Qt::Key_Escape: - { - emit(quit()); - break; - } - case Qt::Key_S: - { - screenshot(); - break; - } - default: - { - if (m_viewer) - m_viewer->keyPressEvent(e); - break; - } - } -} - -//------------------------------------ - -void RealGUI::startDumpVisitor() -{ -#ifdef SOFA_DUMP_VISITOR_INFO - Node* root = currentSimulation(); - if (root && this->exportVisitorCheckbox->isChecked()) - { - m_dumpVisitorStream.str(""); - Visitor::startDumpVisitor(&m_dumpVisitorStream, root->getTime()); - } -#endif -} - -//------------------------------------ - -void RealGUI::stopDumpVisitor() -{ -#ifdef SOFA_DUMP_VISITOR_INFO - if (this->exportVisitorCheckbox->isChecked()) - { - Visitor::stopDumpVisitor(); - m_dumpVisitorStream.flush(); - //Creation of the graph - std::string xmlDoc=m_dumpVisitorStream.str(); - handleTraceVisitor->load(xmlDoc); - m_dumpVisitorStream.str(""); - } -#endif -} - -//------------------------------------ - -void RealGUI::initViewer(BaseViewer* _viewer) -{ - if(_viewer == nullptr) - { - msg_error("RealGUI")<<"when initViewer, the viewer is nullptr"; - return; - } - init(); //init data member from RealGUI for the viewer initialisation in the GUI - - // Is our viewer not a qt::viewer::SofaViewer ? - sofa::gui::qt::viewer::SofaViewer* sofaViewer = dynamic_cast(_viewer); - if( sofaViewer == nullptr ) - { - msg_error("RealGUI") << "initViewer failed as given _viewer is not of type sofa::gui::qt::viewer::SofaViewer*"; - } - else - { - this->mainWidgetLayout->addWidget(sofaViewer->getQWidget()); - - sofaViewer->getQWidget()->setFocusPolicy ( Qt::StrongFocus ); - - sofaViewer->getQWidget()->setSizePolicy ( QSizePolicy ( ( QSizePolicy::Policy ) 7, - ( QSizePolicy::Policy ) 7 - //, 100, 1, - //sofaViewer->getQWidget()->sizePolicy().hasHeightForWidth() ) - )); - - sofaViewer->getQWidget()->setMinimumSize ( QSize ( 0, 0 ) ); - sofaViewer->getQWidget()->setMouseTracking ( true ); - sofaViewer->configureViewerTab(tabs); - - connect ( sofaViewer->getQWidget(), SIGNAL ( resizeW ( int ) ), sizeW, SLOT ( setValue ( int ) ) ); - connect ( sofaViewer->getQWidget(), SIGNAL ( resizeH ( int ) ), sizeH, SLOT ( setValue ( int ) ) ); - connect ( sofaViewer->getQWidget(), SIGNAL ( quit ( ) ), this, SLOT ( fileExit ( ) ) ); - connect(simulationGraph, SIGNAL(focusChanged(sofa::core::objectmodel::BaseObject*)), - sofaViewer->getQWidget(), SLOT(fitObjectBBox(sofa::core::objectmodel::BaseObject*)) - ); - connect(simulationGraph, SIGNAL( focusChanged(sofa::core::objectmodel::BaseNode*) ), - sofaViewer->getQWidget(), SLOT( fitNodeBBox(sofa::core::objectmodel::BaseNode*) ) - ); - - // setGUI - textEdit1->setText ( sofaViewer->helpString() ); - connect ( this, SIGNAL( newStep()), sofaViewer->getQWidget(), SLOT( update())); - - sofaViewer->getQWidget()->setFocus(); - sofaViewer->getQWidget()->show(); - sofaViewer->getQWidget()->update(); - - sofaViewer->getPickHandler()->addCallBack(&informationOnPickCallBack ); - } - - m_sofaMouseManager->setPickHandler(_viewer->getPickHandler()); -} - -//------------------------------------ - -void RealGUI::parseOptions() -{ - - if (mArgumentParser) { - mArgumentParser->getValueFromKey("interactive", m_enableInteraction); - mArgumentParser->getValueFromKey("msaa", m_viewerMSAANbSampling); - - if (m_enableInteraction) - msg_warning("runSofa") << "you activated the interactive mode. This is currently an experimental feature " - "that may change or be removed in the future. "; - } -} - -//------------------------------------ - -void RealGUI::createPluginManager() -{ - pluginManagerDialog = new SofaPluginManager(this); - pluginManagerDialog->hide(); - this->connect( pluginManagerDialog, SIGNAL( libraryAdded() ), this, SLOT( updateViewerList() )); - this->connect( pluginManagerDialog, SIGNAL( libraryRemoved() ), this, SLOT( updateViewerList() )); -} - -void RealGUI::createSofaWindowDataGraph() -{ -#if SOFA_GUI_QT_HAVE_NODEEDITOR - m_sofaWindowDataGraph = new SofaWindowDataGraph(this, currentSimulation()); - m_sofaWindowDataGraph->hide(); -#endif -} - -//------------------------------------ - -void RealGUI::createRecentFilesMenu() -{ - fileMenu->removeAction(Action); - - //const int indexRecentlyOpened=fileMenu->count()-2; - const int indexRecentlyOpened=fileMenu->actions().count(); - - QMenu *recentMenu = recentlyOpenedFilesManager.createWidget(this); - fileMenu->insertMenu(fileMenu->actions().at(indexRecentlyOpened-1), - recentMenu); - connect(recentMenu, SIGNAL(triggered(QAction *)), this, SLOT(fileRecentlyOpened(QAction *))); -} - -//------------------------------------ - -void RealGUI::createBackgroundGUIInfos() -{ - QWidget *colour = new QWidget(TabPage); - QHBoxLayout *colourLayout = new QHBoxLayout(colour); - colourLayout->addWidget(new QLabel(QString("Colour "),colour)); - - for (unsigned int i=0; i<3; ++i) - { - std::ostringstream s; - s<<"background" <setMinValue( 0.0f); - background[i]->setMaxValue( 1.0f); - background[i]->setValue( 1.0f); - background[i]->setMaximumSize(50, 20); - - colourLayout->addWidget(background[i]); - connect( background[i], SIGNAL( returnPressed() ), this, SLOT( updateBackgroundColour() ) ); - } - - QWidget *image = new QWidget(TabPage); - QHBoxLayout *imageLayout = new QHBoxLayout(image); - imageLayout->addWidget(new QLabel(QString("Image "),image)); - - backgroundImage = new QLineEdit(image); - backgroundImage->setText("backgroundImage"); - if ( getViewer() ) - backgroundImage->setText( QString(getViewer()->getBackgroundImage().c_str()) ); - else - backgroundImage->setText( QString() ); - imageLayout->addWidget(backgroundImage); - connect( backgroundImage, SIGNAL( returnPressed() ), this, SLOT( updateBackgroundImage() ) ); - - ((QVBoxLayout*)(TabPage->layout()))->insertWidget(1,colour); - ((QVBoxLayout*)(TabPage->layout()))->insertWidget(2,image); -} - -//------------------------------------ -void RealGUI::createSimulationGraph() -{ - simulationGraph = new QSofaListView(SIMULATION,TabGraph,"SimuGraph"); - TabGraph->layout()->addWidget(simulationGraph); - - connect ( ExportGraphButton, SIGNAL ( clicked() ), simulationGraph, SLOT ( Export() ) ); - connect ( ExpandAllButton, SIGNAL ( clicked() ), simulationGraph, SLOT ( expandAll() ) ); - connect ( CollapseAllButton, SIGNAL ( clicked() ), simulationGraph, SLOT ( ExpandRootNodeOnly() ) ); - connect ( sceneGraphRefreshToggleButton, &QPushButton::clicked , this, &RealGUI::onSceneGraphRefreshButtonClicked ); - connect(simulationGraph, &QSofaListView::dirtynessChanged, this, &RealGUI::sceneGraphViewDirtynessChanged); - connect(simulationGraph, &QSofaListView::lockingChanged, this, &RealGUI::sceneGraphViewLockingChanged); - - connect(simulationGraph, SIGNAL( RootNodeChanged(sofa::simulation::Node*, const char*) ), this, SLOT ( newRootNode(sofa::simulation::Node* , const char*) ) ); - connect(simulationGraph, SIGNAL( NodeRemoved() ), this, SLOT( update() ) ); - connect(simulationGraph, SIGNAL( Lock(bool) ), this, SLOT( lockAnimation(bool) ) ); - connect(simulationGraph, SIGNAL( RequestExportOBJ(sofa::simulation::Node*, bool) ), this, SLOT( exportOBJ(sofa::simulation::Node*, bool) ) ); - connect(simulationGraph, SIGNAL( RequestActivation(sofa::simulation::Node*, bool) ), this, SLOT( activateNode(sofa::simulation::Node*, bool) ) ); - connect(simulationGraph, SIGNAL( RequestSleeping(sofa::simulation::Node*, bool) ), this, SLOT( setSleepingNode(sofa::simulation::Node*, bool) ) ); - connect(simulationGraph, SIGNAL( Updated() ), this, SLOT( redraw() ) ); - connect(simulationGraph, SIGNAL( NodeAdded() ), this, SLOT( update() ) ); - connect(simulationGraph, SIGNAL( dataModified( QString ) ), this, SLOT( appendToDataLogFile(QString ) ) ); - connect(this, SIGNAL( newScene() ), simulationGraph, SLOT( CloseAllDialogs() ) ); - connect(this, SIGNAL( newStep() ), simulationGraph, SLOT( UpdateOpenedDialogs() ) ); - - std::ifstream file( BaseGUI::getConfigDirectoryPath() + "/sceneGraphLock" ); - if(file.is_open()) - { - bool isLocked; - file >> isLocked; - if (isLocked) - { - simulationGraph->lock(); - } - else - { - simulationGraph->unLock(); - } - file.close(); - } - else - { - simulationGraph->unLock(); - } -} - -// This slot is called when the sceneGraph view is set to dirty -void RealGUI::sceneGraphViewDirtynessChanged(bool isDirty) -{ - if(isDirty) - { - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh-dirty")); - } - else if(simulationGraph->isLocked()) - { - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh-locked")); - } - else - { - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh-unlocked")); - } -} - -// This slot is called when the sceneGraph view has been locked/unlocked. -// The locking state indicates how the view is taking into account the scene graph data changes. -// when locked, the vue is not updated. When unlocked all changes are taken into account. -void RealGUI::sceneGraphViewLockingChanged(bool isLocked) -{ - if(isLocked) - { - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh-locked")); - } - else - { - sceneGraphRefreshToggleButton->setIcon(QIcon(":/RealGUI/sceneGraphRefresh-unlocked")); - } -} - -// The scene graph update button has three states -// State 0: unlocked (all the changes on the graph are immediately taken into account) -// State 1: locked (the changes on the graph are not done but the simulation graph is set to dirty if -// there is some changes on the graph. A click on the button unlocks the graph (go to state 0). -// State 2: dirty, in that state the button reflect the fact that the scene graph view has changed but not displayed. -// A click on the button refreshes the graph view but does not change the Lock/Unlock state -void RealGUI::onSceneGraphRefreshButtonClicked() -{ - if(simulationGraph->isLocked()) - { - simulationGraph->unLock(); - } - else - { - simulationGraph->lock(); - } - - std::ofstream file( BaseGUI::getConfigDirectoryPath() + "/sceneGraphLock" ); - if(file) - { - file << simulationGraph->isLocked(); - file.close(); - } -} - -void RealGUI::createPropertyWidget() -{ - ModifyObjectFlags modifyObjectFlags = ModifyObjectFlags(); - modifyObjectFlags.setFlagsForSofa(); - - propertyWidget = new QDisplayPropertyWidget(modifyObjectFlags); - - QDockWidget *dockProperty=new QDockWidget(this); - - dockProperty->setAllowedAreas(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea); - dockProperty->setMaximumSize(QSize(300,300)); - dockProperty->setWidget(propertyWidget); - - connect(dockProperty, SIGNAL(dockLocationChanged(QDockWidget::DockWidgetArea)), - this, SLOT(propertyDockMoved(QDockWidget::DockWidgetArea))); - simulationGraph->setPropertyWidget(propertyWidget); -} - -//------------------------------------ - -void RealGUI::createWindowVisitor() -{ - pathDumpVisitor = SetDirectory::GetParentDir(DataRepository.getFirstPath().c_str()) + std::string( "/dumpVisitor.xml" ); -#ifndef SOFA_DUMP_VISITOR_INFO - //Remove option to see visitor trace - this->exportVisitorCheckbox->hide(); -#else - //Main window containing a QListView only - windowTraceVisitor = new WindowVisitor(this); - windowTraceVisitor->graphView->setSortingEnabled(false); - windowTraceVisitor->hide(); - connect ( exportVisitorCheckbox, SIGNAL ( toggled ( bool ) ), this, SLOT ( setExportVisitor ( bool ) ) ); - connect(windowTraceVisitor, SIGNAL(WindowVisitorClosed(bool)), this->exportVisitorCheckbox, SLOT(setChecked(bool))); - handleTraceVisitor = new GraphVisitor(windowTraceVisitor); -#endif -} - -void RealGUI::createAdvancedTimerProfilerWindow() -{ -#if SOFA_GUI_QT_HAVE_QT_CHARTS - m_windowTimerProfiler = new SofaWindowProfiler(this); - m_windowTimerProfiler->hide(); - connect( displayTimeProfiler, SIGNAL ( toggled ( bool ) ), this, SLOT ( displayProflierWindow ( bool ) ) ); - connect( m_windowTimerProfiler, SIGNAL(closeWindow(bool)), this->displayTimeProfiler, SLOT(setChecked(bool))); -#else - displayTimeProfiler->setEnabled(false); -#endif -} - -void RealGUI::newRootNode(sofa::simulation::Node* root, const char* path) -{ - const std::string filename(this->windowFilePath().toStdString()); - const std::string message="You are about to change the root node of the scene : " + filename + - "to the root node : " + std::string(path) + - "\nThis implies that the simulation singleton has to change its root node.\nDo you want to proceed ?"; - if ( QMessageBox::warning ( this, "New root node: ",message.c_str(), QMessageBox::Yes | QMessageBox::Default, QMessageBox::No ) != QMessageBox::Yes ) - return; - - if(path != nullptr && root != nullptr) - { - getViewer()->setScene(root , path); - getViewer()->load(); - getViewer()->resetView(); - - getSofaViewer()->getQWidget()->update(); - statWidget->CreateStats(root); - } -} - -//------------------------------------ - -void RealGUI::activateNode(sofa::simulation::Node* node, bool activate) -{ - const QSofaListView* sofalistview = (QSofaListView*)sender(); - - if (activate) - node->setActive(true); - simulation::DeactivationVisitor v(sofa::core::execparams::defaultInstance(), activate); - node->executeVisitor(&v); - - using core::objectmodel::BaseNode; - std::list< BaseNode* > nodeToProcess; - nodeToProcess.push_front((BaseNode*)node); - - std::list< BaseNode* > nodeToChange; - //Breadth First approach to activate all the nodes - while (!nodeToProcess.empty()) - { - //We take the first element of the list - Node* n= (Node*)nodeToProcess.front(); - nodeToProcess.pop_front(); - nodeToChange.push_front(n); - //We add to the list of node to process all its children - for(Node::ChildIterator it = n->child.begin(), itend = n->child.end(); it != itend; ++it) - nodeToProcess.push_back(it->get()); - } - - const ActivationFunctor activator( activate, sofalistview->getListener() ); - std::for_each(nodeToChange.begin(),nodeToChange.end(),activator); - nodeToChange.clear(); - update(); - - if ( sofalistview == simulationGraph && activate ) - { - if (node == currentSimulation()) - { - sofa::simulation::node::initRoot(node); - } - else - { - sofa::simulation::node::init(node); - } - } -} - -//------------------------------------ - -void RealGUI::setSleepingNode(sofa::simulation::Node* node, bool sleeping) -{ - node->setSleeping(sleeping); -} - -//------------------------------------ - -void RealGUI::lockAnimation(bool value) -{ - if(value) - { - m_animationState = startButton->isChecked(); - playpauseGUI(false); - } - else - { - playpauseGUI(m_animationState); - } -} - -//------------------------------------ - -void RealGUI::fileRecentlyOpened(QAction *action) -{ - //fileOpen(recentlyOpenedFilesManager.getFilename((unsigned int)id)); - fileOpen(action->text().toStdString()); -} - -//------------------------------------ - -void RealGUI::playpauseGUI ( bool startSimulation ) -{ - startButton->setChecked ( startSimulation ); - - /// If there is no root node we do nothing. - Node* root = currentSimulation(); - if (root==nullptr) - return; - - /// Set the animation 'on' in the getContext() - currentSimulation()->getContext()->setAnimate ( startSimulation ); - - if(startSimulation) - { - SimulationStopEvent startEvt; - root->propagateEvent(core::execparams::defaultInstance(), &startEvt); - m_clockBeforeLastStep = 0; - timerStep->start(0); - return; - } - - SimulationStartEvent stopEvt; - root->propagateEvent(core::execparams::defaultInstance(), &stopEvt); - - timerStep->stop(); - return; -} - -//------------------------------------ - -void RealGUI::interactionGUI ( bool ) -{ -} - - -//------------------------------------ - -//called at each step of the rendering -void RealGUI::step() -{ - SIMULATION_LOOP_SCOPE - sofa::helper::AdvancedTimer::begin("Animate"); - - Node* root = currentSimulation(); - if ( root == nullptr ) return; - - startDumpVisitor(); - - if ( !getViewer()->ready() ) return; - - //root->setLogTime(true); - - // If dt is zero, the actual value of dt will be taken from the graph. - double dt = 0.0; - if (realTimeCheckBox->isChecked() && startButton->isChecked()) - { - const clock_t currentClock = clock(); - // If animation has already started - if (m_clockBeforeLastStep != 0) - { - // then dt <- "time since last step" - dt = (double)(currentClock - m_clockBeforeLastStep) / CLOCKS_PER_SEC; - // dt = std::min(dt, dtEdit->text().toDouble()); - } - m_clockBeforeLastStep = currentClock; - } - - sofa::simulation::node::animate(root, dt); - sofa::simulation::node::updateVisual(root); - - if ( m_dumpState ) - sofa::simulation::node::dumpState ( root, *m_dumpStateStream ); - if ( m_exportGnuplot ) - exportGnuplot(root,gnuplotDirectory); - - getViewer()->wait(); - - eventNewStep(); - eventNewTime(); - - if ( m_animateOBJ ) - { -#ifdef CAPTURE_PERIOD - static int counter = 0; - if ( ( counter++ % CAPTURE_PERIOD ) ==0 ) -#endif - { - exportOBJ ( currentSimulation(), false ); - ++m_animationOBJcounter; - } - } - - stopDumpVisitor(); - emit newStep(); - if ( !currentSimulation()->getContext()->getAnimate() ) - startButton->setChecked ( false ); - -#if SOFA_GUI_QT_HAVE_QT_CHARTS - if (displayTimeProfiler->isChecked()) - { - m_windowTimerProfiler->pushStepData(); - } -#endif - - sofa::helper::AdvancedTimer::end("Animate"); -} - -//------------------------------------ - -void RealGUI::updateDtEditState() -{ - dtEdit->setEnabled(!realTimeCheckBox->isChecked()); -} - -void RealGUI::setDt(const QString& value) -{ - const double dt = value.toDouble(); - // Input is validated, but value may be 0 anywway, while it is being entered. - if (dt > 0.0) - currentSimulation()->getContext()->setDt(dt); -} - -//------------------------------------ - -// Reset the simulation to t=0 -void RealGUI::resetScene() -{ - Node* root = currentSimulation(); - startDumpVisitor(); - emit ( newScene() ); - if (root) - { - m_frameCounter=0; - - sofa::simulation::node::reset(root); - eventNewTime(); - emit newStep(); - } - getViewer()->getPickHandler()->reset(); - stopDumpVisitor(); -} - -//------------------------------------ - -void RealGUI::screenshot() -{ - QString filename; - - const bool pngSupport = helper::io::Image::FactoryImage::getInstance()->hasKey("png") - || helper::io::Image::FactoryImage::getInstance()->hasKey("PNG"); - const bool bmpSupport = helper::io::Image::FactoryImage::getInstance()->hasKey("bmp") - || helper::io::Image::FactoryImage::getInstance()->hasKey("BMP"); - - if(!pngSupport && !bmpSupport) - { - QMessageBox::warning(this, tr("runSofa"), - tr("Screenshot is not available (PNG or BMP support not found).\n"), - QMessageBox::Cancel); - return; - } - std::string imageString = "Images (*.bmp)"; - if(pngSupport) - imageString = "Images (*.png)"; - - filename = getSaveFileName ( this, - getViewer()->screenshotName().c_str(), - imageString.c_str(), - "save file dialog" - "Choose a filename to save under" - ); - - viewer::SofaViewer* sofaViewer = getSofaViewer(); - if( sofaViewer ) - sofaViewer->getQWidget()->repaint(); - - if ( filename != "" ) - { - QString prefix; - const int end = filename.lastIndexOf('_'); - if (end > -1) { - prefix = filename.mid( - 0, - end+1 - ); - } else { - prefix = QString::fromStdString( - SetDirectory::GetFileNameWithoutExtension(filename.toStdString().c_str()) + "_"); - } - - if (!prefix.isEmpty()) - getViewer()->setPrefix ( prefix.toStdString(), false ); - - getViewer()->screenshot ( filename.toStdString() ); - } -} - -//------------------------------------ - -void RealGUI::showhideElements() -{ - displayFlag->updateDataValue(); - getSofaViewer()->getQWidget()->update(); -} - -//------------------------------------ - -void RealGUI::update() -{ - getSofaViewer()->getQWidget()->update(); - statWidget->CreateStats(currentSimulation()); -} - -//------------------------------------ - -void RealGUI::updateBackgroundColour() -{ - if(getViewer()) - getViewer()->setBackgroundColour(background[0]->text().toFloat(),background[1]->text().toFloat(),background[2]->text().toFloat()); - - getSofaViewer()->getQWidget()->update(); -} - -//------------------------------------ - -void RealGUI::updateBackgroundImage() -{ - if(getViewer()) - getViewer()->setBackgroundImage( backgroundImage->text().toStdString() ); - - getSofaViewer()->getQWidget()->update(); -} - -//------------------------------------ - -void RealGUI::clear() -{ - simulationGraph->setRoot(currentSimulation()); - statWidget->CreateStats(currentSimulation()); -} - -//---------------------------------- - -void RealGUI::redraw() -{ - emit newStep(); -} - -//------------------------------------ - -void RealGUI::exportOBJ (simulation::Node* root, bool exportMTL ) -{ - if ( !root ) return; - - SCOPED_TIMER_VARNAME(exportOBJTimer, "exportOBJ"); - - const std::string sceneFileName(this->windowFilePath ().toStdString()); - std::ostringstream ofilename; - if ( !sceneFileName.empty() ) - { - const char* begin = sceneFileName.c_str(); - const char* end = strrchr ( begin,'.' ); - if ( !end ) end = begin + sceneFileName.length(); - ofilename << std::string ( begin, end ); - } - else - ofilename << "scene"; - - std::stringstream oss; - oss.width ( 5 ); - oss.fill ( '0' ); - oss << m_animationOBJcounter; - - ofilename << '_' << ( oss.str().c_str() ); - ofilename << ".obj"; - const std::string filename = ofilename.str(); - std::cout << "Exporting OBJ Scene "<execute( v ); - exportGnuplot(root,gnuplotDirectory); - } -} - -//------------------------------------ - -#ifdef SOFA_DUMP_VISITOR_INFO -void RealGUI::setExportVisitor ( bool exp ) -{ - if (exp) - { - windowTraceVisitor->show(); - handleTraceVisitor->clear(); - } - else - { - windowTraceVisitor->hide(); - } -} -#else -void RealGUI::setExportVisitor ( bool ) -{ -} -#endif - -void RealGUI::displayProflierWindow (bool value) -{ -#if SOFA_GUI_QT_HAVE_QT_CHARTS - if (m_windowTimerProfiler == nullptr) - return; - - m_windowTimerProfiler->activateATimer(value); - if (value) - m_windowTimerProfiler->show(); - else - m_windowTimerProfiler->hide(); -#else - SOFA_UNUSED(value); -#endif -} - - -//------------------------------------ - -void RealGUI::currentTabChanged ( int index ) -{ - QWidget* widget = tabs->widget(index); - - if ( widget == currentTab ) return; - - if ( currentTab == nullptr ) - currentTab = widget; - - if ( widget == TabGraph ) - simulationGraph->update(); - else if (widget == TabStats) - statWidget->CreateStats(currentSimulation()); - - currentTab = widget; -} - -//------------------------------------ - -void RealGUI::changeViewer() -{ - QObject* obj = const_cast( QObject::sender() ); - if( !obj) return; - - QAction* action = static_cast(obj); - action->setChecked(true); - - std::map< helper::SofaViewerFactory::Key, QAction* >::const_iterator iter_map; - for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end(); ++iter_map ) - { - if ( iter_map->second == action ) - { - this->unloadScene(); - removeViewer(); - createViewer(iter_map->first.c_str()); - } - else - { - (*iter_map).second->setChecked(false); - } - } - - // Reload the scene - const std::string filename(this->windowFilePath().toStdString()); - fileOpen ( filename.c_str() ); // keep the current display flags -} - -//------------------------------------ - -void RealGUI::updateViewerList() -{ - // the current list of viewer key with associate QAction - type::vector< helper::SofaViewerFactory::Key > currentKeys; - std::map< helper::SofaViewerFactory::Key, QAction*>::const_iterator iter_map; - for ( iter_map = viewerMap.begin(); iter_map != viewerMap.end(); ++iter_map ) - currentKeys.push_back((*iter_map).first); - std::sort(currentKeys.begin(),currentKeys.end()); - - // the new list (most recent since we load/unload viewer plugin) - type::vector< helper::SofaViewerFactory::Key > updatedKeys; - helper::SofaViewerFactory::getInstance()->uniqueKeys(std::back_inserter(updatedKeys)); - std::sort(updatedKeys.begin(),updatedKeys.end()); - - type::vector< helper::SofaViewerFactory::Key > diffKeys; - std::set_symmetric_difference(currentKeys.begin(), - currentKeys.end(), - updatedKeys.begin(), - updatedKeys.end(), - std::back_inserter(diffKeys) - ); - - bool viewerRemoved=false; - type::vector< helper::SofaViewerFactory::Key >::const_iterator it; - for( it = diffKeys.begin(); it != diffKeys.end(); ++it) - { - // delete old - std::map< helper::SofaViewerFactory::Key, QAction* >::iterator itViewerMap; - if( (itViewerMap = viewerMap.find(*it)) != viewerMap.end() ) - { - if( (*itViewerMap).second->isChecked() ) - { - this->unloadScene(); - removeViewer(); - viewerRemoved = true; - } - //(*itViewerMap).second->disconnect(View); - View->removeAction( (*itViewerMap).second); - viewerMap.erase(itViewerMap); - } - else // add new - { - QAction* action = new QAction(this); - action->setText( helper::SofaViewerFactory::getInstance()->getViewerName(*it) ); - //action->setMenuText( helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*it) ); - action->setToolTip( helper::SofaViewerFactory::getInstance()->getAcceleratedViewerName(*it) ); - - //action->setToggleAction(true); - action->setCheckable(true); - - - //action->addTo(View); - View->addAction(action); - - viewerMap[*it] = action; - action->setEnabled(true); - connect(action, SIGNAL( triggered() ), this, SLOT( changeViewer() ) ); - } - } - - // if we unloaded a viewer plugin actually in use - if( viewerRemoved && !viewerMap.empty() ) - { - createViewer(viewerMap.begin()->first.c_str()); - viewerMap.begin()->second->setChecked(true); - } -} - -void RealGUI::toolsDockMoved() -{ - QDockWidget* dockWindow = qobject_cast(sender()); - if(!dockWindow) - return; - - if(dockWindow->isFloating()) - dockWindow->resize(500, 700); -} - -void RealGUI::propertyDockMoved(Qt::DockWidgetArea /*a*/) -{ - QDockWidget* dockWindow = qobject_cast(sender()); - if(!dockWindow) - return; - - if(dockWindow->isFloating()) - dockWindow->resize(500, 700); -} - -namespace -{ - -std::string getFormattedLocalTimeFromTimestamp(time_t timestamp) -{ - const tm *timeinfo = localtime(×tamp); - std::ostringstream oss; - oss << std::setfill('0') - << std::setw(2) << timeinfo->tm_mday << "/" // Day - << std::setw(2) << (timeinfo->tm_mon + 1) << "/" // Month - << std::setw(4) << (1900 + timeinfo->tm_year) << " " // Year - << std::setw(2) << timeinfo->tm_hour << ":" // Hours - << std::setw(2) << timeinfo->tm_min << ":" // Minutes - << std::setw(2) << timeinfo->tm_sec; // Seconds - return oss.str(); -} - -std::string getFormattedLocalTime() -{ - return getFormattedLocalTimeFromTimestamp( time( nullptr ) ); -} - -} // namespace - -//------------------------------------ -void RealGUI::appendToDataLogFile(QString dataModifiedString) -{ - const std::string filename = this->windowFilePath().toStdString() + std::string(".log"); - - std::ofstream ofs( filename.c_str(), std::ofstream::out | std::ofstream::app ); - - if (ofs.good()) - { - if (m_modifiedLogFiles.find(filename) == m_modifiedLogFiles.end()) - { - ofs << std::endl << "--- NEW SESSION: " << getFormattedLocalTime() << " ---" << std::endl; - m_modifiedLogFiles.insert(filename); - } - - ofs << dataModifiedString.toStdString(); - } - - ofs.close(); -} - -//======================= SIGNALS-SLOTS ========================= } - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.h b/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.h deleted file mode 100644 index ae82e9f131e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/RealGUI.h +++ /dev/null @@ -1,437 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include - -#include -#include "GraphListenerQListView.h" -#include "QMenuFilesRecentlyOpened.h" -#include "AboutSOFADialog.h" -#include "PickHandlerCallBacks.h" - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -class WDoubleLineEdit; -class QDragEnterEvent; - -namespace sofa::gui::qt -{ -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) -class DocBrowser ; -#endif - -//enum TYPE{ NORMAL, PML, LML}; -enum SCRIPT_TYPE { PHP, PERL }; - -class QSofaListView; -class QDisplayPropertyWidget; -class QSofaStatWidget; -class GraphListenerQListView; -class DisplayFlagsDataWidget; -class SofaPluginManager; -#ifdef SOFA_DUMP_VISITOR_INFO -class WindowVisitor; -class GraphVisitor; -#endif - -class SofaMouseManager; - -#if SOFA_GUI_QT_HAVE_QT_CHARTS -class SofaWindowProfiler; -#endif - -#if SOFA_GUI_QT_HAVE_NODEEDITOR -class SofaWindowDataGraph; -#endif - -namespace viewer -{ -class SofaViewer; -} - - -class SOFA_GUI_QT_API RealGUI : public QMainWindow, public Ui::GUI, public sofa::gui::common::BaseGUI -{ - Q_OBJECT - -//-----------------STATIC METHODS------------------------{ -public: - static void setupSurfaceFormat(); - static common::BaseGUI* CreateGUI(const char* name, sofa::simulation::Node::SPtr groot = nullptr, const char* filename = nullptr); - - static void SetPixmap(std::string pixmap_filename, QPushButton* b); - -protected: - static void CreateApplication(int _argc=0, char** _argv=nullptr); - static void InitApplication( RealGUI* _gui); -//-----------------STATIC METHODS------------------------} - - - -//-----------------CONSTRUCTOR - DESTRUCTOR ------------------------{ -public: - RealGUI( const char* viewername); - - ~RealGUI() override; -//-----------------CONSTRUCTOR - DESTRUCTOR ------------------------} - - - -//-----------------OPTIONS DEFINITIONS------------------------{ -//public: - -#ifdef SOFA_DUMP_VISITOR_INFO - void setTraceVisitors(bool) override; -#endif - - void showFPS(double fps) override; - -protected: - QLabel* fpsLabel; - QLabel* timeLabel; - - -private: - -#ifdef SOFA_DUMP_VISITOR_INFO - WindowVisitor* windowTraceVisitor; - GraphVisitor* handleTraceVisitor; -#endif - SofaMouseManager* m_sofaMouseManager; -#if SOFA_GUI_QT_HAVE_QT_CHARTS - SofaWindowProfiler* m_windowTimerProfiler; -#endif - -#if SOFA_GUI_QT_HAVE_NODEEDITOR - SofaWindowDataGraph* m_sofaWindowDataGraph; -#endif -//-----------------OPTIONS DEFINITIONS------------------------} - - - -//-----------------DATAS MEMBER------------------------{ -public: - //TODO: make a protected data with an accessor - QSofaListView* simulationGraph; - -protected: - bool m_dumpState; - std::ofstream* m_dumpStateStream; - std::ostringstream m_dumpVisitorStream; - bool m_exportGnuplot; - bool m_animateOBJ; - int m_animationOBJcounter;// save a succession of .obj indexed by _animationOBJcounter - bool m_displayComputationTime; - bool m_fullScreen; - sofa::gui::qt::viewer::SofaViewer* m_viewer; - // Clock before the last simulation step (or zero if the - // simulation hasn't run yet). - clock_t m_clockBeforeLastStep; - - // Component Properties - QDisplayPropertyWidget* propertyWidget; - - /// list of all viewer key name (for creation) mapped to its QAction in the GUI - std::map< helper::SofaViewerFactory::Key, QAction* > viewerMap; - InformationOnPickCallBack informationOnPickCallBack; - - QWidget* currentTab; - QSofaStatWidget* statWidget; - QTimer* timerStep; - QTimer* timerIdle; - WDoubleLineEdit *background[3]; - QLineEdit *backgroundImage; - SofaPluginManager* pluginManagerDialog; - QMenuFilesRecentlyOpened recentlyOpenedFilesManager; - - std::string simulationName; - std::string gnuplotDirectory; - std::string pathDumpVisitor; - - /// Keep track of log files that have been modified since the GUI started - std::set m_modifiedLogFiles; - - bool m_enableInteraction {false}; -private: - //currently unused: scale is experimental - float m_objectScale[2]; - bool m_saveReloadFile; - DisplayFlagsDataWidget* displayFlag {nullptr}; -#if(SOFA_GUI_QT_HAVE_QT5_WEBENGINE) - DocBrowser* m_docbrowser {nullptr}; -#endif - bool m_animationState; - int m_frameCounter; - unsigned int m_viewerMSAANbSampling; -//-----------------DATAS MEMBER------------------------} - - - -//-----------------METHODS------------------------{ -public: - void stepMainLoop () override; - - int mainLoop() override; - int closeGUI() override; - sofa::simulation::Node* currentSimulation() override; - virtual void fileOpen(std::string filename, bool temporaryFile=false, bool reload=false); - - // virtual void fileOpen(); - virtual void fileOpenSimu(std::string filename); - virtual void setScene(Node::SPtr groot, const char* filename=nullptr, bool temporaryFile=false) override; - virtual void setSceneWithoutMonitor(Node::SPtr groot, const char* filename=nullptr, bool temporaryFile=false); - - virtual void unloadScene(bool _withViewer = true); - - virtual void setTitle( std::string windowTitle ); - - void setViewerResolution(int w, int h) override; - void setFullScreen() override { setFullScreen(true); } - virtual void setFullScreen(bool enable); - void centerWindow() override; - void setBackgroundColor(const sofa::type::RGBAColor& c) override; - virtual void setBackgroundImage(const std::string& i) override; - void setViewerConfiguration(sofa::component::setting::ViewerSetting* viewerConf) override; - void setMouseButtonConfiguration(sofa::component::setting::MouseButtonSetting *button) override; - - //Configuration methods - void setDumpState(bool) override; - void setLogTime(bool) override; - void setExportState(bool) override; - virtual void setGnuplotPath(const std::string & path) override; - - /// create a viewer according to the argument key - /// \note the viewerMap have to be initialize at least once before - /// \arg _updateViewerList is used only if you want to reactualise the viewerMap in the GUI - /// TODO: find a better way to propagate the argument when we construct the viewer - virtual void createViewer(const char* _viewerName, bool _updateViewerList=false); - - /// Used to directly replace the current viewer - void registerViewer(common::BaseViewer* _viewer) override; - - common::BaseViewer* getViewer() override; - - /// A way to know if our viewer is embedded or not... (see initViewer) - /// TODO: Find a better way to do this - sofa::gui::qt::viewer::SofaViewer* getSofaViewer(); - - virtual void removeViewer(); - - void dragEnterEvent( QDragEnterEvent* event) override; - - void dropEvent(QDropEvent* event) override; - -protected: - /// init data member from RealGUI for the viewer initialisation in the GUI - void init(); - void createDisplayFlags(Node::SPtr root); - void loadSimulation(bool one_step=false); //? where is the implementation ? - void eventNewStep(); - void eventNewTime(); - void keyPressEvent ( QKeyEvent * e ) override; - void startDumpVisitor(); - void stopDumpVisitor(); - - /// init the viewer for the GUI (embedded or not we have to connect some info about viewer in the GUI) - void initViewer(common::BaseViewer* _viewer) override; - - virtual int exitApplication(unsigned int _retcode = 0) - { - return _retcode; - } - - void sleep(float seconds, float init_time) - { - [[maybe_unused]] unsigned int t = 0; - const clock_t goal = (clock_t) (seconds + init_time); - while (goal > clock()/(float)CLOCKS_PER_SEC) t++; - } - - sofa::simulation::Node::SPtr mSimulation; - - sofa::helper::system::FileEventListener* m_filelistener {nullptr}; -private: - void addViewer();//? where is the implementation ? - - /// Parse options from the RealGUI constructor - void parseOptions(); - - void createPluginManager(); - void createSofaWindowDataGraph(); - - /// configure Recently Opened Menu - void createRecentFilesMenu(); - - void createBackgroundGUIInfos(); - void createSimulationGraph(); - void createPropertyWidget(); - void createWindowVisitor(); - void createAdvancedTimerProfilerWindow(); - -public slots: - virtual void newRootNode(sofa::simulation::Node* root, const char* path); - virtual void activateNode(sofa::simulation::Node* , bool ); - virtual void setSleepingNode(sofa::simulation::Node*, bool); - virtual void lockAnimation(bool); - virtual void fileRecentlyOpened(QAction * action); - virtual void playpauseGUI(bool value); - virtual void interactionGUI(bool value); - virtual void step(); - virtual void emitIdle(); - // virtual void setDt(double); - virtual void setDt(const QString&); - // Disable dtEdit when realTimeCheckBox is checked - virtual void updateDtEditState(); - virtual void resetScene(); - virtual void screenshot(); - virtual void showhideElements(); - virtual void update(); - virtual void updateBackgroundColour(); - virtual void updateBackgroundImage(); - - // Propagate signal to call viewer method in case of it is not a widget - virtual void resetView() {if(getViewer())getViewer()->resetView(); } - virtual void saveView() {if(getViewer())getViewer()->saveView(); } - virtual void setSizeW ( int _valW ) {if(getViewer())getViewer()->setSizeW(_valW); } - virtual void setSizeH ( int _valH ) {if(getViewer())getViewer()->setSizeH(_valH); } - - virtual void clear(); - /// refresh the visualization window - void redraw() override; - virtual void exportOBJ(sofa::simulation::Node* node, bool exportMTL=true); - virtual void dumpState(bool); - virtual void displayComputationTime(bool); - virtual void setExportGnuplot(bool); - virtual void setExportVisitor(bool); - virtual void displayProflierWindow(bool); - virtual void currentTabChanged(int index); - - virtual void popupOpenFileSelector(); - virtual void fileReload(); - virtual void fileExit(); - virtual void helpAbout() { /* TODO */ } - virtual void editRecordDirectory(); - virtual void editGnuplotDirectory(); - virtual void showDocBrowser() ; - virtual void showAbout() ; - virtual void showPluginManager(); - virtual void showMouseManager(); - virtual void showVideoRecorderManager(); - virtual void showWindowDataGraph(); - virtual void toolsDockMoved(); - -protected slots: - /// Allow to dynamically change viewer. Called when click on another viewer in GUI Qt viewer list (see viewerMap). - /// TODO: find a better way to propagate the argument when we construct the viewer - virtual void changeViewer(); - - /// Update the viewerMap and create viewer if we haven't yet one (the first of the list) - /// TODO: find a better way to propagate the argument when we construct the viewer - virtual void updateViewerList(); - - /// Update the scenegraph and activate the automatic refresh. - virtual void onSceneGraphRefreshButtonClicked(); - - /// Update the SceneGraph update button to reflect the dirtiness status. - virtual void sceneGraphViewDirtynessChanged(bool isDirty); - - /// Update the SceneGraph update button to reflect the locking status. - virtual void sceneGraphViewLockingChanged(bool isLocked); - - void propertyDockMoved(Qt::DockWidgetArea a); - - void appendToDataLogFile(QString); - - void docBrowserVisibilityChanged(bool) ; - -signals: - void reload(); - void newScene(); - void newStep(); - void quit(); -//-----------------SIGNALS-SLOTS------------------------} - -}; - - - - - -struct ActivationFunctor -{ - ActivationFunctor(bool act, GraphListenerQListView* l):active(act), listener(l) - { - pixmap_filename= std::string("textures/media-record.png"); - if ( sofa::helper::system::DataRepository.findFile ( pixmap_filename ) ) - pixmap_filename = sofa::helper::system::DataRepository.getFile ( pixmap_filename ); - } - void operator()(core::objectmodel::BaseNode* n) - { - if (active) - { - //Find the corresponding node in the Qt Graph - QTreeWidgetItem *item=listener->items[n]; - //Remove the text - QString desact_text = item->text(0); - desact_text.remove(QString("Deactivated "), Qt::CaseInsensitive); - item->setText(0,desact_text); - //Remove the icon - const QPixmap *p = getPixmap(n, false,false, false); - item->setIcon(0, QIcon(*p)); -// item->setOpen(true); - item->setExpanded(true); - } - else - { - //Find the corresponding node in the Qt Graph - QTreeWidgetItem *item=listener->items[n]; - //Remove the text - item->setText(0, QString("Deactivated ") + item->text(0)); - item->setIcon(0, QIcon(QPixmap::fromImage(QImage(pixmap_filename.c_str())))); - - item->setExpanded(false); - } - } -protected: - std::string pixmap_filename; - bool active; - GraphListenerQListView* listener; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp deleted file mode 100644 index 0cca21cc8c3..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "SimpleDataWidget.h" -#include -#include -#include - -namespace sofa::gui::qt -{ - -using sofa::helper::Creator; -using sofa::type::fixed_array; -using namespace sofa::type; -using namespace sofa::defaulttype; - -Creator > DWClass_bool("default",true); -Creator > DWClass_char("default",true); -Creator > DWClass_uchar("default",true); -Creator > DWClass_int("default",true); -Creator > DWClass_uint("default",true); -Creator > DWClass_float("default",true); -Creator > DWClass_double("default",true); -Creator > DWClass_string("default",true); - - - -Creator > > DWClass_Vec1i("default",true); -Creator > > DWClass_Vec1u("default",true); -Creator > > DWClass_Vec1f("default",true); -Creator > > DWClass_Vec1d("default",true); -Creator > > DWClass_Vec2i("default",true); -Creator > > DWClass_Vec2u("default",true); -Creator > > DWClass_Vec2f("default",true); -Creator > > DWClass_Vec2d("default",true); -Creator > > DWClass_Vec3i("default",true); -Creator > > DWClass_Vec3u("default",true); -Creator > > DWClass_Vec3f("default",true); -Creator > > DWClass_Vec3d("default",true); -Creator > > DWClass_Vec4i("default",true); -Creator > > DWClass_Vec4u("default",true); -Creator > > DWClass_Vec4f("default",true); -Creator > > DWClass_Vec4d("default",true); -Creator > > DWClass_Vec6i("default",true); -Creator > > DWClass_Vec6u("default",true); -Creator > > DWClass_Vec6f("default",true); -Creator > > DWClass_Vec6d("default",true); -Creator > > DWClass_Vec8i("default",true); -Creator > > DWClass_Vec8u("default",true); - -Creator > > DWClass_fixed_array1i("default",true); -Creator > > DWClass_fixed_array1u("default",true); -Creator > > DWClass_fixed_array2i("default",true); -Creator > > DWClass_fixed_array2u("default",true); -Creator > > DWClass_fixed_array3i("default",true); -Creator > > DWClass_fixed_array3u("default",true); -Creator > > DWClass_fixed_array4i("default",true); -Creator > > DWClass_fixed_array4u("default",true); -Creator > > DWClass_fixed_array6i("default",true); -Creator > > DWClass_fixed_array6u("default",true); -Creator > > DWClass_fixed_array8i("default",true); -Creator > > DWClass_fixed_array8u("default",true); - -Creator > DWClass_Edge ("default",true); -Creator > DWClass_Triangle ("default",true); -Creator > DWClass_Quad ("default",true); -Creator > DWClass_Tetrahedron("default",true); -Creator > DWClass_Hexahedron ("default",true); - -Creator > > DWClass_fixed_array1f("default",true); -Creator > > DWClass_fixed_array1d("default",true); -Creator > > DWClass_fixed_array2f("default",true); -Creator > > DWClass_fixed_array2d("default",true); -Creator > > DWClass_fixed_array3f("default",true); -Creator > > DWClass_fixed_array3d("default",true); -Creator > > DWClass_fixed_array4f("default",true); -Creator > > DWClass_fixed_array4d("default",true); -Creator > > DWClass_fixed_array6f("default",true); -Creator > > DWClass_fixed_array6d("default",true); -Creator > > DWClass_fixed_array8f("default",true); -Creator > > DWClass_fixed_array8d("default",true); - -Creator > > DWClass_Quatf("default",true); -Creator > > DWClass_Quatd("default",true); - - -using sofa::helper::Polynomial_LD; -Creator > >DWClass_PolynomialLD5d("default",true); -Creator > >DWClass_PolynomialLD4d("default",true); -Creator > >DWClass_PolynomialLD3d("default",true); -Creator > >DWClass_PolynomialLD2d("default",true); -Creator > >DWClass_PolynomialLD1d("default",true); -Creator > >DWClass_PolynomialLD5f("default",true); -Creator > >DWClass_PolynomialLD4f("default",true); -Creator > >DWClass_PolynomialLD3f("default",true); -Creator > >DWClass_PolynomialLD2f("default",true); -Creator > >DWClass_PolynomialLD1f("default",true); - -Creator > > DWClass_Mat22f("default",true); -Creator > > DWClass_Mat22d("default",true); -Creator > > DWClass_Mat23f("default",true); -Creator > > DWClass_Mat23d("default",true); -Creator > > DWClass_Mat33f("default",true); -Creator > > DWClass_Mat33d("default",true); -Creator > > DWClass_Mat34f("default",true); -Creator > > DWClass_Mat34d("default",true); -Creator > > DWClass_Mat44f("default",true); -Creator > > DWClass_Mat44d("default",true); -Creator > > DWClass_Mat66f("default",true); -Creator > > DWClass_Mat66d("default",true); -Creator > DWClass_TagSet("default",true); - - -Creator> > > DWClass_CRSCVec1f("default",true); -Creator> > > DWClass_CRSCVec2f("default",true); -Creator> > > DWClass_CRSCVec3f("default",true); -Creator> > > DWClass_CRSCVec6f("default",true); -Creator> > > DWClass_CRSCVec1d("default",true); -Creator> > > DWClass_CRSCVec2d("default",true); -Creator> > > DWClass_CRSCVec3d("default",true); -Creator> > > DWClass_CRSCVec6d("default",true); - -//////////////////////////////////////////////////////////////// -/// OptionsGroup support -//////////////////////////////////////////////////////////////// - -//these functions must be written here for effect of writeToData -Creator DWClass_OptionsGroup("default",true); - -bool RadioDataWidget::createWidgets() -{ - QVBoxLayout* layout = new QVBoxLayout(this); - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - const unsigned int LIMIT_NUM_BUTTON=4; - buttonMode=m_radiotrick.size() < LIMIT_NUM_BUTTON; - if (buttonMode) - { - buttonList=new QButtonGroup(this); - - for(unsigned int i=0; isetChecked(true); - layout->addWidget(m_radiobutton); - buttonList->addButton(m_radiobutton,i); - } - connect(buttonList, SIGNAL(buttonClicked(int)), this, SLOT(setWidgetDirty())) ; - } - else - { - comboList=new QComboBox(this); - comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - QStringList list; - for(unsigned int i=0; iinsertItems(0, list); - - comboList->setCurrentIndex(m_radiotrick.getSelectedId()); - - connect(comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); - layout->addWidget(comboList); - - } - - return true; -} -void RadioDataWidget::setDataReadOnly(bool readOnly) -{ - if (buttonMode) - { - const QList buttons = buttonList->buttons(); - for (int i = 0; i < buttons.size(); ++i) - { - buttons.at(i)->setEnabled(!readOnly); - } - } - else - { - comboList->setEnabled(!readOnly); - } -} - -void RadioDataWidget::readFromData() -{ - const sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - - if (buttonMode) - { - buttonList->button(m_radiotrick.getSelectedId())->setChecked(true); - } - else - { - comboList->setCurrentIndex(m_radiotrick.getSelectedId()); - } -} -void RadioDataWidget::writeToData() -{ - sofa::helper::OptionsGroup m_radiotrick = getData()->getValue(); - if (buttonMode) - { - m_radiotrick.setSelectedItem((unsigned int)buttonList->checkedId ()); - } - else - { - m_radiotrick.setSelectedItem((unsigned int)comboList->currentIndex()); - } - - this->getData()->setValue(m_radiotrick); -} - -Creator DWClass_SelectableItem("default",true); - -SelectableItemWidget::SelectableItemWidget(QWidget* parent, const char* name, - core::BaseData* m_data, const helper::BaseSelectableItem* item) -: TDataWidget(parent, name, m_data, item) -, m_selectableItem(item) -{} - -bool SelectableItemWidget::createWidgets() -{ - if ((Tdata && Tdata->getValueTypeString() != "SelectableItem") || - (baseData && baseData->getValueTypeString() != "SelectableItem")) - { - return false; - } - - QVBoxLayout* layout = new QVBoxLayout(this); - static constexpr unsigned int LIMIT_NUM_BUTTON = 4; - - assert(m_selectableItem); - const std::size_t nbItems = m_selectableItem->getNumberOfItems(); - m_buttonMode = nbItems < LIMIT_NUM_BUTTON; - const auto* items = m_selectableItem->getItemsData(); - - const auto getItem = [](const sofa::helper::Item* item) - { - std::stringstream ss; - ss << item->key; - if (!item->description.empty()) - { - ss << " (" << item->description << ")"; - } - return ss.str(); - }; - - if (m_buttonMode) - { - m_buttonList = new QButtonGroup(this); - - for (std::size_t i = 0; i < nbItems; i++) - { - const helper::Item* item_i = items + i; - - QRadioButton * m_radiobutton = new QRadioButton(QString(getItem(item_i).c_str()), this); - if (i == m_selectableItem->getSelectedId()) - { - m_radiobutton->setChecked(true); - } - layout->addWidget(m_radiobutton); - m_buttonList->addButton(m_radiobutton, i); - } - connect(m_buttonList, SIGNAL(buttonClicked(int)), this, SLOT(setWidgetDirty())) ; - } - else - { - m_comboList=new QComboBox(this); - m_comboList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - QStringList list; - for (std::size_t i = 0; i < nbItems; i++) - { - const helper::Item* item_i = items + i; - list << getItem(item_i).c_str(); - } - - m_comboList->insertItems(0, list); - - m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); - - connect(m_comboList, SIGNAL(activated(int)), this, SLOT(setWidgetDirty())); - layout->addWidget(m_comboList); - - } - - return true; -} - -void SelectableItemWidget::setDataReadOnly(const bool readOnly) -{ - if (m_buttonMode) - { - const QList buttons = m_buttonList->buttons(); - for (auto& button : buttons) - { - button->setEnabled(!readOnly); - } - } - else - { - m_comboList->setEnabled(!readOnly); - } -} - -void SelectableItemWidget::readFromData() -{ - if (m_buttonMode) - { - m_buttonList->button(m_selectableItem->getSelectedId())->setChecked(true); - } - else - { - m_comboList->setCurrentIndex(m_selectableItem->getSelectedId()); - } -} - -void SelectableItemWidget::writeToData() -{ - if (m_buttonMode) - { - const_cast(m_selectableItem)->setSelectedId(static_cast(m_buttonList->checkedId())); - } - else - { - const_cast(m_selectableItem)->setSelectedId(static_cast(m_comboList->currentIndex())); - } -} - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h deleted file mode 100644 index 3583f2c29a8..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h +++ /dev/null @@ -1,1031 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "DataWidget.h" -#include "ModifyObject.h" -#include -#include -//#include -#include -#include -#include -#include "WDoubleLineEdit.h" -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#if !defined(INFINITY) -#define INFINITY 9.0e10 -#endif -namespace sofa::gui::qt -{ - -using sofa::type::Quat; - -/// This class is used to specify how to graphically represent a data type, -/// by default using a simple QLineEdit -template -class data_widget_trait -{ -public: - typedef T data_type; - typedef QLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent); - w->setFocusPolicy(Qt::StrongFocus); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - std::ostringstream o; - o << d; - if (o.str() != w->text().toStdString()) - w->setText(QString(o.str().c_str())); - } - static void writeToData(Widget* w, data_type& d) - { - const std::string s = w->text().toStdString(); - std::istringstream i(s); - i >> d; - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - w->setReadOnly(readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty())); - } -}; - - - - - -/// This class is used to create and manage the GUI of a data type, -/// using data_widget_trait to know which widgets to use -template -class data_widget_container -{ -public: - typedef T data_type; - typedef data_widget_trait helper; - typedef typename helper::Widget Widget; - typedef QHBoxLayout Layout; - Widget* w; - Layout* container_layout; - data_widget_container() : w(nullptr),container_layout(nullptr) { } - - bool createLayout(DataWidget* parent) - { - if(parent->layout() != nullptr) return false; - container_layout = new QHBoxLayout(parent); - //parent->setLayout(container_layout); - return true; - } - - bool createLayout(QLayout* layout) - { - if(container_layout) return false; - container_layout = new QHBoxLayout(); - layout->addItem(container_layout); - return true; - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool readOnly) - { - w = helper::create(parent,d); - if (w == nullptr) return false; - - helper::readFromData(w, d); - if (readOnly) - helper::setReadOnly(w, readOnly); - else - helper::connectChanged(w, parent); - return true; - } - void setReadOnly(bool readOnly) - { - if(w){ - w->setEnabled(!readOnly); - helper::setReadOnly(w, readOnly); - } - } - void readFromData(const data_type& d) - { - helper::readFromData(w, d); - } - void writeToData(data_type& d) - { - helper::writeToData(w, d); - } - - void insertWidgets() - { - assert(w); - container_layout->addWidget(w); - } -}; - -/// This class manages the GUI of a BaseData, using the corresponding instance of data_widget_container -template > -class SimpleDataWidget : public TDataWidget -{ - -protected: - typedef T data_type; - Container container; - typedef data_widget_trait helper; - - -public: - typedef sofa::core::objectmodel::Data MyTData; - SimpleDataWidget(QWidget* parent,const char* name, MyTData* d): - TDataWidget(parent,name,d) - {} - virtual bool createWidgets() - { - const data_type& d = this->getData()->getValue(); - if (!container.createWidgets(this, d, ! this->isEnabled() ) ) - return false; - - container.createLayout(this); - container.insertWidgets(); - - return true; - } - virtual void setDataReadOnly(bool readOnly) - { - container.setReadOnly(readOnly); - } - - virtual void readFromData() - { - container.readFromData(this->getData()->getValue()); - } - - virtual void setReadOnly(bool readOnly) - { - container.setReadOnly(readOnly); - } - - virtual void writeToData() - { - data_type& d = *this->getData()->beginEdit(); - container.writeToData(d); - this->getData()->endEdit(); - } - virtual unsigned int numColumnWidget() { return 5; } -}; - -//////////////////////////////////////////////////////////////// -/// std::string support -//////////////////////////////////////////////////////////////// - -template<> -class data_widget_trait < std::string > -{ -public: - typedef std::string data_type; - typedef QLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent); - w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - if (w->text().toStdString() != d) - w->setText(QString(d.c_str())); - } - static void writeToData(Widget* w, data_type& d) - { - d = w->text().toStdString(); - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - w->setReadOnly(readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty()) ); - } -}; - -//////////////////////////////////////////////////////////////// -/// bool support -//////////////////////////////////////////////////////////////// - -template<> -class data_widget_trait < bool > -{ -public: - typedef bool data_type; - typedef QCheckBox Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - if (w->isChecked() != d) - w->setChecked(d); - } - static void writeToData(Widget* w, data_type& d) - { - d = (data_type) (w->isChecked()); - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( toggled(bool) ), datawidget, SLOT(setWidgetDirty())); - } -}; - -//////////////////////////////////////////////////////////////// -/// float and double support -//////////////////////////////////////////////////////////////// - -template < typename T > -class real_data_widget_trait -{ -public: - typedef T data_type; - typedef WDoubleLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent, "real"); - - w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - w->setMinValue( (data_type)-INFINITY ); - w->setMaxValue( (data_type)INFINITY ); - w->setMinimumWidth(20); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - if (d != w->getDisplayedValue()) - w->setValue(d); - } - static void writeToData(Widget* w, data_type& d) - { - d = (data_type) w->getDisplayedValue(); - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty())); - } -}; - -template<> -class data_widget_trait < float > : public real_data_widget_trait< float > -{}; - -template<> -class data_widget_trait < double > : public real_data_widget_trait< double > -{}; - -//////////////////////////////////////////////////////////////// -/// int, unsigned int, char and unsigned char support -//////////////////////////////////////////////////////////////// - -template -class int_data_widget_trait -{ -public: - typedef T data_type; - typedef QSpinBox Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent); - w->setMinimum(vmin); - w->setMaximum(vmax); - w->setSingleStep(1); - - w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - if ((int)d != w->value()) - w->setValue((int)d); - } - static void writeToData(Widget* w, data_type& d) - { - d = (data_type) w->value(); - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( valueChanged(int) ), datawidget, SLOT(setWidgetDirty())); - } -}; - -template<> -class data_widget_trait < int > : public int_data_widget_trait < int, INT_MIN, INT_MAX > -{}; - -template<> -class data_widget_trait < unsigned int > : public int_data_widget_trait < unsigned int, 0, INT_MAX > -{}; - -template<> -class data_widget_trait < char > : public int_data_widget_trait < char, -128, 127 > -{}; - -template<> -class data_widget_trait < unsigned char > : public int_data_widget_trait < unsigned char, 0, 255 > -{}; - -//////////////////////////////////////////////////////////////// -/// arrays and vectors support -//////////////////////////////////////////////////////////////// - -/// This class is used to get properties of a data type in order to display it as a table or a list -template -class vector_data_trait -{ -public: - - typedef T data_type; - /// Type of a row if this data type is viewed in a table or list - typedef T value_type; - /// Number of dimensions of this data type - enum { NDIM = 0 }; - enum { SIZE = 1 }; - /// Get the number of rows - static Size size(const data_type&) { return SIZE; } - /// Get the name of a row, or nullptr if the index should be used instead - static const char* header(const data_type& /*d*/, Size /*i*/ = 0) - { - return nullptr; - } - /// Get a row - static const value_type* get(const data_type& d, Size i = 0) - { - return (i == 0) ? &d : nullptr; - } - /// Set a row - static void set( const value_type& v, data_type& d, Size i = 0) - { - if (i == 0) - d = v; - } - /// Resize - static void resize( Size /*s*/, data_type& /*d*/) - { - } -}; - - -template::value_type> > -class fixed_vector_data_widget_container -{ -public: - typedef T data_type; - typedef vector_data_trait vhelper; - typedef typename vhelper::value_type value_type; - typedef QHBoxLayout Layout; - enum { N = vhelper::SIZE }; - Container w[N]; - Layout* container_layout; - - fixed_vector_data_widget_container():container_layout(nullptr) {} - - bool createLayout(DataWidget* parent) - { - if(parent->layout() != nullptr) return false; - container_layout = new QHBoxLayout(parent); - return true; - } - - bool createLayout(QLayout* layout) - { - if(container_layout) return false; - container_layout = new QHBoxLayout(); - layout->addItem(container_layout); - return true; - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool readOnly) - { - for (sofa::Size i=0; iaddWidget(w[i].w); - } - } -}; - -template::value_type >::value_type> > -class fixed_grid_data_widget_container -{ -public: - - typedef T data_type; - typedef vector_data_trait rhelper; - typedef typename rhelper::value_type row_type; - typedef vector_data_trait vhelper; - typedef typename vhelper::value_type value_type; - enum { L = rhelper::SIZE }; - enum { C = vhelper::SIZE }; - typedef QGridLayout Layout; - Container w[L][C]; - Layout* container_layout; - fixed_grid_data_widget_container():container_layout(nullptr) {} - - bool createLayout(QWidget* parent) - { - if( parent->layout() != nullptr ) return false; - container_layout = new Layout(parent /*,L,C */); - return true; - } - bool createLayout(QLayout* layout) - { - if(container_layout != nullptr ) return false; - container_layout = new Layout( /*,L,C */); - layout->addItem(container_layout); - return true; - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool readOnly) - { - for (sofa::Size y=0; yaddWidget(w[y][x].w,y,x); - } - } - } -}; - -//////////////////////////////////////////////////////////////// -/// sofa::type::fixed_array support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < sofa::type::fixed_array > -{ -public: - typedef sofa::type::fixed_array data_type; - typedef T value_type; - enum { NDIM = 1 }; - enum { SIZE = N }; - static sofa::Size size(const data_type&) { return SIZE; } - static const char* header(const data_type& /*d*/, sofa::Size /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, sofa::Index i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, sofa::Index i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( sofa::Size /*s*/, data_type& /*d*/) - { - } - -}; - -template -class data_widget_container < sofa::type::fixed_array > : public fixed_vector_data_widget_container < sofa::type::fixed_array > -{}; - - -//////////////////////////////////////////////////////////////// -/// Topological edges/triangles/... support -//////////////////////////////////////////////////////////////// - -template<> -class vector_data_trait < sofa::core::topology::Topology::Edge > - : public vector_data_trait < sofa::type::fixed_array < sofa::core::topology::Topology::PointID, 2 > > -{ -}; - -template<> -class data_widget_container < sofa::core::topology::Topology::Edge > : public fixed_vector_data_widget_container < sofa::core::topology::Topology::Edge > -{}; - -template<> -class vector_data_trait < sofa::core::topology::Topology::Triangle > - : public vector_data_trait < sofa::type::fixed_array < sofa::core::topology::Topology::PointID, 3 > > -{ -}; - -template<> -class data_widget_container < sofa::core::topology::Topology::Triangle > : public fixed_vector_data_widget_container < sofa::core::topology::Topology::Triangle > -{}; - -template<> -class vector_data_trait < sofa::core::topology::Topology::Quad > - : public vector_data_trait < sofa::type::fixed_array < sofa::core::topology::Topology::PointID, 4 > > -{ -}; - -template<> -class data_widget_container < sofa::core::topology::Topology::Quad > : public fixed_vector_data_widget_container < sofa::core::topology::Topology::Quad > -{}; - -template<> -class vector_data_trait < sofa::core::topology::Topology::Tetrahedron > - : public vector_data_trait < sofa::type::fixed_array < sofa::core::topology::Topology::PointID, 4 > > -{ -}; - -template<> -class data_widget_container < sofa::core::topology::Topology::Tetrahedron > : public fixed_vector_data_widget_container < sofa::core::topology::Topology::Tetrahedron > -{}; - -template<> -class vector_data_trait < sofa::core::topology::Topology::Hexahedron > - : public vector_data_trait < sofa::type::fixed_array < sofa::core::topology::Topology::PointID, 8 > > -{ -}; - -template<> -class data_widget_container < sofa::core::topology::Topology::Hexahedron > : public fixed_vector_data_widget_container < sofa::core::topology::Topology::Hexahedron > -{}; - -//////////////////////////////////////////////////////////////// -/// sofa::defaulttype::Vec support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < sofa::type::Vec > -{ -public: - typedef sofa::type::Vec data_type; - typedef T value_type; - typedef typename data_type::Size Size; - enum { NDIM = 1 }; - enum { SIZE = N }; - static Size size(const data_type&) { return SIZE; } - static const char* header(const data_type& /*d*/, Size /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, Size i = 0) - { - return (i < size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, Size i = 0) - { - if (i < size(d)) - d[i] = v; - } - static void resize( Size /*s*/, data_type& /*d*/) - { - } -}; - -template<> -inline const char* vector_data_trait < sofa::type::Vec<2, float> >::header(const data_type& /*d*/, Size i) -{ - switch(i) - { - case 0: return "X"; - case 1: return "Y"; - } - return nullptr; -} - -template<> -inline const char* vector_data_trait < sofa::type::Vec<2, double> >::header(const data_type& /*d*/, Size i) -{ - switch(i) - { - case 0: return "X"; - case 1: return "Y"; - } - return nullptr; -} - -template<> -inline const char* vector_data_trait < sofa::type::Vec<3, float> >::header(const data_type& /*d*/, Size i) -{ - switch(i) - { - case 0: return "X"; - case 1: return "Y"; - case 2: return "Z"; - } - return nullptr; -} - -template<> -inline const char* vector_data_trait < sofa::type::Vec<3, double> >::header(const data_type& /*d*/, Size i) -{ - switch(i) - { - case 0: return "X"; - case 1: return "Y"; - case 2: return "Z"; - } - return nullptr; -} - -template -class data_widget_container < sofa::type::Vec > : public fixed_vector_data_widget_container < sofa::type::Vec > -{}; - -//////////////////////////////////////////////////////////////// -/// std::helper::Quater support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < Quat > -{ -public: - typedef Quat data_type; - typedef T value_type; - enum { NDIM = 1 }; - enum { SIZE = 4 }; - static sofa::Size size(const data_type&) { return SIZE; } - static const char* header(const data_type& /*d*/, sofa::Index i = 0) - { - switch(i) - { - case 0: return "qX"; - case 1: return "qY"; - case 2: return "qZ"; - case 3: return "qW"; - } - return nullptr; - } - static const value_type* get(const data_type& d, sofa::Index i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, sofa::Index i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( sofa::Size /*s*/, data_type& /*d*/) - { - } -}; - -template -class data_widget_container < Quat > : public fixed_vector_data_widget_container < Quat > -{}; - - -//////////////////////////////////////////////////////////////// -/// sofa::helper::Polynomial_LD support -//////////////////////////////////////////////////////////////// -using sofa::helper::Polynomial_LD; - -template -class data_widget_trait < Polynomial_LD > -{ -public: - typedef Polynomial_LD data_type; - typedef QLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& ) - { - Widget* w = new Widget(parent); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - auto length = d.getString().length(); - if (w->text().toStdString() != d.getString()) - { - w->setMaxLength(length+2); w->setReadOnly(true); - w->setText(QString(d.getString().c_str())); - } - } - static void writeToData(Widget* , data_type& ) - { - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - w->setReadOnly(readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty()) ); - } -}; - - -#ifdef TODOLINK -//////////////////////////////////////////////////////////////// -/// sofa::core::objectmodel::ObjectRef -//////////////////////////////////////////////////////////////// - -using sofa::core::objectmodel::ObjectRef; - -template<> -class data_widget_trait < ObjectRef > -{ -public: - typedef ObjectRef data_type; - typedef QLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& d) - { - Widget* w = new Widget(parent); - w->setText(QString(d.getPath().c_str())); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - std::ostringstream _outref; _outref<text().toStdString() != _outref.str()) - w->setText(QString(_outref.str().c_str())); - } - static void writeToData(Widget* w, data_type& d) - { - bool canwrite = d.setPath ( w->text().toStdString() ); - if(!canwrite) - msg_info()<<"cannot set Path "<text().toStdString()<setReadOnly(readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty()) ); - } -}; - -//////////////////////////////////////////////////////////////// -/// support sofa::core::objectmodel::VectorObjectRef; -//////////////////////////////////////////////////////////////// - -using sofa::core::objectmodel::VectorObjectRef; -template<> -class vector_data_trait < sofa::core::objectmodel::VectorObjectRef > -{ -public: - typedef sofa::core::objectmodel::VectorObjectRef data_type; - typedef sofa::core::objectmodel::ObjectRef value_type; - - static sofa::Size size(const data_type& d) { return d.size(); } - static const char* header(const data_type& , sofa::Index i = 0) - { - std::ostringstream _header; _header< -class vector_data_trait < sofa::type::Mat > -{ -public: - typedef sofa::type::Mat data_type; - typedef typename data_type::Line value_type; - enum { NDIM = 1 }; - enum { SIZE = L }; - static sofa::Size size(const data_type&) { return SIZE; } - static const char* header(const data_type& /*d*/, sofa::Index /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, sofa::Index i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, sofa::Index i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( sofa::Size /*s*/, data_type& /*d*/) - { - } -}; - -template -class data_widget_container < sofa::type::Mat > : public fixed_grid_data_widget_container < sofa::type::Mat > -{}; - -//////////////////////////////////////////////////////////////// -/// sofa::linearalgebra::CompressedRowSparseMatrixConstraint support -//////////////////////////////////////////////////////////////// - -template -class data_widget_trait > -{ -public: - typedef sofa::linearalgebra::CompressedRowSparseMatrixConstraint data_type; - typedef QLineEdit Widget; - static Widget* create(QWidget* parent, const data_type& /*d*/) - { - Widget* w = new Widget(parent); - w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - return w; - } - static void readFromData(Widget* w, const data_type& d) - { - std::ostringstream oss; - d.prettyPrint(oss); - w->setText(QString(oss.str().c_str())); - } - static void writeToData(Widget* /* w */, const data_type& /* d */) - { - // not supported by this type - // TODO: CompressedRowSparseMatrixConstraint needs a parser for its pretty output - } - static void setReadOnly(Widget* w, bool readOnly) - { - w->setEnabled(!readOnly); - w->setReadOnly(readOnly); - } - static void connectChanged(Widget* w, DataWidget* datawidget) - { - datawidget->connect(w, SIGNAL( textChanged(const QString&) ), datawidget, SLOT(setWidgetDirty()) ); - } - -}; - -//////////////////////////////////////////////////////////////// -/// OptionsGroup support -//////////////////////////////////////////////////////////////// - - -class RadioDataWidget : public TDataWidget -{ - Q_OBJECT -public : - - ///The class constructor takes a TData since it creates - ///a widget for a that particular data type. - RadioDataWidget(QWidget* parent, const char* name, - core::objectmodel::Data* m_data) - : TDataWidget(parent,name,m_data) {} - - ///In this method we create the widgets and perform the signal / slots connections. - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - -protected: - ///Implements how update the widgets knowing the data value. - virtual void readFromData(); - - ///Implements how to update the data, knowing the widget value. - virtual void writeToData(); - - QButtonGroup *buttonList; - QComboBox *comboList; - bool buttonMode; -}; - -class SelectableItemWidget final : public TDataWidget -{ - Q_OBJECT -public : - - SelectableItemWidget(QWidget* parent, const char* name, - core::BaseData* m_data, const helper::BaseSelectableItem* item); - - bool createWidgets() override; - void setDataReadOnly(bool readOnly) override; - -protected: - void readFromData() override; - - void writeToData() override; - - QButtonGroup *m_buttonList { nullptr }; - QComboBox *m_comboList { nullptr }; - bool m_buttonMode { false }; - - const helper::BaseSelectableItem* m_selectableItem { nullptr }; -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.cpp deleted file mode 100644 index b6fb316bf2f..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaMouseManager.h" -#include -#include "QMouseOperations.h" - -#include -#include - -#include - -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ -SofaMouseManager::SofaMouseManager(QWidget *parent) - : QDialog(parent) - , gui(new Ui_MouseManager) -{ - gui->setupUi(this); - - connect( gui->LeftOperationCombo, SIGNAL(activated(int)), this, SLOT( selectOperation(int) )); - connect( gui->MiddleOperationCombo, SIGNAL(activated(int)), this, SLOT( selectOperation(int) )); - connect( gui->RightOperationCombo, SIGNAL(activated(int)), this, SLOT( selectOperation(int) )); - - RegisterOperation("Attach").add< QAttachOperation >(); - RegisterOperation("AddFrame").add< AddFrameOperation >(); - RegisterOperation("SaveCameraViewPoint").add< QAddRecordedCameraOperation >(); - RegisterOperation("StartNavigation").add< QStartNavigationOperation >(); - RegisterOperation("Fix") .add< QFixOperation >(); - RegisterOperation("Incise").add< QInciseOperation >(); - RegisterOperation("Remove").add< QTopologyOperation >(); - RegisterOperation("Suture").add< QAddSutureOperation >(); - RegisterOperation("ConstraintAttach").add< ConstraintAttachOperation >(); -} - -SofaMouseManager::~SofaMouseManager() -{ -} - -void SofaMouseManager::updateContent() -{ - gui->LeftOperationCombo->clear(); - gui->MiddleOperationCombo->clear(); - gui->RightOperationCombo->clear(); - mapIndexOperation.clear(); - - if (mapIndexOperation.empty()) - { - const OperationFactory::RegisterStorage ®istry = OperationFactory::getInstance()->registry; - - int idx=0; - for (OperationFactory::RegisterStorage::const_iterator it=registry.begin(); it!=registry.end(); ++it) - { - gui->LeftOperationCombo ->addItem(QString(OperationFactory::GetDescription(it->first).c_str())); - gui->MiddleOperationCombo->addItem(QString(OperationFactory::GetDescription(it->first).c_str())); - gui->RightOperationCombo ->addItem(QString(OperationFactory::GetDescription(it->first).c_str())); - - if (OperationFactory::GetDescription(it->first) == OperationFactory::GetDescription(usedOperations[LEFT])) - gui->LeftOperationCombo->setCurrentIndex(idx); - if (OperationFactory::GetDescription(it->first) == OperationFactory::GetDescription(usedOperations[MIDDLE])) - gui->MiddleOperationCombo->setCurrentIndex(idx); - if (OperationFactory::GetDescription(it->first) == OperationFactory::GetDescription(usedOperations[RIGHT])) - gui->RightOperationCombo->setCurrentIndex(idx); - - mapIndexOperation.insert(std::make_pair(idx++, it->first)); - } - } -} - -void SofaMouseManager::setPickHandler(PickHandler *picker) -{ - pickHandler=picker; - updateContent(); - updateOperation(LEFT, "Attach"); - updateOperation(MIDDLE, "Incise"); - updateOperation(RIGHT, "Remove"); -} - - -void SofaMouseManager::selectOperation(int operation) -{ - const QComboBox *combo = (QComboBox*)(sender()); - const std::string operationName=mapIndexOperation[operation]; - - if (combo == gui->LeftOperationCombo) updateOperation(LEFT, operationName); - else if (combo == gui->MiddleOperationCombo) updateOperation(MIDDLE, operationName); - else if (combo == gui->RightOperationCombo) updateOperation(RIGHT, operationName); -} - -void SofaMouseManager::updateOperation( sofa::component::setting::MouseButtonSetting* setting) -{ - //By changing the operation, we delete the previous operation - Operation *operation=pickHandler->changeOperation( setting); - updateOperation(operation); -} - -void SofaMouseManager::updateOperation( MOUSE_BUTTON button, const std::string &id) -{ - //By changing the operation, we delete the previous operation - Operation *operation=pickHandler->changeOperation( button, id); - updateOperation(operation); -} - - -void SofaMouseManager::updateOperation( Operation* operation) -{ - if (!operation || operation->getMouseButton()==NONE ) return; - usedOperations[operation->getMouseButton()] = operation->getId(); - - QWidget* qoperation=dynamic_cast(operation); - if (!qoperation) return; - - switch(operation->getMouseButton()) - { - case LEFT: - { - gui->LeftButton->layout()->addWidget(qoperation); - break; - } - case MIDDLE: - { - gui->MiddleButton->layout()->addWidget(qoperation); - break; - } - case RIGHT: - { - gui->RightButton->layout()->addWidget(qoperation); - break; - } - default: - { - } - } -} - -} // namespace sofa::gui::qt - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.h deleted file mode 100644 index 0a8ab1f278d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaMouseManager.h +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include - -class Ui_MouseManager; - -namespace sofa::gui::qt -{ - - -class SofaMouseManager : public QDialog -{ - Q_OBJECT - std::unique_ptr gui; -public: - - SofaMouseManager(QWidget *parent); - ~SofaMouseManager() override; - - void updateContent(); - - void setPickHandler(common::PickHandler *); - - std::map< int, std::string >& getMapIndexOperation() - { - return mapIndexOperation; - } - - void updateOperation( sofa::component::setting::MouseButtonSetting* setting); - void updateOperation(common::MOUSE_BUTTON button, const std::string &id); - - -public slots: - void selectOperation(int); - -protected: - void updateOperation(common::Operation* op); - common::PickHandler *pickHandler; - std::map< int, std::string > mapIndexOperation; - - type::fixed_array< std::string, common::NONE > usedOperations; -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.cpp deleted file mode 100644 index 6d29032d0fa..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaPluginManager.h" -#include "FileManagement.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#include -#include - -namespace sofa::gui::qt -{ - -#define LOCATION_COLUMN 3 - -SofaPluginManager::SofaPluginManager(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - // SIGNAL / SLOTS CONNECTIONS - this->connect(buttonAdd, SIGNAL(clicked() ), this, SLOT( addLibrary() )); - this->connect(buttonRemove, SIGNAL(clicked() ), this, SLOT( removeLibrary() )); - - this->connect(listPlugins, SIGNAL(itemSelectionChanged() ), this, SLOT(updateComponentList() )); - this->connect(listPlugins, SIGNAL(itemSelectionChanged() ), this, SLOT(updateDescription() )); - - listPlugins->setHeaderLabels(QStringList() << "Name" << "License" << "Version" << "Location"); - listComponents->setHeaderLabels(QStringList() << "Component list"); - - loadPluginsFromIniFile(); - updatePluginsListView(); -} - - - -void SofaPluginManager::updatePluginsListView() -{ - typedef sofa::helper::system::PluginManager::PluginMap PluginMap; - PluginMap& map = sofa::helper::system::PluginManager::getInstance().getPluginMap(); - typedef PluginMap::iterator PluginIterator; - listPlugins->clear(); - for( PluginIterator iter = map.begin(); iter != map.end(); ++iter ) - { - sofa::helper::system::Plugin& plugin = iter->second; - QString slicense = plugin.getModuleLicense(); - QString sname = plugin.getModuleName(); - QString sversion = plugin.getModuleVersion(); - QString sfile = (iter->first).c_str(); - - QTreeWidgetItem * item = new QTreeWidgetItem(listPlugins); - - if (std::find(m_loadedPlugins.begin(), m_loadedPlugins.end(), plugin.getModuleName()) != m_loadedPlugins.end() || - std::find(m_loadedPlugins.begin(), m_loadedPlugins.end(), iter->first) != m_loadedPlugins.end()) - { - for (unsigned int i = 0; i < 4; ++i) - { - item->setForeground(i, QColor::fromRgb(0, 0, 255)); - item->setToolTip(i, QString(std::string{"This plugin has been loaded by the GUI from the file " + m_pluginsIniFile}.c_str())); - } - } - - item->setText(0, sname); - item->setText(1, slicense); - item->setText(2, sversion); - item->setText(3, sfile); - //item->setSelected(true); - //listPlugins->addTopLevelItem(item); - } -} - -void SofaPluginManager::addLibrary() -{ - // compute the plugin directory path - QDir dir = QCoreApplication::applicationDirPath(); -#if defined (WIN32) - dir.cd("../bin"); -#else - dir.cd("../lib"); -#endif - QString pluginPath = dir.canonicalPath(); - //get the lib to load -#if defined (__APPLE__) - QString sfile = getOpenFileName ( this, pluginPath, "dynamic library (*.dylib*)", "load library dialog", "Choose the component library to load" ); -#elif defined (WIN32) - QString sfile = getOpenFileName ( this, pluginPath, "dynamic library (*.dll)", "load library dialog", "Choose the component library to load" ); -#else - QString sfile = getOpenFileName ( this, pluginPath, "dynamic library (*.so)", "load library dialog", "Choose the component library to load" ); -#endif - if(sfile=="") - return; -#ifndef _DEBUG - if(sfile.contains(QString("d.")) == true) - if(QMessageBox::question(this, "library loading warning","This plugin lib seems to be in debug mode whereas you are currently in release mode.\n Are you sure you want to load this lib?",QMessageBox::Yes,QMessageBox::No) != QMessageBox::Yes) - return; -#else - if(sfile.contains(QString("d.")) == false) - if(QMessageBox::question(this, "library loading warning","This plugin lib seems to be in release mode whereas you are currently in debug mode.\n Are you sure you want to load this lib?",QMessageBox::Yes,QMessageBox::No) != QMessageBox::Yes) - return; -#endif - std::stringstream sstream; - - const std::string pluginFile = std::string(sfile.toStdString()); - const auto status = sofa::helper::system::PluginManager::getInstance().loadPluginByPath(pluginFile,&sstream); - if(status == sofa::helper::system::PluginManager::PluginLoadStatus::SUCCESS) - { - typedef sofa::helper::system::Plugin Plugin; - if( ! sstream.str().empty()) - { - QMessageBox * mbox = new QMessageBox(this); - mbox->setWindowTitle("library loading warning"); - mbox->setIcon(QMessageBox::Warning); - mbox->setText(sstream.str().c_str()); - mbox->show(); - } - const Plugin* plugin = sofa::helper::system::PluginManager::getInstance().getPlugin(pluginFile); - if(!plugin) - { - // This should not happen as we are protected by if(loadPluginByPath(...)) - msg_error("SofaPluginManager") << "plugin should be loaded: " << pluginFile << msgendl; - return; - } - - if ( (plugin->moduleIsInitialized.func && plugin->moduleIsInitialized()) - || !plugin->moduleIsInitialized.func) - { - if (const char* moduleName = plugin->getModuleName()) - { - core::ObjectFactory::getInstance()->registerObjectsFromPlugin(moduleName); - } - } - - const QString slicense = plugin->getModuleLicense(); - const QString sname = plugin->getModuleName(); - const QString sversion = plugin->getModuleVersion(); - - //QTreeWidgetItem * item = new QTreeWidgetItem(listPlugins, sname, slicense, sversion, pluginFile.c_str()); - QTreeWidgetItem * item = new QTreeWidgetItem(listPlugins); - item->setText(0, sname); - item->setText(1, slicense); - item->setText(2, sversion); - item->setText(3, pluginFile.c_str()); - listPlugins->addTopLevelItem(item); - - //item->setSelectable(true); - savePluginsToIniFile(); - emit( libraryAdded() ); - } - else if (status == sofa::helper::system::PluginManager::PluginLoadStatus::ALREADY_LOADED) - { - if( !sstream.str().empty()) - { - QMessageBox * mbox = new QMessageBox(this); - mbox->setWindowTitle("library loading warning"); - mbox->setIcon(QMessageBox::Warning); - mbox->setText(sstream.str().c_str()); - mbox->show(); - } - savePluginsToIniFile(); - } - else - { - QMessageBox * mbox = new QMessageBox(this); - mbox->setWindowTitle("library loading error"); - mbox->setIcon(QMessageBox::Critical); - mbox->setText(sstream.str().c_str()); - mbox->show(); - } - - -} - - - -void SofaPluginManager::removeLibrary() -{ - //get the selected item - if(listPlugins->selectedItems().count() < 1) - return; - - const QTreeWidgetItem * curItem = listPlugins->selectedItems()[0]; - std::stringstream sstream; - if (!curItem) return; - - const std::string location( curItem->text(LOCATION_COLUMN).toStdString() ); //get the location value - - if( sofa::helper::system::PluginManager::getInstance().unloadPlugin(location,&sstream) ) - { - //listPlugins->removeItem(curItem); - delete curItem; - - savePluginsToIniFile(); - emit( libraryRemoved() ); - - if(this->listPlugins->selectedItems().count() < 1) - { - description->clear(); - listComponents->clear(); - } - } - else - { - std::string errlog; - sstream >> errlog; - QMessageBox * mbox = new QMessageBox(this); - mbox->setWindowTitle("library unloading error"); - mbox->setIcon(QMessageBox::Critical); - mbox->setText(errlog.c_str()); - mbox->show(); - } - -} - -void SofaPluginManager::updateComponentList() -{ - if(this->listPlugins->selectedItems().count() < 1) - return; - - const QTreeWidgetItem* curItem = this->listPlugins->selectedItems()[0]; - - if(curItem == nullptr ) return; - //update the component list when an item is selected - listComponents->clear(); - - const std::string location( curItem->text(LOCATION_COLUMN).toStdString() ); //get the location value - - typedef sofa::helper::system::Plugin Plugin; - const Plugin* plugin = sofa::helper::system::PluginManager::getInstance().getPlugin(location); - if(!plugin) - { - msg_warning("SofaPluginManager") << "plugin is not loaded: " << location << msgendl; - return; - } - - std::string componentListStr{}; - const char* tempComponentList = plugin->getModuleComponentList(); - - // the plugin does not implement getModuleComponentList(), or returns nothing. - if (tempComponentList == nullptr) - { - const char* pluginNameStr = plugin->getModuleName(); - componentListStr = sofa::core::ObjectFactory::getInstance()->listClassesFromTarget(pluginNameStr); - } - else - { - componentListStr = tempComponentList; - } - - QString cpts(componentListStr.data()); - cpts.replace(", ","\n"); - cpts.replace(",","\n"); - std::istringstream in(cpts.toStdString()); - - while (!in.eof()) - { - std::string componentText; - in >> componentText; - //QTreeWidgetItem *item=new QTreeWidgetItem(listComponents,curItem); - - QTreeWidgetItem * item = new QTreeWidgetItem(listComponents); - item->setText(0, componentText.c_str()); - } -} - - -void SofaPluginManager::updateDescription() -{ - if(this->listPlugins->selectedItems().count() < 1) - return; - - const QTreeWidgetItem* curItem = this->listPlugins->selectedItems()[0]; - - if(curItem == nullptr ) return; - //update the component list when an item is selected - description->clear(); - - const std::string location( curItem->text(LOCATION_COLUMN).toStdString() ); //get the location value - - typedef sofa::helper::system::Plugin Plugin; - const Plugin* plugin = sofa::helper::system::PluginManager::getInstance().getPlugin(location); - if(!plugin) - { - msg_warning("SofaPluginManager") << "plugin is not loaded: " << location << msgendl; - return; - } - description->setText(QString(plugin->getModuleDescription())); -} - -void SofaPluginManager::savePluginsToIniFile() -{ - m_pluginsIniFile = sofa::gui::common::BaseGUI::getConfigDirectoryPath() + "/loadedPlugins.ini"; - sofa::helper::system::PluginManager::getInstance().writeToIniFile(m_pluginsIniFile); -} - -void SofaPluginManager::loadPluginsFromIniFile() -{ - m_pluginsIniFile = sofa::gui::common::BaseGUI::getConfigDirectoryPath() + "/loadedPlugins.ini"; - msg_info("SofaPluginManager") << "Loading automatically plugin list in " << m_pluginsIniFile; - sofa::helper::system::PluginManager::getInstance().readFromIniFile(m_pluginsIniFile, m_loadedPlugins); - - for (const auto& loadedPlugin : m_loadedPlugins) - { - core::ObjectFactory::getInstance()->registerObjectsFromPlugin(loadedPlugin); - } -} - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.h deleted file mode 100644 index 725df093277..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaPluginManager.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include - -#include - -#include - - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API SofaPluginManager: public QDialog, public Ui_PluginManager -{ - Q_OBJECT -public: - SofaPluginManager(QWidget *parent); - - -signals: - - void libraryAdded(); - void libraryRemoved(); - -public slots: - - void addLibrary(); - void removeLibrary(); - - void updateComponentList(); - void updateDescription(); -public: - void updatePluginsListView(); -private: - void savePluginsToIniFile(); - - std::string m_pluginsIniFile; ///< path to the saved/loaded list of plugins by SofaPluginManager - type::vector m_loadedPlugins; ///< list of plugins loaded by SofaPluginManager - void loadPluginsFromIniFile(); -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.cpp deleted file mode 100644 index 788ce512f4c..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaSceneGraphWidget.h" - -namespace sofa::gui::qt -{ - -void SofaSceneGraphWidget::setViewToDirty() -{ - if(!m_isLocked) - return; - - if(m_isDirty) - return; - - m_isDirty = true; - emit dirtynessChanged(m_isDirty); -} - -bool SofaSceneGraphWidget::isDirty() -{ - return m_isDirty; -} - -bool SofaSceneGraphWidget::isLocked() -{ - return m_isLocked; -} - -void SofaSceneGraphWidget::lock() -{ - if(m_isLocked) - return; - - m_isLocked = true; - emit lockingChanged(m_isLocked); -} - -void SofaSceneGraphWidget::unLock() -{ - if(!m_isLocked) - return; - - m_isLocked = false; - - if(m_isDirty) - update(); - - emit lockingChanged(m_isLocked); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.h deleted file mode 100644 index a5b45e62e91..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaSceneGraphWidget.h +++ /dev/null @@ -1,118 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include -#include -#include -#include - - -#include -#include -#include -#include - -#include - -namespace sofa::gui::qt -{ - -class AddObject; -class GraphListenerQListView; -class QDisplayPropertyWidget; - -enum ObjectModelType { typeNode, typeObject, typeData }; -typedef union ObjectModelPtr -{ - sofa::simulation::Node* Node; - core::objectmodel::BaseObject* Object; - core::objectmodel::BaseData* Data; -} ObjectModelPtr; - -typedef struct ObjectModel -{ -public: - ObjectModelType type; - ObjectModelPtr ptr; - bool isNode() { return type == typeNode; } - bool isObject() { return type == typeObject; } - bool isData() { return type == typeData; } - bool isBase() { return isNode() || isObject(); } - sofa::core::objectmodel::Base* asBase() - { - if( isNode() ) - return sofa::core::castToBase(ptr.Node); - if( isObject() ) - return dynamic_cast(ptr.Object); - return nullptr; - } -} ObjectModel; - -enum SofaListViewAttribute -{ - SIMULATION, - VISUAL, - MODELER -}; - -class SOFA_GUI_QT_API SofaSceneGraphWidget : public QTreeWidget -{ - Q_OBJECT -public: - SofaSceneGraphWidget(QWidget* parent) : QTreeWidget(parent){} - ~SofaSceneGraphWidget(){} - - void lock(); - void unLock(); - - /// Returns true if the view is not synchronized anymore with the simulation graph. - /// To re-syncronize the view you can: - /// - call unfreeze() so any future change will be reflected - /// - call update(), to update one time the graph. - bool isDirty(); - - /// Returns true if the view updates for any scene graph change is disable. - bool isLocked(); - - /// call this method to indicate that the internal model has changed - /// and thus the view is now dirty. - void setViewToDirty(); - -Q_SIGNALS: - /// Connect to this signal to be notified when the dirtiness status of the QSofaListView changed. - void dirtynessChanged(bool isDirty); - - /// Connect to this signal to be notified when the locking status changed - void lockingChanged(bool isLocked); - -protected: - /// Indicate that the view is de-synchronized with the real content of the simulation graph. - /// This can happen if the graph has been freezed (i.e. not graphically updated) for performance - /// reason while simulating complex scenes. - bool m_isDirty; - bool m_isLocked; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.cpp deleted file mode 100644 index cd20a7f1652..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaVideoRecorderManager.h" -#include - -namespace sofa::gui::qt -{ - -CaptureOptionsWidget::CaptureOptionsWidget( QWidget * parent) - : QWidget(parent) -{ - - QVBoxLayout *layout=new QVBoxLayout(this); - - QHBoxLayout *HLayoutFramerate = new QHBoxLayout(); - QLabel *labelFramerate=new QLabel(QString("Framerate (in img/s): "), this); - framerateSpinBox = new QSpinBox(this); - framerateSpinBox->setMinimum(1); - framerateSpinBox->setMaximum(120); - framerateSpinBox->setValue(60); - HLayoutFramerate->addWidget (labelFramerate); - HLayoutFramerate->addWidget (framerateSpinBox); - - realtimeCheckBox = new QCheckBox(QString("Real-Time recording"), this); - - QHBoxLayout *HLayoutFrameskip = new QHBoxLayout(); - QLabel *labelFrameskip=new QLabel(QString("Skip frames before capture (fast replay): "), this); - frameskipSpinBox = new QSpinBox(this); - frameskipSpinBox->setMinimum(0); - frameskipSpinBox->setMaximum(100); - frameskipSpinBox->setValue(0); - HLayoutFrameskip->addWidget (labelFrameskip); - HLayoutFrameskip->addWidget (frameskipSpinBox); - - layout->addLayout(HLayoutFramerate); - layout->addWidget(realtimeCheckBox); - layout->addLayout(HLayoutFrameskip); - - //this->addLayout(layout); -} - -MovieOptionsWidget::MovieOptionsWidget( QWidget * parent) - : QWidget(parent) -{ - //Build codec list - listCodecs.push_back(Codec("mp4", "yuv420p", "Video: h264 (Windows Media Player, QuickTime and compatible with most other players) ")); - listCodecs.push_back(Codec("mp4", "yuv444p", "Video: h264 (VLC media player) ")); - - QVBoxLayout *layout=new QVBoxLayout(this); - - QHBoxLayout *HLayoutCodec = new QHBoxLayout(); - QLabel *labelCodec=new QLabel(QString("Codec: "), this); - codecComboBox = new QComboBox(this); - for(unsigned int i=0; iaddItem(QString(listCodecs[i].description.c_str())); - codecComboBox->setCurrentIndex(0); - HLayoutCodec->addWidget (labelCodec); - HLayoutCodec->addWidget (codecComboBox); - - QHBoxLayout *HLayoutBitrate = new QHBoxLayout(); - QLabel *labelBitrate=new QLabel(QString("Bitrate (in KB/s): "), this); - bitrateSpinBox = new QSpinBox(this); - bitrateSpinBox->setMinimum(100); - bitrateSpinBox->setMaximum(40960); - bitrateSpinBox->setValue(5000); - HLayoutBitrate->addWidget (labelBitrate); - HLayoutBitrate->addWidget (bitrateSpinBox); - -// labelBitrate->setVisible(false); -// bitrateSpinBox->setVisible(false); - - layout->addLayout(HLayoutCodec); - layout->addLayout(HLayoutBitrate); - - //this->addLayout(layout); -} - -SofaVideoRecorderManager::SofaVideoRecorderManager(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - captureOptionsWidget = new CaptureOptionsWidget(this); - movieOptionsWidget = new MovieOptionsWidget(this); - - internalAddWidget(VideoRecorderOptionGroupBox, captureOptionsWidget); - internalAddWidget(VideoRecorderOptionGroupBox, movieOptionsWidget); - - MovieRecordingTypeRadioButton->setChecked(true); - onChangeRecordingType(); -} - - -std::string SofaVideoRecorderManager::getCodecExtension() -{ - const unsigned int index = movieOptionsWidget->codecComboBox->currentIndex(); - return movieOptionsWidget->listCodecs[index].extension; -} - -std::string SofaVideoRecorderManager::getCodecName() -{ - const unsigned int index = movieOptionsWidget->codecComboBox->currentIndex(); - return movieOptionsWidget->listCodecs[index].codec; -} - -unsigned int SofaVideoRecorderManager::getFramerate() -{ - return captureOptionsWidget->framerateSpinBox->value(); -} - -unsigned int SofaVideoRecorderManager::getBitrate() -{ - return movieOptionsWidget->bitrateSpinBox->value()*1024; -} - -bool SofaVideoRecorderManager::realtime() -{ - return captureOptionsWidget->realtimeCheckBox->isChecked(); -} - -unsigned int SofaVideoRecorderManager::getFrameskip() -{ - return captureOptionsWidget->frameskipSpinBox->value(); -} - - -void SofaVideoRecorderManager::updateContent() -{ - movieOptionsWidget->setHidden(currentRecordingType != MOVIE); -} - -void SofaVideoRecorderManager::onChangeRecordingType() -{ - currentRecordingType = (MovieRecordingTypeRadioButton->isChecked()) ? MOVIE : SCREENSHOTS; - - updateContent(); -} - -void SofaVideoRecorderManager::internalAddWidget(QWidget* parent, QWidget* widgetToAdd) -{ - parent->layout()->addWidget(widgetToAdd); -} - -void SofaVideoRecorderManager::close() -{ - this->hide(); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.h deleted file mode 100644 index 325da2331e9..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaVideoRecorderManager.h +++ /dev/null @@ -1,110 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include -#include - -#include - -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -class CaptureOptionsWidget : public QWidget -{ - Q_OBJECT -public: - - CaptureOptionsWidget( QWidget * parent = nullptr); - - QSpinBox* framerateSpinBox; - QCheckBox* realtimeCheckBox; - QSpinBox* frameskipSpinBox; -}; - -class MovieOptionsWidget : public QWidget -{ - Q_OBJECT -public: - //Codec = - struct Codec - { - std::string extension; - std::string codec; - std::string description; - Codec(std::string e, std::string c, std::string d) : extension(e), codec(c), description(d) {} - Codec(std::string e, std::string d) : extension(e), codec(), description(d) {} - }; - - - MovieOptionsWidget( QWidget * parent = nullptr); - - QComboBox* codecComboBox; - QSpinBox* bitrateSpinBox; - - std::vector< Codec > listCodecs; -}; - -class SofaVideoRecorderManager: public QDialog, public Ui_VideoRecorderManager -{ - Q_OBJECT -public: - enum RecordingType { SCREENSHOTS, MOVIE }; - - SofaVideoRecorderManager(QWidget *parent = Q_NULLPTR); - - static SofaVideoRecorderManager* getInstance() - { - static SofaVideoRecorderManager instance; - return &instance; - } - - void updateContent(); - std::string getCodecExtension(); - std::string getCodecName(); - unsigned int getFramerate(); - unsigned int getBitrate(); - bool realtime(); - unsigned int getFrameskip(); - RecordingType getRecordingType() { return currentRecordingType; } - - //helper function - static void internalAddWidget(QWidget* parent, QWidget* widgetToAdd); - -public slots: - virtual void onChangeRecordingType(); - virtual void close(); - -protected: - RecordingType currentRecordingType; - - CaptureOptionsWidget* captureOptionsWidget; - MovieOptionsWidget* movieOptionsWidget; - QWidget* screenshotsOptionsWidget; -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.cpp deleted file mode 100644 index 2b27ad91beb..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaWindowDataGraph.h" -#include "dataGraph/SofaComponentNodeModel.h" - -#include - -#include -#include -#include -#include -#include - -#include -#include - - -namespace sofa::gui::qt -{ -using namespace sofa::helper; - - -using QtNodes::DataModelRegistry; -using QtNodes::FlowScene; -using QtNodes::FlowView; -using QtNodes::ConnectionStyle; - -static std::shared_ptr registerDataModels() -{ - auto ret = std::make_shared(); - - std::vector results; - sofa::core::ObjectFactory::getInstance()->getAllEntries(results); - - ret->registerModel(); - //for (auto compo : results) - //{ - // std::cout << compo->className << std::endl; - // ret->registerModel(QString::fromStdString(compo->className)); - //} - - - /* - We could have more models registered. - All of them become items in the context meny of the scene. - - ret->registerModel(); - ret->registerModel(); - - */ - - return ret; -} - - -static -void -setConnecStyle() -{ - ConnectionStyle::setConnectionStyle( - R"( - { - "ConnectionStyle": { - "LineWidth": 3.0, - "UseDataDefinedColors": true - } - } - )"); -} - - - -///////////////////////////////////////// ProfilerChartView /////////////////////////////////// - -SofaWindowDataGraph::SofaWindowDataGraph(QWidget *parent, sofa::simulation::Node* scene) - : QDialog(parent) - , m_rootNode(scene) - , m_scaleX(10) - , m_scaleY(30) - , m_posX(0) - , m_posY(0) - , debugNodeGraph(false) -{ - setConnecStyle(); - Qt::WindowFlags flags = windowFlags(); - flags |= Qt::WindowMaximizeButtonHint; - flags |= Qt::WindowContextHelpButtonHint; - setWindowFlags(flags); - - m_graphScene = new FlowScene(registerDataModels()); - - m_exceptions = { "RequiredPlugin", "VisualStyle", "DefaultVisualManagerLoop", "InteractiveCamera" }; - - QVBoxLayout* layout = new QVBoxLayout(this); - m_graphView = new FlowView(m_graphScene, this); - layout->addWidget(m_graphView); - this->setLayout(layout); - - resize(1000, 800); - - // start from parsing root node - parseSimulationNode(m_rootNode); - - // then connect all data - connectNodeData(); -} - - -SofaWindowDataGraph::~SofaWindowDataGraph() -{ - std::cout << "SofaWindowDataGraph::~SofaWindowDataGraph()" << std::endl; - clearNodeData(); - // todo check if m_graphView need to be deleted. Normally no as child of QtWidget RealGui. - //delete m_graphView; -} - -void SofaWindowDataGraph::clearNodeData() -{ - if (m_graphScene != nullptr) - { - msg_info_when(debugNodeGraph, "SofaWindowDataGraph") << "clear before: " << m_graphScene->allNodes().size(); - //m_graphScene->clear(); - delete m_graphScene; - m_graphScene = new FlowScene(registerDataModels()); - m_graphView->setScene(m_graphScene); - - msg_info_when(debugNodeGraph, "SofaWindowDataGraph") << "clear after: " << m_graphScene->allNodes().size(); - } - m_posX = 0; - m_posY = 0; -} - -void SofaWindowDataGraph::resetNodeGraph(sofa::simulation::Node* scene) -{ - m_rootNode = scene; - clearNodeData(); - - // start from parsing root node - parseSimulationNode(m_rootNode); - - // then connect all data - connectNodeData(); -} - - -void SofaWindowDataGraph::parseSimulationNode(sofa::simulation::Node* node, int posX) -{ - msg_info_when(debugNodeGraph, "SofaWindowDataGraph") << m_posY << " ### Child Name: " << node->getName(); - // first parse the list BaseObject inside this node - std::vector bObjects = node->getNodeObjects(); - m_posX = posX; - int maxData = 0; - for (auto bObject : bObjects) - { - bool skip = false; - for (auto except : m_exceptions) - { - if (except == bObject->getClassName()) - { - msg_info_when(debugNodeGraph, "SofaWindowDataGraph") << "skip: " << except; - skip = true; - break; - } - } - - if (skip) - continue; - - size_t nbrData = addSimulationObject(bObject); - if (nbrData > maxData) - maxData = nbrData; - - // space between cells - m_posX += 14 * m_scaleX; - } - - if (bObjects.size() >= 4) { - m_posY += (maxData + 10) * m_scaleY; - m_posX = posX + 30 * m_scaleX; - } - - // second move to child nodes - for (auto simuNode : node->getChildren()) - { - parseSimulationNode(dynamic_cast(simuNode), m_posX); - } -} - - -size_t SofaWindowDataGraph::addSimulationObject(sofa::core::objectmodel::BaseObject* bObject) -{ - const std::string& name = bObject->getClassName() + " - " + bObject->getName(); - msg_info_when(debugNodeGraph, "SofaWindowDataGraph") << "addSimulationObject: " << name; - - QtNodes::Node& fromNode = m_graphScene->createNode(std::make_unique(bObject, debugNodeGraph)); - fromNode.setObjectName(QString::fromStdString(bObject->getName())); - - SofaComponentNodeModel* model = dynamic_cast(fromNode.nodeDataModel()); - model->setCaption(name); - - auto& fromNgo = fromNode.nodeGraphicsObject(); - fromNgo.setPos(m_posX, m_posY); - m_posX += name.length() * m_scaleX; - - return model->getNbrData(); -} - - -void SofaWindowDataGraph::connectNodeData() -{ - std::vector nodes = m_graphScene->allNodes(); - - for (auto node : nodes) - { - // get connections - SofaComponentNodeModel* childNode = dynamic_cast(node->nodeDataModel()); - - if (childNode->getNbrConnections() == 0) - continue; - - const std::map >& connections = childNode->getDataConnections(); - - for (auto connection : connections) - { - bool parentFound = false; - for (auto pNode : nodes) - { - QString pObjName = pNode->objectName(); - if (pObjName.compare(connection.second.first) == 0) - { - parentFound = true; - SofaComponentNodeModel* parentNode = dynamic_cast(pNode->nodeDataModel()); - QtNodes::PortIndex parentId = parentNode->getDataInputId(connection.second.second); - QtNodes::PortIndex childId = childNode->getDataInputId(connection.first); - - m_graphScene->createConnection(*node, childId, *pNode, parentId); - - break; - } - } - - if (!parentFound) - { - msg_error("SofaWindowDataGraph") << "Object not found while creating connection between " << node->objectName().toStdString() << " and child: " << connection.second.first.toStdString(); - continue; - } - } - } -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.h deleted file mode 100644 index 4c901242fc6..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowDataGraph.h +++ /dev/null @@ -1,87 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#define NODE_EDITOR_SHARED - -namespace QtNodes -{ - class FlowScene; - class FlowView; -} - - -namespace sofa::gui::qt -{ - /** - * This Class provide an interface with the library QtNodes to display Data Graph connection inside a QDialog. - * It will take a SOFA simulation scene and create Graph nodes for each Sofa component and display connections between Data. - */ -class SofaWindowDataGraph : public QDialog -{ - Q_OBJECT -public: - /// Default constructor of the Widget, given a QWidget as parent and a pointer to the current simulation scene. - SofaWindowDataGraph(QWidget *parent, sofa::simulation::Node* scene); - - ~SofaWindowDataGraph(); - - /// Method to be called when graph need to be recomputed (like reloading scene). Take a pointer to the root node of the scene. - void resetNodeGraph(sofa::simulation::Node* scene); - -protected: - /// Internal method to parse all Sofa component inside a Sofa simulation Node. Will call @sa addSimulationObject for each compoenent then will iterate on children nodes. - void parseSimulationNode(sofa::simulation::Node* node, int posX = 0); - - /// Internal method to create a Node for this sofa BaseObject. - size_t addSimulationObject(sofa::core::objectmodel::BaseObject* bObject); - - /// Internal method to create all connection between component on the graph. - void connectNodeData(); - - /// Internal method to clear the graph structures - void clearNodeData(); - -protected: - /// Pointer to the graphScene used to store nodes. - QtNodes::FlowScene* m_graphScene; - /// Pointer to the view of the graph. - QtNodes::FlowView* m_graphView; - - /// Point to the root node of the current simulation. - sofa::simulation::Node* m_rootNode; - - /// List of component name not to be display in the graph. - std::vector m_exceptions; - - SReal m_scaleX; ///< Scale parameter to apply between nodes for display in abscissa. - SReal m_scaleY; ///< Scale parameter to apply between nodes for display in ordinate. - - int m_posX; ///< Increment position counter on abscissa for Node display. - int m_posY; ///< Increment position counter on ordinate for Node display. - - bool debugNodeGraph; ///< parameter to activate graph logs. False by default. -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.cpp deleted file mode 100644 index 40b3e2269b2..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaWindowProfiler.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ -using namespace sofa::helper; - -typedef sofa::helper::system::thread::ctime_t ctime_t; -typedef sofa::helper::system::thread::CTime CTime; - - -///////////////////////////////////////// ProfilerChartView /////////////////////////////////// - -ProfilerChartView::ProfilerChartView(QChart *chart, QWidget *parent, int bufferSize) - : QChartView(chart, parent) - , m_bufferSize(bufferSize) - , m_pointSelected(-1) - , m_maxY(1000) -{ - -} - -void ProfilerChartView::mousePressEvent(QMouseEvent *event) -{ - auto const valueInSeries = chart()->mapToValue(event->localPos()); - - const int width = valueInSeries.x(); - - if (width >= 0 && width < m_bufferSize) - { - m_pointSelected = width; - updateSelection(m_pointSelected); - emit pointSelected(m_pointSelected); - } - else - m_pointSelected = -1; -} - -void ProfilerChartView::updateSelection(int x) -{ - m_pointSelected = x; - m_lineSelect = chart()->mapToPosition(QPointF(x, m_maxY)); - m_lineOrigin = chart()->mapToPosition(QPointF(x, 0)); - - this->scene()->update(this->sceneRect()); -} - - -void ProfilerChartView::drawForeground(QPainter *painter, const QRectF &) -{ - if (m_pointSelected == -1) - return; - - painter->drawLine(m_lineOrigin, m_lineSelect); -} - - - -// quick method to convert freq time into ms -SReal convertInMs(ctime_t t, int nbIter=1) -{ - static SReal timer_freqd = SReal(CTime::getTicksPerSec()); - return 1000.0 * SReal(t) / SReal (timer_freqd * nbIter); -} - -///////////////////////////////////////// AnimationSubStepData /////////////////////////////////// - -SofaWindowProfiler::AnimationSubStepData::AnimationSubStepData(int level, std::string name, ctime_t start) - : m_level(level) - , m_name(std::move(name)) - , m_nbrCall(1) - , m_start(start) -{ - -} - -SofaWindowProfiler::AnimationSubStepData::~AnimationSubStepData() -{ - for (unsigned int i=0; icomputeTimeAndPercentage(invTotalMs); - totalChildrenMs += m_children[i]->m_totalMs; - } - - // now that all children are update, compute ms and % - m_totalMs = convertInMs(m_end - m_start); - m_selfMs = m_totalMs - totalChildrenMs; - - m_selfPercent = m_selfMs * invTotalMs; - m_totalPercent = m_totalMs * invTotalMs; - } - else // leaf - { - // compute ms: - m_totalMs = convertInMs(m_end - m_start); - if (m_nbrCall != 1) - m_selfMs = SReal(m_totalMs / m_nbrCall); - else - m_selfMs = m_totalMs; - - // compute % - m_selfPercent = m_selfMs * invTotalMs; - m_totalPercent = m_totalMs * invTotalMs; - } -} - -SReal SofaWindowProfiler::AnimationSubStepData::getStepMs(const std::string& stepName, const std::string& parentName) -{ - SReal result = 0.0; - if (parentName == m_name) - { - for (unsigned int i=0; im_name == stepName) - return m_children[i]->m_totalMs; - } - } - else - { - for (unsigned int i=0; igetStepMs(stepName, parentName); - if (result != 0.0) - return result; - } - } - - return 0.0; -} - - - -///////////////////////////////////////// AnimationStepData /////////////////////////////////// - -SofaWindowProfiler::AnimationStepData::AnimationStepData(int step, const std::string& idString) - : m_stepIteration(step) - , m_totalMs(0.0) - , m_idString(idString) - , m_overheadMs(0.) -{ - m_subSteps.clear(); - - const bool res = processData(idString); - if (!res) // error clear data - { - for (unsigned int i=0; i _records = sofa::helper::AdvancedTimer::getRecords(idString); - - m_totalTimers = 0; - - //AnimationSubStepData* currentSubStep = nullptr; - std::stack processStack; - int level = 0; - ctime_t t0 = 0; - const ctime_t tEnd = CTime::getTime(); - ctime_t tCurr; - for (unsigned int ri = 0; ri < _records.size(); ++ri) - { - const Record& rec = _records[ri]; - - if (level == 0) // main step - { - t0 = rec.time; - level++; - continue; - } - - tCurr = rec.time - t0; - - if (rec.type == Record::RBEGIN || rec.type == Record::RSTEP_BEGIN || rec.type == Record::RSTEP) - { -// for (int i=0; im_tag = std::string(AdvancedTimer::IdObj(rec.obj)); - - if (level == 1) // Add top level step - m_subSteps.push_back(currentSubStep); - else - { - if (processStack.empty()) - { - msg_error("SofaWindowProfiler") << "No parent found to add step: " << currentSubStep->m_name; - delete currentSubStep; - return false; - } - else if (processStack.top()->m_level + 1 != currentSubStep->m_level) - { - msg_warning("SofaWindowProfiler") << "Problem of level coherence between step: " << currentSubStep->m_name << " with level: " << currentSubStep->m_level - << " and parent step: " << processStack.top()->m_name << " with level: " << processStack.top()->m_level; - } - - // add next step to the hierarchy - processStack.top()->m_children.push_back(currentSubStep); - } - - // add step into the stack for parent/child order - processStack.push(currentSubStep); - ++level; - } - - if (rec.type == Record::REND || rec.type == Record::RSTEP_END) - { - ++m_totalTimers; - --level; -// for (int i=0; im_name) - { - msg_error("SofaWindowProfiler") << "Not the same name to end step between logs: " << rec.label << " and top stack: " << processStack.top()->m_name; - return false; - } - - AnimationSubStepData* currentSubStep = processStack.top(); - processStack.pop(); - - currentSubStep->m_end = tCurr; - } - } - // compute total MS step: - m_totalMs = convertInMs(tEnd - t0); - - // update percentage - const SReal invTotalMs = 100. / m_totalMs; - SReal totalChildrenMs = 0.0; - for (unsigned int i=0; icomputeTimeAndPercentage(invTotalMs); - totalChildrenMs += m_subSteps[i]->m_totalMs; - } - - m_selfMs = m_totalMs - totalChildrenMs; - m_selfPercent = 100. * m_selfMs / m_totalMs; - - return true; -} - - -SReal SofaWindowProfiler::AnimationStepData::getStepMs(const std::string& stepName, const std::string& parentName) -{ - SReal result = 0.0; - if (parentName.empty()) - { - for (unsigned int i=0; im_name == stepName) - return m_subSteps[i]->m_totalMs; - } - } - else - { - for (unsigned int i=0; igetStepMs(stepName, parentName); - if (result != 0.0) - return result; - } - } - - return 0.0; -} - - -SofaWindowProfiler::AnimationStepData::~AnimationStepData() -{ - for (unsigned int i=0; isetRange(0, m_bufferSize-1); - step_scroller->setMinimumWidth(200); - step_scroller->setMaximumWidth(200); - connect(step_scroller, SIGNAL(valueChanged(int)), this, SLOT(updateSummaryLabels(int))); - connect(step_scroller, SIGNAL(valueChanged(int)), this, SLOT(updateTree(int))); - - connect(step_scroller, SIGNAL(valueChanged(int)), m_chartView, SLOT(updateSelection(int))); - connect(m_chartView, SIGNAL(pointSelected(int)), this, SLOT(updateFromSelectedStep(int))); - - ExpandAllButton->setIcon(QIcon(":/RealGUI/expandAll")); - CollapseAllButton->setIcon(QIcon(":/RealGUI/collapseAll")); - for (auto* button : {ExpandAllButton, CollapseAllButton}) - { - button->setFixedWidth(button->height()); - } - - connect ( ExpandAllButton, SIGNAL ( clicked() ), tree_steps, SLOT ( expandAll() ) ); - connect ( CollapseAllButton, SIGNAL ( clicked() ), this, SLOT ( expandRootNodeOnly() ) ); -} - - -void SofaWindowProfiler::activateATimer(bool activate) -{ - sofa::helper::AdvancedTimer::setEnabled("Animate", activate); - sofa::helper::AdvancedTimer::setInterval("Animate", 1); - sofa::helper::AdvancedTimer::setOutputType("Animate", "gui"); -} - - -void SofaWindowProfiler::pushStepData() -{ - const ctime_t start = CTime::getRefTime(); - - m_profilingData.pop_front(); - const static std::string idString = "Animate"; - m_profilingData.push_back(new AnimationStepData(m_step, idString)); - m_step++; - - updateChart(); - - m_profilingData.back()->m_overheadMs = convertInMs(CTime::getRefTime() - start); -} - - -void SofaWindowProfiler::resetGraph() -{ - if (m_step == 0) - return; - - for(unsigned int i=0; ireplace(i, 0.0, 0.0); - m_selectionSeries->replace(i, 0.0, 0.0); - m_selectionSeries->setName("Selected SubStep"); - if (m_profilingData[i] && m_profilingData[i]->m_stepIteration != -1) - { - delete m_profilingData[i]; - m_profilingData[i] = new AnimationStepData(); - } - } - - step_scroller->setValue(1); // for rest by changing 2 times value - step_scroller->setValue(0); - m_step = 0; - m_selectedStep = ""; - m_selectedParentStep = ""; -} - - -void SofaWindowProfiler::createTreeView() -{ - //list of the columns description - //- first: column names - //- second: tooltip (description of the column) - const std::vector< std::pair< QString, QString > > columnsLabels = { - {"Hierarchy Step Name", "Label of the measured step"}, - {"Total (%)", "Percentage of duration of this step compared to the duration of the root step"}, - {"Self (%)", "- If the step has child steps: percentage of the duration " - "of this step minus the sum of durations of its children, compared to " - "the duration of the root step.\n" - "- If the step has no child step: percentage of the average duration " - "of this step in case of multiple calls of this step during this time step, " - "compared to the duration of the root step."}, - {"Time (ms)", "Duration in milliseconds of this step"}, - {"Self (ms)", "- If the step has child steps: duration in milliseconds of " - "this step minus the sum of durations of its children.\n" - "- If the step has no child step: average duration in milliseconds of " - "this step in case of multiple calls of this step during this time step."} - }; - - // set column names - QStringList columnNames; - - for (std::size_t i = 0; i < columnsLabels.size(); ++i) - { - columnNames << columnsLabels[i].first; - tree_steps->headerItem()->setToolTip(i, columnsLabels[i].second); - } - tree_steps->setHeaderLabels(columnNames); - - tree_steps->headerItem()->setToolTip(1, QString("Percentage of duration of this step compared to the duration of the root step")); - tree_steps->headerItem()->setToolTip(2, - QString("- If the step has child steps: percentage of the duration " - "of this step minus the sum of durations of its children, compared to " - "the duration of the root step.\n" - "- If the step has no child step: percentage of the average duration " - "of this step in case of multiple calls of this step during this time step, " - "compared to the duration of the root step.")); - tree_steps->headerItem()->setToolTip(3, QString("Duration in milliseconds of this step")); - tree_steps->headerItem()->setToolTip(4, - QString("- If the step has child steps: duration in milliseconds of " - "this step minus the sum of durations of its children.\n" - "- If the step has no child step: average duration in milliseconds of " - "this step in case of multiple calls of this step during this time step.")); - - // set column properties - tree_steps->header()->setStretchLastSection(false); - tree_steps->header()->setSectionResizeMode(0, QHeaderView::Stretch); - - connect(tree_steps, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(onStepSelected(QTreeWidgetItem*,int))); -} - - -void SofaWindowProfiler::createChart() -{ - m_series = new QLineSeries(); - QPen pen = m_series->pen(); - pen.setColor(Qt::red); - pen.setWidth(2); - m_series->setName("Full Animation Step"); - m_series->setPen(pen); - - m_selectionSeries = new QLineSeries(); - m_selectionSeries->setName("Selected SubStep"); - - for(unsigned int i=0; iappend(i, 0.0f); - m_selectionSeries->append(i, 0.0f); - } - - m_chart = new QChart(); - m_chart->legend()->setShowToolTips(true); - m_chart->addSeries(m_series); - m_chart->addSeries(m_selectionSeries); - m_axisY = new QValueAxis(); - m_chart->addAxis(m_axisY, Qt::AlignLeft); - m_series->attachAxis(m_axisY); - m_selectionSeries->attachAxis(m_axisY); - - m_chart->setTitle("Steps durations (in ms)"); - m_axisY->setRange(0, 1000); - - m_chartView = new ProfilerChartView(m_chart, this, m_bufferSize); - m_chartView->setRenderHint(QPainter::Antialiasing); - - Layout_graph->addWidget(m_chartView); -} - - -void SofaWindowProfiler::updateChart() -{ - bool updateAxis = false; - - QVector seriesPoints; - QVector selectedStepPoints; - std::unordered_map > checkedSeriesPoints; - - int cpt = 0; - for (auto* stepData : m_profilingData) - { - seriesPoints.push_back(QPointF(cpt, stepData->m_totalMs)); - - if (!m_selectedStep.empty()) - { - const SReal value = stepData->getStepMs(m_selectedStep, m_selectedParentStep); - selectedStepPoints.push_back(QPointF(cpt, value)); - } - - for (const auto& checkedSeries : m_checkedSeries) - { - const SReal value = stepData->getStepMs(checkedSeries.first, checkedSeries.second.checkedParentStep); - checkedSeriesPoints[checkedSeries.first].push_back(QPointF(cpt, value)); - } - - if (m_fpsMaxAxis < stepData->m_totalMs){ - m_fpsMaxAxis = stepData->m_totalMs; - updateAxis = true; - } - - // keep max ms value - if (m_maxFps < stepData->m_totalMs) - m_maxFps = stepData->m_totalMs; - - cpt++; - } - - m_series->replace(seriesPoints); - m_selectionSeries->replace(selectedStepPoints); - for (const auto& checkedSeries : m_checkedSeries) - { - auto it = checkedSeriesPoints.find(checkedSeries.first); - if (it != checkedSeriesPoints.end()) - { - checkedSeries.second.lineSeries->replace(it->second); - } - } - - // if needed enlarge the Y axis to cover new data - if (updateAxis){ - m_axisY->setRange(0, m_fpsMaxAxis*1.1); - m_chartView->updateYMax(m_fpsMaxAxis*1.1); - } - - // every loop on buffer size check if Y axis can be reduced - if ((m_step% m_bufferSize) == 0) - { - if (m_maxFps < m_fpsMaxAxis) - m_fpsMaxAxis = m_maxFps; - - m_maxFps = 0; - m_axisY->setRange(0, m_fpsMaxAxis*1.1); - m_chartView->updateYMax(m_fpsMaxAxis*1.1); - } - - // m_chartView->update(); - - // update all widgets from value sliced - updateSummaryLabels(step_scroller->value()); - updateTree(step_scroller->value()); -} - - -void SofaWindowProfiler::updateFromSelectedStep(int step) -{ - // only update scroller as all the connection are already made from the scroller value change. - step_scroller->setValue(step); -} - - -void SofaWindowProfiler::updateSummaryLabels(int step) -{ - const AnimationStepData* stepData = m_profilingData.at(step); - label_stepValue->setText(QString::number(stepData->m_stepIteration)); - label_timeValue->setText(QString::number(stepData->m_totalMs)); - label_overheadValue->setText(QString::number(stepData->m_overheadMs)); - label_timersCounterValue->setText(QString::number(stepData->m_totalTimers)); -} - -void SofaWindowProfiler::updateTree(int step) -{ - const AnimationStepData* stepData = m_profilingData.at(step); - - tree_steps->setUpdatesEnabled(false); - - //clear old values - tree_steps->clear(); - - QList root; - root << addTreeItem(stepData); - tree_steps->addTopLevelItems(root); - - //Expand the first two levels - for (int i = 0; i < tree_steps->topLevelItemCount(); ++i) - { - auto* item = tree_steps->topLevelItem(i); - item->setExpanded(true); - for (int j = 0; j < item->childCount(); ++j) - { - item->child(i)->setExpanded(true); - } - } - - tree_steps->setUpdatesEnabled(true); -} - -QTreeWidgetItem* SofaWindowProfiler::addTreeItem(AnimationSubStepData* subStep) -{ - QStringList columns; - columns << QString::fromStdString(subStep->m_name); - columns << QString::number(subStep->m_totalPercent, 'g', 2); - columns << QString::number(subStep->m_selfPercent, 'g', 2); - columns << QString::number(subStep->m_totalMs); - columns << QString::number(subStep->m_selfMs); - - // add item to the tree - QTreeWidgetItem* treeItem = new QTreeWidgetItem(columns); - - if (m_checkedSeries.find(subStep->m_name) == m_checkedSeries.end()) - { - treeItem->setCheckState(0, Qt::Unchecked); - } - else - { - treeItem->setCheckState(0, Qt::Checked); - } - - treeItem->setSelected(m_selectedStep == subStep->m_name); - - if (subStep->m_level <= 2) - { - QFont font = QApplication::font(); - font.setBold(true); - - for (int i = 0; icolumnCount(); i++) - treeItem->setFont(i, font); - } - - QList children; - // process children - for (auto* child : subStep->m_children) - children << addTreeItem(child); - treeItem->addChildren(children); - - return treeItem; -} - -QTreeWidgetItem* SofaWindowProfiler::addTreeItem(const AnimationStepData* step) -{ - QStringList columns; - columns << QString::fromStdString(step->m_idString); - columns << "100"; - columns << QString::number(step->m_selfPercent, 'g', 2); - columns << QString::number(step->m_totalMs); - columns << QString::number(step->m_selfMs); - - QTreeWidgetItem* treeItem = new QTreeWidgetItem(columns); - - QFont font = QApplication::font(); - font.setBold(true); - - for (int i = 0; icolumnCount(); i++) - treeItem->setFont(i, font); - - // add new step items - QList children; - for (auto* substep : step->m_subSteps) - { - children << addTreeItem(substep); - } - - treeItem->addChildren(children); - - return treeItem; -} - -void SofaWindowProfiler::onStepSelected(QTreeWidgetItem *item, int /*column*/) -{ - if (item->parent()) - m_selectedParentStep = item->parent()->text(0).toStdString(); - - m_selectedStep = item->text(0).toStdString(); - - if (item->checkState(0)) - { - if (m_checkedSeries.find(m_selectedStep) == m_checkedSeries.end()) - { - QLineSeries* checkedLineSeries = new QLineSeries; - for (unsigned int i = 0; i < m_bufferSize; ++i) - { - const SReal value = (i < m_profilingData.size()) ? - m_profilingData[i]->getStepMs(m_selectedStep, m_selectedParentStep) : 0.f; - checkedLineSeries->append(i, value); - } - - m_chart->addSeries(checkedLineSeries); - checkedLineSeries->setName(QString(m_selectedStep.c_str())); - checkedLineSeries->attachAxis(m_axisY); - - m_checkedSeries.insert({m_selectedStep, {checkedLineSeries, m_selectedParentStep}}); - } - } - else - { - const auto it = m_checkedSeries.find(m_selectedStep); - if (it != m_checkedSeries.end()) - { - m_chart->removeSeries(it->second.lineSeries); - m_checkedSeries.erase(it); - } - - if (item->parent()) - { - m_chart->addSeries(m_selectionSeries); - int cpt = 0; - QVector seriesPoints; - for (auto* stepData : m_profilingData) - { - const SReal value = stepData->getStepMs(m_selectedStep, m_selectedParentStep); - seriesPoints << QPointF(cpt++, value); - } - m_selectionSeries->replace(seriesPoints); - m_selectionSeries->setName(QString(m_selectedStep.c_str())); - } - } -} - -void SofaWindowProfiler::expandRootNodeOnly() const -{ - tree_steps->expandToDepth(0); -} -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.h b/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.h deleted file mode 100644 index 8a8b7e42064..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/SofaWindowProfiler.h +++ /dev/null @@ -1,265 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include "PieWidget.h" -#include "QVisitorControlPanel.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -using namespace QtCharts; -#endif - -namespace sofa::gui::qt -{ - -typedef sofa::helper::system::thread::ctime_t ctime_t; - -/** - * @brief The ProfilerChartView class is a override of QtCharts::QChartView - * to be able to catch mouse selection and update all widgets of \sa SofaWindowProfiler - * Will also override drawForeground to draw a line to show the selected step. - */ -class ProfilerChartView : public QChartView -{ - Q_OBJECT -public: - ProfilerChartView(QChart *chart, QWidget *parent, int bufferSize); - - /// method to update the max value of the Y axis (for line rendering). - void updateYMax(int y) {m_maxY = y;} - -protected: - /// Override to catch mouse selection on the graph. - virtual void mousePressEvent(QMouseEvent *event); - /// Override to draw line at the step selected. - virtual void drawForeground(QPainter *painter, const QRectF &rect); - -signals: - /// signal emitted when a step has been selected on the graph @param int is the step number - void pointSelected(int); - -public slots: - /// method to update the selection on the graph. - void updateSelection(int x); - -protected: - /// copy of the series size to check if selection is not out of bound - int m_bufferSize; - - /// 2D point of the line to draw the selection - QPointF m_lineSelect; - QPointF m_lineOrigin; - - /// Step number selected on the graph. -1 if none - int m_pointSelected; - /// Stored value of the Y axis max. - int m_maxY; -}; - -/** - * @brief The SofaWindowProfiler class - * This class is a QDialog widget to display information recorded by AdvancedTimer mechanism - * At each step, info will be gathered from the AdvancedTimer using class sofa::helper::StepData - * Info will be displayed by: - * - plotting the step duration into a graph - * - Showing information duration/step number - * - Showing all substep of an animation step with their own duration in ms and the corresponding percentage over the whole step. - */ -class SofaWindowProfiler: public QDialog, public Ui_WindowProfiler -{ - Q_OBJECT -public: - SofaWindowProfiler(QWidget* parent); - - /// method called when window is shown to activate AdvancedTimer recording. - void activateATimer(bool activate); - - /// main method to iterate on the AdvancedTimer Data and update the info in the widgets - void pushStepData(); - - /// Method to clear all Data and reset graph - void resetGraph(); - - /** - * @brief The AnimationSubStepData Internal class to store data for each step of the animation. Correspond to one AdvancedTimer::begin/end - * Data stored/computed will be step name, its time in ms and the corresponding % inside the whole step. - * the total ms and percentage it represent if this step has substeps. - * Buffer of AnimationSubStepData corresponding to its children substeps - */ - class AnimationSubStepData - { - public: - AnimationSubStepData(int level, std::string name, ctime_t start); - virtual ~AnimationSubStepData(); - - int m_level; - std::string m_name; - int m_nbrCall; - ctime_t m_start; - ctime_t m_end; - - std::string m_tag; - SReal m_totalMs; - SReal m_totalPercent; - SReal m_selfMs; - SReal m_selfPercent; - - void computeTimeAndPercentage(SReal invTotalMs); - // Method to get a given step duration (ms) given its name and parent name - SReal getStepMs(const std::string& stepName, const std::string& parentName); - - sofa::type::vector m_children; - }; - - /** - * @brief The AnimationStepData internal class to store all info of a animation step recorded by AdvancedTimer - * Data stored/computed will be the step number, and the total time in ms of the step. - * All Data will then be stored inside a tree of \sa AnimationSubStepData tree. - */ - class AnimationStepData - { - public: - // default constructor for empty data. - AnimationStepData() - : m_stepIteration(-1) - , m_totalMs(0.0) - , m_overheadMs(0.) - {} - - AnimationStepData(int step, const std::string& idString); - - // Method to get a given step duration (ms) given its name and parent name - SReal getStepMs(const std::string& stepName, const std::string& parentName); - - virtual ~AnimationStepData(); - int m_stepIteration; - SReal m_totalMs; - SReal m_selfMs {}; ///< Difference between the total time and the time of all children - SReal m_selfPercent {}; ///< Difference between the total time and the time of all children as a percentage - std::string m_idString; ///< Name of the timer - - sofa::type::vector m_subSteps; - - /// The overhead due to timers processing. In milliseconds - SReal m_overheadMs; - - /// Total number of timers in this step - unsigned int m_totalTimers {}; - protected: - bool processData(const std::string& idString); - }; - -protected: - /// Method called at creation to init the chart - void createChart(); - /// Method called at creation to init the QTreeWidget - void createTreeView(); - - /// Method called at each iteration to update the chart - void updateChart(); - /// Method to add new QTreeWidgetItem item inside the QTreeWidget using the data from \sa AnimationSubStepData - QTreeWidgetItem* addTreeItem(AnimationSubStepData* subStep); - - QTreeWidgetItem* addTreeItem(const AnimationStepData* step); - -public slots: - void closeEvent( QCloseEvent* ) override - { - emit(closeWindow(false)); - } - - /// Method to update all widgets from select absisse on the graph - void updateFromSelectedStep(int step); - - /// Method called when a given @param step is triggered to update summary information - void updateSummaryLabels(int step); - /// Method called when a given @param step is triggered to update the QTreeView - void updateTree(int step); - /// Method called when a QTreeWidgetItem is selected in the Tree view. - void onStepSelected(QTreeWidgetItem *item, int column); - - void expandRootNodeOnly() const; - -signals: - void closeWindow(bool); - -protected: - /// Pointer to the chart Data - QChart *m_chart; - /// Pointer to Y Axis - QValueAxis *m_axisY; - /// Pointer to the \sa ProfilerChartView class to handle chart drawing/selection - ProfilerChartView* m_chartView; - - /// Current animation step internally recorded. - int m_step; - /// Size of the buffer data stored. (i.e number of stepData info stored) - unsigned int m_bufferSize; - /// Bigger step encountered in ms. - SReal m_maxFps; - /// Current Y max value of the graph (max ms encountered x1.1) - SReal m_fpsMaxAxis; - - /// Buffer of \sa AnimationStepData (data for each step), deque size correspond to \sa m_bufferSize - std::deque m_profilingData; - - /// Series of step duration in ms to be plot on the graph. size = \sa m_bufferSize - QLineSeries *m_series; - - /// Series of selection substep duration in ms to be plot on the graph. size = \sa m_bufferSize - QLineSeries *m_selectionSeries; - - struct CheckedSeries - { - QLineSeries* lineSeries; - std::string checkedParentStep; - }; - std::unordered_map m_checkedSeries; - - /// Name of the substep selected in the Tree - std::string m_selectedStep; - /// Name of the parent of the substep selected in the Tree - std::string m_selectedParentStep; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.cpp deleted file mode 100644 index bb2db368d10..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "StructDataWidget.h" -#include -#include - -namespace sofa::gui::qt -{ - -using sofa::helper::Creator; -using sofa::type::fixed_array; -using namespace sofa::defaulttype; - -Creator > > DWClass_RigidCoord2f("default",true); -Creator > > DWClass_RigidCoord2d("default",true); -Creator > > DWClass_RigidMass2f("default",true); -Creator > > DWClass_RigidMass2d("default",true); -Creator > > DWClass_RigidCoord3f("default",true); -Creator > > DWClass_RigidCoord3d("default",true); -Creator > > DWClass_RigidMass3f("default",true); -Creator > > DWClass_RigidMass3d("default",true); - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.h deleted file mode 100644 index 761380daa54..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/StructDataWidget.h +++ /dev/null @@ -1,564 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "SimpleDataWidget.h" -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace sofa::gui::qt -{ - -//////////////////////////////////////////////////////////////// -/// Generic data structures support -//////////////////////////////////////////////////////////////// - -template -class struct_data_trait -{ -public: - typedef T data_type; - enum { NVAR = 1 }; - static void set( data_type& /*d*/ ) - { - } -}; - -template -class struct_data_trait_var -{ -public: - typedef T data_type; - typedef T value_type; - static const char* name() { return nullptr; } - static const value_type* get(const data_type& d) { return &d; } - static void set( const value_type& v, data_type& d) { d = v; } - static bool readOnly() { return false; } - static bool isCheckable() { return false; } - static bool isChecked(const data_type& /*d*/) { return true; } - static void setChecked(bool /*b*/, data_type& /*d*/) {} -}; - -template::NVAR > -class struct_data_widget_container -{ -public: - typedef T data_type; - typedef struct_data_trait shelper; - typedef struct_data_trait_var vhelper; - typedef typename vhelper::value_type value_type; - typedef data_widget_container Container; - typedef struct_data_widget_container PrevContainer; - typedef QVBoxLayout MasterLayout; - typedef QHBoxLayout Layout; - PrevContainer p; - Container w; - QCheckBox* check; - QLabel* label; - Layout* container_layout; - MasterLayout* master_layout; - struct_data_widget_container() : check(nullptr),label(nullptr),container_layout(nullptr),master_layout(nullptr) {} - - void setMasterLayout(MasterLayout* layout) - { - p.setMasterLayout(layout); - master_layout = layout; - } - - bool createLayout( DataWidget* parent ) - { - if( parent->layout() != nullptr ) - { - return false; - } - master_layout = new QVBoxLayout(parent); - setMasterLayout(master_layout); - return true; - } - - bool createLayout( QLayout* layout) - { - container_layout = new QHBoxLayout(); - layout->addItem(container_layout); - return true; - } - - void insertWidgets() - { - p.insertWidgets(); - createLayout(master_layout); - - if(check) - { - container_layout->addWidget(check); - } - if(label) - { - container_layout->addWidget(label); - } - w.createLayout(container_layout); // create the layout for the rest of the widgets - w.insertWidgets(); // insert them accordingly - - } - - bool createWidgets(DataWidget * parent, const data_type& d, bool readOnly ) - { - - if (!p.createWidgets( parent, d, readOnly)) - return false; - - const char* name = vhelper::name(); - const bool checkable = vhelper::isCheckable(); - if (checkable) - { - check = new QCheckBox(parent); - if (name && *name) - { - check->setText(QString(name)); - } - } - else - { - if (name && *name && N > 1) - { - label = new QLabel(QString(name),parent); - } - } - if (!w.createWidgets(parent, *vhelper::get(d), readOnly || vhelper::readOnly())) - return false; - - if (checkable) - { - const bool isChecked = vhelper::isChecked(d); - check->setChecked(isChecked); - if (readOnly || vhelper::readOnly()) - check->setEnabled(false); - else - { - if (!isChecked) - w.setReadOnly(true); - parent->connect(check, SIGNAL( toggled(bool) ),parent, SLOT( setWidgetDirty() )); - parent->connect(check, SIGNAL( toggled(bool) ),parent, SLOT( setReadOnly(bool) )); - - } - } - return true; - } - - void setReadOnly(bool readOnly) - { - p.setReadOnly(readOnly); - w.setReadOnly(readOnly || vhelper::readOnly() || (check && !(check->checkState() == Qt::Checked))); - } - void readFromData(const data_type& d) - { - p.readFromData(d); - if (check) - { - const bool wasChecked = (check->checkState() == Qt::Checked); - const bool isChecked = vhelper::isChecked(d); - if (isChecked != wasChecked) - { - check->setChecked(isChecked); - if (check->isEnabled()) - w.setReadOnly(!isChecked); - } - } - w.readFromData(*vhelper::get(d)); - } - void readConstantsFromData(const data_type& d) - { - p.readConstantsFromData(d); - if (vhelper::readOnly()) - { - if (check) - { - check->setChecked(vhelper::isChecked(d)); - } - w.readFromData(*vhelper::get(d)); - } - } - void writeToData(data_type& d) - { - p.writeToData(d); - if (check) - { - bool isChecked = (check->checkState() == Qt::Checked); - vhelper::setChecked(isChecked, d); - } - value_type v = *vhelper::get(d); - w.writeToData(v); - vhelper::set(v,d); - if ( N == struct_data_trait::NVAR ) - { - shelper::set(d); - readConstantsFromData(d); // reread constant fields - } - } -}; - -template -class struct_data_widget_container< T, 0 > -{ -public: - typedef T data_type; - typedef struct_data_trait shelper; - typedef QVBoxLayout MasterLayout; - typedef QHBoxLayout Layout ; - MasterLayout* master_layout; - Layout* container_layout; - struct_data_widget_container():master_layout(nullptr),container_layout(nullptr) {} - - void setMasterLayout(MasterLayout* /*layout*/) - { - } - - bool createLayout( DataWidget* /*parent*/ ) - { - return true; - } - - bool createLayout( QLayout* /*layout*/) - { - return true; - } - - bool createWidgets(DataWidget * /*parent*/, const data_type& /*d*/, bool /*readOnly*/) - { - return true; - } - void setReadOnly(bool /*readOnly*/) - { - } - void readFromData(const data_type& /*d*/) - { - } - void readConstantsFromData(const data_type& /*d*/) - { - } - void writeToData(data_type& /*d*/) - { - } - - void insertWidgets() - { - } - -}; - -template -class default_struct_data_trait_var -{ -public: - typedef T data_type; - static const char* name() { return nullptr; } - static const char* shortname() { return nullptr; } - static bool readOnly() { return false; } - static bool isCheckable() { return false; } - static bool isChecked(const data_type& /*d*/) { return true; } - static void setChecked(bool /*b*/, data_type& /*d*/) {} -}; - -#define STRUCT_DATA_VAR(parent, vid, vname, sname, vtype, var) \ - class struct_data_trait_var < parent, vid > : public default_struct_data_trait_var < parent, vid > \ - { \ - public: \ - typedef parent data_type; \ - typedef vtype value_type; \ - static const char* name() { return vname; } \ - static const char* shortname() { return sname; } \ - static const value_type* get(const data_type& d) { return &(d.var); } \ - static void set( const value_type& v, data_type& d) { d.var = v; } \ - } - -#define STRUCT_DATA_VAR_READONLY(parent, vid, vname, sname, vtype, var) \ - class struct_data_trait_var < parent, vid > : public default_struct_data_trait_var < parent, vid > \ - { \ - public: \ - typedef parent data_type; \ - typedef vtype value_type; \ - static const char* name() { return vname; } \ - static const char* shortname() { return sname; } \ - static bool readOnly() { return true; } \ - static const value_type* get(const data_type& d) { return &(d.var); } \ - static void set( const value_type& v, data_type& d) { d.var = v; } \ - } - -#define STRUCT_DATA_VAR_CHECK(parent, vid, vname, sname, vtype, var, check) \ - class struct_data_trait_var < parent, vid > : public default_struct_data_trait_var < parent, vid > \ - { \ - public: \ - typedef parent data_type; \ - typedef vtype value_type; \ - static const char* name() { return vname; } \ - static const char* shortname() { return sname; } \ - static const value_type* get(const data_type& d) { return &(d.var); } \ - static void set( const value_type& v, data_type& d) { d.var = v; } \ - static bool isCheckable() { return true; } \ - static bool isChecked(const data_type& d) { return d.check; } \ - static void setChecked(bool b, data_type& d) { d.check = b; } \ - } - -// A comma can't appear in a macro argument... -#define COMMA , - - -//////////////////////////////////////////////////////////////// -/// Rigids (as data-structures) support -//////////////////////////////////////////////////////////////// - -template -class struct_data_trait < sofa::defaulttype::RigidCoord > -{ -public: - typedef sofa::defaulttype::RigidCoord data_type; - enum { NVAR = 2 }; - static void set( data_type& /*d*/ ) - { - } -}; -template STRUCT_DATA_VAR(sofa::defaulttype::RigidCoord<3 COMMA T>, 0, "Center", "", typename data_type::Vec3, getCenter()); -template STRUCT_DATA_VAR(sofa::defaulttype::RigidCoord<3 COMMA T>, 1, "Orientation", "", typename data_type::Quat, getOrientation()); - -template STRUCT_DATA_VAR(sofa::defaulttype::RigidCoord<2 COMMA T>, 0, "Center", "", typename data_type::Vec2, getCenter()); -template STRUCT_DATA_VAR(sofa::defaulttype::RigidCoord<2 COMMA T>, 1, "Orientation", "A", typename data_type::Real, getOrientation()); - -template -class data_widget_container < sofa::defaulttype::RigidCoord > : public struct_data_widget_container < sofa::defaulttype::RigidCoord > -{}; - -template -class struct_data_trait < sofa::defaulttype::RigidMass > -{ -public: - typedef sofa::defaulttype::RigidMass data_type; - enum { NVAR = 4 }; - static void set( data_type& d) - { - d.recalc(); - } -}; - -template STRUCT_DATA_VAR(sofa::defaulttype::RigidMass, 0, "Mass", "Mass", T, mass); -template STRUCT_DATA_VAR(sofa::defaulttype::RigidMass, 1, "Volume", "Vol", T, volume); -template STRUCT_DATA_VAR(sofa::defaulttype::RigidMass<2 COMMA T>, 2, "Inertia Matrix", "Inertia", T, inertiaMatrix); -template STRUCT_DATA_VAR(sofa::defaulttype::RigidMass<3 COMMA T>, 2, "Inertia Matrix", "Inertia", typename data_type::Mat3x3, inertiaMatrix); -template STRUCT_DATA_VAR_READONLY(sofa::defaulttype::RigidMass<2 COMMA T>, 3, "Inertia Mass Matrix", "InertialMass", T, inertiaMassMatrix); -template STRUCT_DATA_VAR_READONLY(sofa::defaulttype::RigidMass<3 COMMA T>, 3, "Inertia Mass Matrix", "InertialMass", typename data_type::Mat3x3, inertiaMassMatrix); - -template -class data_widget_container < sofa::defaulttype::RigidMass > : public struct_data_widget_container < sofa::defaulttype::RigidMass > -{}; - - -//////////////////////////////////////////////////////////////// -/// sofa::component::forcefield::LinearSpring support -//////////////////////////////////////////////////////////////// - -#define CLASS typename sofa::component::solidmechanics::spring::LinearSpring< T > - -template -class struct_data_trait < CLASS > -{ -public: - typedef CLASS data_type; - enum { NVAR = 5 }; - static void set( data_type& /*d*/) - { - } -}; - -template STRUCT_DATA_VAR(CLASS, 0, "Index 1", "Index 1", sofa::Index, m1); -template STRUCT_DATA_VAR(CLASS, 1, "Index 2", "Index 2", sofa::Index, m2); -template STRUCT_DATA_VAR(CLASS, 2, "Stiffness", "Ks", T, ks); -template STRUCT_DATA_VAR(CLASS, 3, "Damping", "Kd", T, kd); -template STRUCT_DATA_VAR(CLASS, 4, "Rest Length", "L", T, initpos); - -template -class data_widget_container < CLASS > : public struct_data_widget_container < CLASS > -{}; - -#undef CLASS - -//////////////////////////////////////////////////////////////// -/// sofa::component::forcefield::JointSpring support -//////////////////////////////////////////////////////////////// - -#define CLASS typename sofa::component::solidmechanics::spring::JointSpring< T > - -template -class struct_data_trait < CLASS > -{ -public: - typedef CLASS data_type; - enum { NVAR = 27 }; - static void set( data_type& /*d*/) - { - } -}; - -template STRUCT_DATA_VAR(CLASS, 0, "Index 1", "Index 1", sofa::Index, m1); -template STRUCT_DATA_VAR(CLASS, 1, "Index 2", "Index 2", sofa::Index, m2); -template STRUCT_DATA_VAR(CLASS, 2, "Trans X Axis", "Trans X Axis", bool, freeMovements[0]); -template STRUCT_DATA_VAR(CLASS, 3, "Trans Y Axis", "Trans Y Axis", bool, freeMovements[1]); -template STRUCT_DATA_VAR(CLASS, 4, "Trans Z Axis", "Trans Z Axis", bool, freeMovements[2]); -template STRUCT_DATA_VAR(CLASS, 5, "Rot X Axis", "Rot X Axis", bool, freeMovements[3]); -template STRUCT_DATA_VAR(CLASS, 6, "Rot Y Axis", "Rot Y Axis", bool, freeMovements[4]); -template STRUCT_DATA_VAR(CLASS, 7, "Rot Z Axis", "Rot Z Axis", bool, freeMovements[5]); -template STRUCT_DATA_VAR(CLASS, 8, "Soft Stiffness Translation", "Soft Ks Trans", typename data_type::Real, softStiffnessTrans); -template STRUCT_DATA_VAR(CLASS, 9, "Hard Stiffness Translation", "Hard Ks Trans", typename data_type::Real, hardStiffnessTrans); -template STRUCT_DATA_VAR(CLASS, 10, "Soft Stiffness Rotation", "Soft Ks Rot", typename data_type::Real, softStiffnessRot); -template STRUCT_DATA_VAR(CLASS, 11, "Hard Stiffness Rotation", "Hard Ks Rot", typename data_type::Real, hardStiffnessRot); -template STRUCT_DATA_VAR(CLASS, 12, "Bloc Stiffness Rotation", "Bloc Ks Rot", typename data_type::Real, blocStiffnessRot); -template STRUCT_DATA_VAR(CLASS, 13, "Damping", "Kd", typename data_type::Real, kd); -template STRUCT_DATA_VAR(CLASS, 14, "Min Angle X", "Min Angle X", typename data_type::Real, limitAngles[0]); -template STRUCT_DATA_VAR(CLASS, 15, "Max Angle X", "Max Angle X", typename data_type::Real, limitAngles[1]); -template STRUCT_DATA_VAR(CLASS, 16, "Min Angle Y", "Min Angle Y", typename data_type::Real, limitAngles[2]); -template STRUCT_DATA_VAR(CLASS, 17, "Max Angle Y", "Max Angle Y", typename data_type::Real, limitAngles[3]); -template STRUCT_DATA_VAR(CLASS, 18, "Min Angle Z", "Min Angle Z", typename data_type::Real, limitAngles[4]); -template STRUCT_DATA_VAR(CLASS, 19, "Max Angle Z", "Max Angle Z", typename data_type::Real, limitAngles[5]); - -template STRUCT_DATA_VAR(CLASS, 20, "Initial length of the spring X", "L init spring X", typename data_type::Real, initTrans[0]); -template STRUCT_DATA_VAR(CLASS, 21, "Initial length of the spring Y", "L init spring Y", typename data_type::Real, initTrans[1]); -template STRUCT_DATA_VAR(CLASS, 22, "Initial length of the spring Z", "L init spring Z", typename data_type::Real, initTrans[2]); - -template STRUCT_DATA_VAR(CLASS, 23, "Initial rotation of the spring X", "Rot init spring X", SReal, initRot[0]); -template STRUCT_DATA_VAR(CLASS, 24, "Initial rotation of the spring Y", "Rot init spring Y", SReal, initRot[1]); -template STRUCT_DATA_VAR(CLASS, 25, "Initial rotation of the spring Z", "Rot init spring Z", SReal, initRot[2]); -template STRUCT_DATA_VAR(CLASS, 26, "Initial rotation of the spring W", "Rot init spring W", SReal, initRot[3]); - -template -class data_widget_container < CLASS > : public struct_data_widget_container < CLASS > -{}; - -#undef CLASS - -//////////////////////////////////////////////////////////////// -/// sofa::component::forcefield::GearSpring support -//////////////////////////////////////////////////////////////// - -#define CLASS typename sofa::component::solidmechanics::spring::GearSpring< T > - -template -class struct_data_trait < CLASS > -{ -public: - typedef CLASS data_type; - enum { NVAR = 10 }; - static void set( data_type& /*d*/) - { - } -}; - -template STRUCT_DATA_VAR(CLASS, 0, "Parent 1", "Parent 1", unsigned int, p1); -template STRUCT_DATA_VAR(CLASS, 1, "Index 1", "Index 1", unsigned int, m1); -template STRUCT_DATA_VAR(CLASS, 2, "Parent 2", "Parent 2", unsigned int, p2); -template STRUCT_DATA_VAR(CLASS, 3, "Index 2", "Index 2", unsigned int, m2); -template STRUCT_DATA_VAR(CLASS, 4, "Axis 1", "Axis 1", unsigned int, freeAxis[0]); -template STRUCT_DATA_VAR(CLASS, 5, "Axis 2", "Axis 2", unsigned int, freeAxis[1]); -template STRUCT_DATA_VAR(CLASS, 6, "Pivot Stiffness Translation", "Ks Trans", typename data_type::Real, hardStiffnessTrans); -template STRUCT_DATA_VAR(CLASS, 7, "Gear Stiffness Rotation", "Gear Ks Rot", typename data_type::Real, softStiffnessRot); -template STRUCT_DATA_VAR(CLASS, 8, "Pivot Stiffness Rotation", "Pivot Ks Rot", typename data_type::Real, hardStiffnessRot); -template STRUCT_DATA_VAR(CLASS, 9, "Damping", "Kd", typename data_type::Real, kd); - -template -class data_widget_container < CLASS > : public struct_data_widget_container < CLASS > -{}; - -#undef CLASS - - -//////////////////////////////////////////////////////////////// -/// sofa::type::Material support -//////////////////////////////////////////////////////////////// - -template<> -class struct_data_trait < sofa::type::Material > -{ -public: - typedef sofa::type::Material data_type; - enum { NVAR = 6 }; - static void set( data_type& /*d*/) - { - } -}; - -template<> STRUCT_DATA_VAR(sofa::type::Material, 0, "Name", "Name", std::string, name); -template<> STRUCT_DATA_VAR_CHECK(sofa::type::Material, 1, "Ambient", "Amb", sofa::type::RGBAColor, ambient, useAmbient); -template<> STRUCT_DATA_VAR_CHECK(sofa::type::Material, 2, "Diffuse", "Diff", sofa::type::RGBAColor, diffuse, useDiffuse); -template<> STRUCT_DATA_VAR_CHECK(sofa::type::Material, 3, "Specular", "Spec", sofa::type::RGBAColor, specular, useSpecular); -template<> STRUCT_DATA_VAR_CHECK(sofa::type::Material, 4, "Emissive", "Emm", sofa::type::RGBAColor, emissive, useEmissive); -template<> STRUCT_DATA_VAR_CHECK(sofa::type::Material, 5, "Shininess", "Shin", float, shininess, useShininess); - -template<> -class data_widget_container < sofa::type::Material > : public struct_data_widget_container < sofa::type::Material > -{}; - - - -//////////////////////////////////////////////////////////////// -/// sofa::component::interactionforcefield::PenalityContactForceField Contact support -//////////////////////////////////////////////////////////////// - -#define CLASS typename sofa::component::collision::response::contact::PenalityContact< T > - -template -class struct_data_trait < CLASS > -{ -public: - typedef CLASS data_type; - enum { NVAR = 9 }; - static void set(data_type& /*d*/) - { - } -}; - -template STRUCT_DATA_VAR(CLASS, 0, "VertexId 1", "VertexId 1", sofa::Index, m1); -template STRUCT_DATA_VAR(CLASS, 1, "VertexId 2", "VertexId 2", sofa::Index, m2); -template STRUCT_DATA_VAR(CLASS, 2, "ElemId 1", "ElemId 1", sofa::Index, index1); -template STRUCT_DATA_VAR(CLASS, 3, "ElemId 2", "ElemId 2", sofa::Index, index2); - -template STRUCT_DATA_VAR(CLASS, 4, "Normal", "Norm", typename data_type::Deriv, norm); -template STRUCT_DATA_VAR(CLASS, 5, "Distance", "Dist", typename data_type::Real, dist); - -template STRUCT_DATA_VAR(CLASS, 6, "Stiffness", "Ks", typename data_type::Real, ks); -template STRUCT_DATA_VAR(CLASS, 7, "Penetration", "Pene", typename data_type::Real, pen); -template STRUCT_DATA_VAR(CLASS, 8, "Age", "Age", int, age); - -template -class data_widget_container < CLASS > : public struct_data_widget_container < CLASS > -{}; - -#undef CLASS - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.cpp deleted file mode 100644 index e422128db4e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "TableDataWidget.h" -#include -#include -#include - -namespace sofa::gui::qt -{ - -using sofa::helper::Creator; -using sofa::type::fixed_array; -using namespace sofa::type; -using namespace sofa::defaulttype; - -Creator, TABLE_HORIZONTAL > > DWClass_vectori("default",true); -Creator, TABLE_HORIZONTAL > > DWClass_vectoru("default",true); -Creator, TABLE_HORIZONTAL > > DWClass_vectorf("default",true); -Creator, TABLE_HORIZONTAL > > DWClass_vectord("default",true); -Creator > > DWClass_vectorstring("default",true); - -Creator > DWClass_SeqEdges ("default",true); -Creator > DWClass_SeqTriangles ("default",true); -Creator > DWClass_SeqQuads ("default",true); -Creator > DWClass_SeqTetrahedra("default",true); -Creator > DWClass_SeqHexahedra ("default",true); - -Creator > > > DWClass_vectorVec1i("default",true); -Creator > > > DWClass_vectorVec1u("default",true); -Creator > > > DWClass_vectorVec1f("default",true); -Creator > > > DWClass_vectorVec1d("default",true); -Creator > > > DWClass_vectorVec2i("default",true); -Creator > > > DWClass_vectorVec2u("default",true); -Creator > > > DWClass_vectorVec2f("default",true); -Creator > > > DWClass_vectorVec2d("default",true); -Creator > > > DWClass_vectorVec3i("default",true); -Creator > > > DWClass_vectorVec3u("default",true); -Creator > > > DWClass_vectorVec3f("default",true); -Creator > > > DWClass_vectorVec3d("default",true); -Creator > > > DWClass_vectorVec4i("default",true); -Creator > > > DWClass_vectorVec4u("default",true); -Creator > > > DWClass_vectorVec4f("default",true); -Creator > > > DWClass_vectorVec4d("default",true); -Creator > > > DWClass_vectorVec6i("default",true); -Creator > > > DWClass_vectorVec6u("default",true); -Creator > > > DWClass_vectorVec6f("default",true); -Creator > > > DWClass_vectorVec6d("default",true); -Creator > > > DWClass_vectorVec8i("default",true); -Creator > > > DWClass_vectorVec8u("default",true); - -Creator > > > DWClass_vectorA1i("default",true); -Creator > > > DWClass_vectorA1u("default",true); -Creator > > > DWClass_vectorA2i("default",true); -Creator > > > DWClass_vectorA2u("default",true); -Creator > > > DWClass_vectorA3i("default",true); -Creator > > > DWClass_vectorA3u("default",true); -Creator > > > DWClass_vectorA3f("default",true); -Creator > > > DWClass_vectorA3d("default",true); -Creator > > > DWClass_vectorA4i("default",true); -Creator > > > DWClass_vectorA4u("default",true); -Creator > > > DWClass_vectorA6i("default",true); -Creator > > > DWClass_vectorA6u("default",true); -Creator > > > DWClass_vectorA8i("default",true); -Creator > > > DWClass_vectorA8u("default",true); - -#if !defined(_MSC_VER) && !defined(__clang__) -Creator > > > DWClass_stdvectorA1i("default",true); -Creator > > > DWClass_stdvectorA1u("default",true); -Creator > > > DWClass_stdvectorA2i("default",true); -Creator > > > DWClass_stdvectorA2u("default",true); -Creator > > > DWClass_stdvectorA3i("default",true); -Creator > > > DWClass_stdvectorA3u("default",true); -Creator > > > DWClass_stdvectorA4i("default",true); -Creator > > > DWClass_stdvectorA4u("default",true); -Creator > > > DWClass_stdvectorA6i("default",true); -Creator > > > DWClass_stdvectorA6u("default",true); -Creator > > > DWClass_stdvectorA8i("default",true); -Creator > > > DWClass_stdvectorA8u("default",true); -#endif - -Creator > > > DWClass_vectorQuatf("default",true); -Creator > > > DWClass_vectorQuatd("default",true); - -Creator > > > DWClass_vectorPolynomialLD5d("default",true); -Creator > > > DWClass_vectorPolynomialLD4d("default",true); -Creator > > > DWClass_vectorPolynomialLD3d("default",true); -Creator > > > DWClass_vectorPolynomialLD2d("default",true); - -Creator > > > DWClass_vectorPolynomialLD5f("default",true); -Creator > > > DWClass_vectorPolynomialLD4f("default",true); -Creator > > > DWClass_vectorPolynomialLD3f("default",true); -Creator > > > DWClass_vectorPolynomialLD2f("default",true); - -Creator > > > DWClass_vectorRigidCoord2f("default",true); -Creator > > > DWClass_vectorRigidCoord2d("default",true); -Creator > > > DWClass_vectorRigidCoord3f("default",true); -Creator > > > DWClass_vectorRigidCoord3d("default",true); - -Creator > > > DWClass_vectorLinearSpringf("default",true); -Creator > > > DWClass_vectorLinearSpringd("default",true); - -Creator > > > DWClass_vectorJointSpring3f("default",true); -Creator > > > DWClass_vectorGearSpring3f("default",true); - -Creator > > > DWClass_vectorPenalityContact("default",true); - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.h deleted file mode 100644 index fbcc179beff..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/TableDataWidget.h +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "SimpleDataWidget.h" -#include "StructDataWidget.h" -#include - -#include "QModelViewTableDataContainer.h" - - -namespace sofa::gui::qt -{ - -template -class TableDataWidget : public SimpleDataWidget > -{ -public: - typedef T data_type; - typedef SimpleDataWidget > Inherit; - typedef sofa::core::objectmodel::Data MyData; -public: - TableDataWidget(QWidget* parent,const char* name, MyData* d) : Inherit(parent,name,d) {} - virtual unsigned int sizeWidget() {return 8;} - virtual unsigned int numColumnWidget() { return 1; } -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/VideoRecorderManager.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/VideoRecorderManager.ui deleted file mode 100644 index 863031a3b83..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/VideoRecorderManager.ui +++ /dev/null @@ -1,188 +0,0 @@ - - - VideoRecorderManager - - - true - - - - 0 - 0 - 600 - 400 - - - - VideoRecorderManager - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - RecordingType - - - - - 20 - 20 - 380 - 20 - - - - List of Screenshots - - - true - - - - - - 20 - 40 - 430 - 16 - - - - Movie file encoded with FFMPEG - - - - - - - - - 0 - 0 - - - - Options - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 80 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 237 - 20 - - - - - - - - &Close - - - Alt+C - - - true - - - - - - - - - - - - buttonClose - clicked() - VideoRecorderManager - close() - - - 20 - 20 - - - 20 - 20 - - - - - ScreenshotsRecordingTypeRadioButton - clicked(bool) - VideoRecorderManager - onChangeRecordingType() - - - 20 - 20 - - - 20 - 20 - - - - - MovieRecordingTypeRadioButton - clicked(bool) - VideoRecorderManager - onChangeRecordingType() - - - 20 - 20 - - - 20 - 20 - - - - - - onChangeRecordingType() - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/VisitorGUI.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/VisitorGUI.ui deleted file mode 100644 index 053428f04c9..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/VisitorGUI.ui +++ /dev/null @@ -1,89 +0,0 @@ - - - VisitorGUI - - - - 0 - 0 - 1000 - 550 - - - - VisitorGUI - - - - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - - - Graph - - - false - - - true - - - - - Time - - - false - - - false - - - - - Type - - - false - - - false - - - - - Value - - - false - - - true - - - - - - - - - - - - - - graphView - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.cpp deleted file mode 100644 index 552e61850b3..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -/* -------------------------------------------------------- */ -#include -#include "WDoubleLineEdit.h" -#include -/* -------------------------------------------------------- */ - -WDoubleLineEdit::WDoubleLineEdit(QWidget *parent,const char *name) : QLineEdit(parent /*,name */) -{ - setObjectName(name); - setFocusPolicy( Qt::StrongFocus ); - - m_iPercent=-1; - m_fMinValue=0.0; - m_fMaxValue=1.0; - m_fValue=0.0; - m_bFirst=true; - m_DblValid=new QDoubleValidator(m_fMinValue,m_fMaxValue,20,this); - m_isDragging = false ; - setValidator(m_DblValid); - - connect(this,SIGNAL(returnPressed()), - this,SLOT (slotReturnPressed())); - - m_bInternal=false; - this->setText(QString("%1").arg(m_fValue)); - this->setCursorPosition(0); - this->setSelection(0, 0); -} -/* -------------------------------------------------------- */ -void WDoubleLineEdit::slotReturnPressed() -{ - m_bInternal=true; - - slotCalcValue(text().toDouble()); - -} -/* -------------------------------------------------------- */ -void WDoubleLineEdit::slotCalcValue(double f, bool isEditted) -{ - int p; - - if (f < m_fMinValue) - f=m_fMinValue; - else if (f > m_fMaxValue) - f=m_fMaxValue; - if (f != m_fValue || m_bFirst) - { - m_bFirst=false; - m_fValue=f; - if(isEditted) - emit (valueEdited(f)); - else - emit (valueChanged(f)); - - p=(int)(100.0*(f - m_fMinValue)/(m_fMaxValue - m_fMinValue)); - if (p != m_iPercent) - { - emit (valuePercentChanged(p)); - m_iPercent=p; - } - update(); - } - - this->setText(QString("%1").arg(m_fValue)); - this->setCursorPosition(0); - this->setSelection(0, 0); -} -/* -------------------------------------------------------- */ -void WDoubleLineEdit::slotCalcValue(const QString& s) -{ - slotCalcValue(s.toDouble()); -} -/* -------------------------------------------------------- */ -void WDoubleLineEdit::setValue(double f) -{ - m_bInternal=true; - slotCalcValue(f); -} - -void WDoubleLineEdit::setIntValue(int f) -{ - setValue(static_cast(f)); -} - -/* -------------------------------------------------------- */ -void WDoubleLineEdit::setValuePercent(int p) -{ - if (!m_bInternal) - setValue(m_fMinValue + (m_fMaxValue - m_fMinValue)*((double)p)/99.0); - else - m_bInternal=false; -} - -/* -------------------------------------------------------- */ -int WDoubleLineEdit::valuePercent() -{ - return ((int)(99.0*(m_fValue - m_fMinValue)/(m_fMaxValue - m_fMinValue))); -} - -/* -------------------------------------------------------- */ -void WDoubleLineEdit::keyPressEvent(QKeyEvent *e) -{ - if (e->key() == Qt::Key_Escape) - { - this->setText(QString("%1").arg(m_fValue)); - this->setCursorPosition(0); - this->setSelection(0, 0); - } - else - QLineEdit::keyPressEvent(e); -} -/* -------------------------------------------------------- */ -void WDoubleLineEdit::mouseMoveEvent(QMouseEvent *event) { - if(m_isDragging){ - const double dt=(event->x() - m_prevMousePosition.x())/100.0 ; - m_prevMousePosition = event->pos() ; - slotCalcValue(dt + m_fValue, false) ; - emit valueEdited(m_fValue) ; - } - QLineEdit::mouseMoveEvent(event) ; -} - -void WDoubleLineEdit::mousePressEvent(QMouseEvent *event) { - if(event->button() == Qt::LeftButton){ - m_isDragging = true ; - m_prevMousePosition = event->pos() ; - } - QLineEdit::mousePressEvent(event) ; -} - -void WDoubleLineEdit::mouseReleaseEvent(QMouseEvent *event) { - if(event->button() == Qt::LeftButton){ - m_isDragging = false ; - m_prevMousePosition = event->pos() ; - } - QLineEdit::mouseReleaseEvent(event) ; -} diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.h b/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.h deleted file mode 100644 index 27f4aeedd8c..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/WDoubleLineEdit.h +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -/* -------------------------------------------------------- */ -#pragma once -#include -#include -#include - -#include - -/* -------------------------------------------------------- */ -class SOFA_GUI_QT_API WDoubleLineEdit : public QLineEdit -{ - Q_OBJECT - Q_PROPERTY( double minValue READ minValue WRITE setMinValue ) - Q_PROPERTY( double maxValue READ maxValue WRITE setMaxValue ) - Q_PROPERTY( double Value READ Value WRITE setValue ) - Q_PROPERTY( int intValue READ intValue WRITE setIntValue ) - -protected: - - int m_iPercent; - double m_fMinValue; - double m_fMaxValue; - bool m_bFirst; - mutable double m_fValue; - QDoubleValidator *m_DblValid; - double m_bInternal; - - bool m_isDragging ; - QPoint m_prevMousePosition ; - - void checkValue(); - void keyPressEvent(QKeyEvent *) override; - - void mouseMoveEvent(QMouseEvent *) override ; - void mousePressEvent(QMouseEvent *) override ; - void mouseReleaseEvent(QMouseEvent *) override ; - -public: - - WDoubleLineEdit(QWidget *parent,const char *name); - - double minValue() const { return (m_fMinValue);} - double getMinValue() { emit(returnPressed()); return minValue();} - void setMinValue(double f) {m_fMinValue=f; m_DblValid->setBottom(m_fMinValue); } - - - double maxValue() const { return (m_fMaxValue);} - double getMaxValue() { emit(returnPressed()); return maxValue();} - void setMaxValue(double f) {m_fMaxValue=f; m_DblValid->setTop(m_fMaxValue); } - - double Value() const { return (m_fValue);} - double getValue() { emit(returnPressed()); return Value();} - void setValue(double f); - - int intValue() const { return static_cast(m_fValue);} - int getIntValue() { emit(returnPressed()); return intValue();} - void setIntValue(int f); - - int valuePercent(); - - //Return the value displayed: WARNING!! NO VALIDATION IS MADE! - double getDisplayedValue() {return text().toDouble();} - int getIntDisplayedValue() {return static_cast(text().toDouble());} - -signals: - void valueEdited(double) ; - void valueChanged(double); - void valuePercentChanged(int); - -protected slots: - - void slotCalcValue(const QString&); - void slotCalcValue(double, bool isEditted=false); - void slotReturnPressed(); - -public slots: - - void setValuePercent(int p); - -}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowProfiler.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/WindowProfiler.ui deleted file mode 100644 index fd2aff80bd8..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowProfiler.ui +++ /dev/null @@ -1,233 +0,0 @@ - - - WindowProfiler - - - true - - - - 0 - 0 - 950 - 760 - - - - AdvancedTimer profiler window - - - false - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - QLayout::SetFixedSize - - - - - - 75 - true - true - - - - Summary - - - - - - - - - Step Number: - - - - - - - Overhead due to the process of the timers. Close this window to avoid the overhead. - - - Overhead (ms) - - - - - - - 0 - - - - - - - Time (ms) - - - - - - - 0 - - - - - - - 0 - - - - - - - Number of timers in the current step - - - Timers Counter: - - - - - - - 0 - - - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Collapse all - - - - - - - - - - Expand all - - - - - - - - - - - - 5 - - - - 1 - - - - - 2 - - - - - 3 - - - - - 4 - - - - - 5 - - - - - - - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.cpp deleted file mode 100644 index 1129c61fb2b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ -QPixmap *WindowVisitor::icons[WindowVisitor::OTHER+1]; - -WindowVisitor::WindowVisitor(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - - this->setContextMenuPolicy(Qt::CustomContextMenu); - connect(graphView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT( rightClick(const QPoint&))); - - QImage * img[OTHER+1]; - img[NODE] = new QImage(10,10,QImage::Format_ARGB32); - - img[NODE]->fill(qRgba(0,0,0,0)); - // Workaround for qt 3.x where fill() does not set the alpha channel - for (int y=0 ; y < 10 ; y++) - for (int x=0 ; x < 10 ; x++) - img[NODE]->setPixel(x,y,qRgba(0,0,0,0)); - - for (int y=0 ; y < 10 ; y++) - img[NODE]->setPixel(0,y,qRgba(0,0,0,255)); - - - img[OTHER] = new QImage(img[NODE]->copy()); - - //BORDER!!!!------------------------------------- - for (int x=1; x <10 ; x++) - { - img[NODE] ->setPixel(x,0,qRgba(0,0,0,255)); - img[NODE] ->setPixel(x,9,qRgba(0,0,0,255)); - } - for (int y=0 ; y < 10 ; y++) - { - img[NODE] ->setPixel(0,y,qRgba(0,0,0,255)); - img[NODE] ->setPixel(9,y,qRgba(0,0,0,255)); - } - //----------------------------------------------- - - img[COMMENT] = new QImage(img[NODE]->copy()); - img[COMPONENT] = new QImage(img[NODE]->copy()); - - for (int y=0 ; y < 9 ; y++) - for (int x=0 ; x < 9 ; x++) - { - img[NODE] ->setPixel(x,y,qRgba(125,125,125,255)); - img[COMMENT]->setPixel(x,y,qRgba(255,255,0,255)); - img[COMPONENT]->setPixel(x,y,qRgba(255,0,255,255)); - } - - for (int y=0 ; y < 5 ; y++) - for (int x=0 ; x < 2*y+1 ; x++) - { - img[OTHER]->setPixel(x,y,qRgba(0,0,255,255)); - } - for (int y=5 ; y < 10 ; y++) - for (int x=0 ; x < 2*(10-y) ; x++) - { - img[OTHER] ->setPixel(x,y,qRgba(0,0,255,255)); - } - icons[NODE] = new QPixmap(QPixmap::fromImage(*img[NODE])); - icons[COMMENT] = new QPixmap(QPixmap::fromImage(*img[COMMENT])); - icons[COMPONENT] = new QPixmap(QPixmap::fromImage(*img[COMPONENT])); - icons[OTHER] = new QPixmap(QPixmap::fromImage(*img[OTHER])); - - statsWidget=new QWidget(splitterStats); - - QGridLayout *statsLayout=new QGridLayout(statsWidget); - - typeOfCharts = new QComboBox(statsWidget); - QStringList list; - list << "Latest execution" - << "Most time-consuming step" - << "Total execution time"; - - - splitterStats->addWidget(statsWidget); - typeOfCharts->insertItems(0,list); - - chartsComponent=new ChartsWidget("Component (name)", statsWidget); - chartsVisitor =new ChartsWidget("Visitor", statsWidget); - - statsLayout->addWidget(typeOfCharts,0,0); - statsLayout->addWidget(chartsComponent,1,0); - statsLayout->addWidget(chartsVisitor,2,0); - connect(typeOfCharts, SIGNAL(activated(int)), this, SLOT(setCurrentCharts(int))); - - - //Add Control Panel - controlPanel = new QVisitorControlPanel(splitterWindow); - connect( controlPanel, SIGNAL(focusOn(QString)), this, SLOT(focusOn(QString))); - connect( controlPanel, SIGNAL(clearGraph()), this, SLOT(clearGraph())); - controlPanel->setMaximumHeight(110); - -} - - -void WindowVisitor::setCharts(std::vector< dataTime >&latestC, std::vector< dataTime >&maxTC, std::vector< dataTime >&totalC, - std::vector< dataTime >&latestV, std::vector< dataTime >&maxTV, std::vector< dataTime >&totalV) -{ - componentsTime=latestC; - componentsTimeMax=maxTC; - componentsTimeTotal=totalC; - visitorsTime=latestV; - visitorsTimeMax=maxTV; - visitorsTimeTotal=totalV; - setCurrentCharts(typeOfCharts->currentIndex()); -} - - - -void WindowVisitor::setCurrentCharts(int type) -{ - switch(type) - { - case 0: - chartsComponent->setChart(componentsTime, componentsTime.size()); - chartsVisitor->setChart(visitorsTime, visitorsTime.size()); - break; - case 1: - chartsComponent->setChart(componentsTimeMax, componentsTimeMax.size()); - chartsVisitor->setChart(visitorsTimeMax, visitorsTimeMax.size()); - break; - case 2: - chartsComponent->setChart(componentsTimeTotal, componentsTimeTotal.size()); - chartsVisitor->setChart(visitorsTimeTotal, visitorsTimeTotal.size()); - break; - } -} - -void WindowVisitor::rightClick( const QPoint& point) -{ - QTreeWidgetItem *item = graphView->itemAt( point ); - - if (!item) return; - - QMenu *contextMenu = new QMenu ( this ); - contextMenu->setObjectName( "ContextMenu"); - - if(item->childCount()) - { - contextMenu->addAction("Collapse", this,SLOT(collapseNode())); - contextMenu->addAction("Expand", this,SLOT(expandNode())); - - contextMenu->exec ( this->mapToGlobal(point)); - } -} - -void WindowVisitor::focusOn(QString text) -{ - if(graphView->topLevelItemCount() < 1) return; - - bool found = false; - for(int i=0 ; itopLevelItemCount() && !found; i++) - { - QTreeWidgetItem *item = graphView->topLevelItem(i); - found = setFocusOn(item, text); - } - - graphView->clearSelection(); - -} - -bool WindowVisitor::setFocusOn(QTreeWidgetItem *item, QString text) -{ - for ( int c=0; ccolumnCount(); ++c) - { - if (item->text(c).contains(text, Qt::CaseInsensitive)) - { - if ( !graphView->currentItem() || - graphView->visualItemRect(graphView->currentItem()).topLeft().y() < graphView->visualItemRect(item).topLeft().y() ) - { -// graphView->ensureItemVisible(item); - graphView->scrollToItem(item); - graphView->clearSelection(); - graphView->setCurrentItem(item); - item->setExpanded(true); - return true; - } - } - } - - bool found = false; - for(int i=0 ; ichildCount() && !found; i++) - { - QTreeWidgetItem *child = item->child(i); - found = setFocusOn(child, text); - - } - - return found; -} - -void WindowVisitor::expandNode() -{ - expandNode(graphView->currentItem()); -} - -void WindowVisitor::expandNode(QTreeWidgetItem* item) -{ - if (!item) return; - - item->setExpanded( true ); - if ( item != NULL ) - { - QTreeWidgetItem* child; - - for(int i=0 ; ichildCount() ; i++) - { - child = item->child(i); - child->setExpanded( true ); - expandNode(item); - } - } -} - -void WindowVisitor::collapseNode() -{ - collapseNode(graphView->currentItem()); - QTreeWidgetItem* item = graphView->currentItem(); - QTreeWidgetItem* child; - - for(int i=0 ; ichildCount() ; i++) - { - child = item->child(i); - collapseNode(child); - } - - graphView->currentItem()->setExpanded(true); -} -void WindowVisitor::collapseNode(QTreeWidgetItem* item) -{ - if (!item) return; - - item->setExpanded(false); - - QTreeWidgetItem* child; - - for(int i=0 ; ichildCount() ; i++) - { - child = item->child(i); - collapseNode(child); - } -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.h b/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.h deleted file mode 100644 index 70a2dd602aa..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/WindowVisitor.h +++ /dev/null @@ -1,125 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -class WindowVisitor: public QDialog, public Ui_VisitorGUI -{ - Q_OBJECT -public: - enum componentType {NODE, COMMENT, COMPONENT, VECTOR, OTHER}; - WindowVisitor(QWidget *parent); - - void collapseNode(QTreeWidgetItem* item); - void expandNode(QTreeWidgetItem* item); - - void setCharts(std::vector< dataTime >&latestC, std::vector< dataTime >&maxTC, std::vector< dataTime >&totalC, - std::vector< dataTime >&latestV, std::vector< dataTime >&maxTV, std::vector< dataTime >&totalV); - - -public slots: - void setCurrentCharts(int); - - void rightClick( const QPoint& point); - - void collapseNode(); - void expandNode(); - - void focusOn(QString focus); - - static componentType getComponentType(std::string name) - { - if (name == "Node") - return NODE; - else if (name == "Component") - return COMPONENT; - else if (name == "Vector") - return VECTOR; - else - return OTHER; - } - - static QPixmap* getPixmap(componentType t) {return icons[t];} - - void closeEvent( QCloseEvent* ) - { - emit(WindowVisitorClosed(false)); - hide(); - clearGraph(); - } - - void clearGraph() - { - graphView->clear(); - chartsComponent->clear(); - chartsVisitor->clear(); - - componentsTime.clear(); - componentsTimeMax.clear(); - componentsTimeTotal.clear(); - - - visitorsTime.clear(); - visitorsTimeMax.clear(); - visitorsTimeTotal.clear(); - } - -signals: - void WindowVisitorClosed(bool); -public: - - QWidget *statsWidget; -protected: - bool setFocusOn(QTreeWidgetItem *item, QString text); - - static QPixmap *icons[OTHER+1]; - - std::vector< dataTime > componentsTime; - std::vector< dataTime > visitorsTime; - - std::vector< dataTime > componentsTimeTotal; - std::vector< dataTime > visitorsTimeTotal; - - std::vector< dataTime > componentsTimeMax; - std::vector< dataTime > visitorsTimeMax; - - QVisitorControlPanel *controlPanel; - ChartsWidget *chartsComponent; - ChartsWidget *chartsVisitor; - QComboBox *typeOfCharts; -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/config.h.in b/Sofa/GUI/Qt/src/sofa/gui/qt/config.h.in deleted file mode 100644 index 139c5da8873..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/config.h.in +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#cmakedefine01 SOFA_GUI_QT_ENABLE_QTVIEWER -#cmakedefine01 SOFA_GUI_QT_ENABLE_QGLVIEWER -#cmakedefine01 SOFA_GUI_QT_ENABLE_NATIVE_MENU -#cmakedefine01 SOFA_GUI_QT_ENABLE_VSYNC - -#cmakedefine01 SOFA_GUI_QT_HAVE_QT5_CHARTS -#cmakedefine01 SOFA_GUI_QT_HAVE_QT6_CHARTS -#cmakedefine01 SOFA_GUI_QT_HAVE_QT5_WEBENGINE -#cmakedefine01 SOFA_GUI_QT_HAVE_QT6_WEBENGINECORE - -#define SOFA_GUI_QT_HAVE_QT_CHARTS (SOFA_GUI_QT_HAVE_QT5_CHARTS || SOFA_GUI_QT_HAVE_QT6_CHARTS) -#define SOFA_GUI_QT_HAVE_QT_WEBENGINE (SOFA_GUI_QT_HAVE_QT5_WEBENGINE || SOFA_GUI_QT_HAVE_QT6_WEBENGINECORE) - -// Equals to SOFA_GUI_QT_ENABLE_NODEGRAPH -#cmakedefine01 SOFA_GUI_QT_HAVE_NODEEDITOR - -#ifdef SOFA_BUILD_SOFA_GUI_QT -# define SOFA_GUI_QT_API SOFA_EXPORT_DYNAMIC_LIBRARY -#else -# define SOFA_GUI_QT_API SOFA_IMPORT_DYNAMIC_LIBRARY -#endif - -namespace sofa::gui::qt -{ - constexpr const char* MODULE_NAME = "@PROJECT_NAME@"; - constexpr const char* MODULE_VERSION = "@PROJECT_VERSION@"; -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.cpp deleted file mode 100644 index c724024a69a..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "SofaComponentNodeModel.h" -#include - -SofaComponentNodeData::SofaComponentNodeData() - : m_bData(nullptr) -{ - -} - -SofaComponentNodeData::SofaComponentNodeData(sofa::core::objectmodel::BaseData* bData) - : m_bData(bData) -{ - -} - -sofa::core::objectmodel::BaseData* SofaComponentNodeData::getData() -{ - //m_bData->updateIfDirty(); ?? - return m_bData; -} - -NodeDataType SofaComponentNodeData::type() const -{ - return NodeDataType{ "SofaComponentNodeData", - "My Sofa Node Data" }; -} - - -SofaComponentNodeModel::SofaComponentNodeModel(std::string name) - : NodeDataModel() - , debugNodeGraph(true) - , m_SofaObject(nullptr) -{ - m_uniqName = QString::fromStdString(name); - m_caption = m_uniqName; -} - -SofaComponentNodeModel::SofaComponentNodeModel(sofa::core::objectmodel::BaseObject* _sofaObject, bool debugMode) - : NodeDataModel() - , debugNodeGraph(debugMode) - , m_SofaObject(_sofaObject) -{ - if (m_SofaObject == nullptr) - { - msg_error("SofaComponentNodeModel") << "Sofa BaseObject is null, Node graph initialisation failed."; - m_uniqName = "ErrorNode"; - } - else - { - parseSofaObjectData(); - } -} - - -void SofaComponentNodeModel::parseSofaObjectData() -{ - if (m_SofaObject == nullptr) - { - msg_error("SofaComponentNodeModel") << "Sofa BaseObject is null, Node graph parseSofaObjectData failed."; - return; - } - - // first add this object name as first Data (to be used for the links representation) - QString SObjectName = QString::fromStdString(m_SofaObject->getName()); - m_data.push_back(std::pair(SObjectName, "name")); - - // parse links - const sofa::core::objectmodel::Base::VecLink& links = m_SofaObject->getLinks(); - for (auto link : links) - { - const std::string& name = link->getName(); - // ignore unnamed link - if (link->getName().empty()) - continue; - - // ignore link to context - if (link->getName() == "context") - continue; - - if (!link->storePath() && 0 == link->getSize()) - continue; - - const std::string valuetype = link->getValueTypeString(); - - msg_info_when(debugNodeGraph, "SofaComponentNodeModel") << "## link: " << name << " | link->getSize(): " << link->getSize() << " | valuetype: " << valuetype << " | path: " << link->storePath(); - - std::string linkPath = link->getLinkedPath(); - linkPath.erase(0, 1); // remove @ - std::size_t found = linkPath.find_last_of("/"); - if (found != std::string::npos) // remove path - linkPath.erase(0, found); - - msg_info_when(debugNodeGraph, "SofaComponentNodeModel") << " # baselink: " << linkPath; - QString parentObject = QString::fromStdString(linkPath); - m_dataConnections[SObjectName] = std::pair(parentObject, parentObject); - } - - // parse all Data - sofa::type::vector allData = m_SofaObject->getDataFields(); - for (auto data : allData) - { - QString name = QString::fromStdString(data->getName()); - QString group = QString::fromStdString(data->getGroup()); - - bool toBeIgnored = false; - for (auto idata : ignoredData) - { - if (name.compare(idata) == 0) - { - toBeIgnored = true; - break; - } - } - - if (group == "Visualization") - toBeIgnored = true; - - - if (toBeIgnored) - continue; - - sofa::core::objectmodel::BaseData* pData = data->getParent(); - if (pData) - { - QString parentObject = QString::fromStdString(pData->getOwner()->getName()); - QString parentData = QString::fromStdString(pData->getName()); - msg_info_when(debugNodeGraph, "SofaComponentNodeModel") << "- Parent: " << pData->getName() << " owwner: " << pData->getOwner()->getName(); - m_dataConnections[name] = std::pair(parentObject, parentData); - } - - if (!group.isEmpty()) - { - msg_info_when(debugNodeGraph, "SofaComponentNodeModel") << name.toStdString() << " -> " << data->getGroup(); - } - m_data.push_back(std::pair(name, QString::fromStdString(data->getValueTypeString()))); - m_Nodedata.push_back(std::make_shared(data)); - } -} - - -QtNodes::PortIndex SofaComponentNodeModel::getDataInputId(const QString& dataName) -{ - int cpt = 0; - for (auto data : m_data) - { - if (data.first.compare(dataName) == 0) - return cpt; - - cpt++; - } - - return QtNodes::INVALID; -} - - -unsigned int SofaComponentNodeModel::nPorts(PortType portType) const -{ - return m_data.size(); -} - -NodeDataType SofaComponentNodeModel::dataType(PortType portType, PortIndex portIndex) const -{ - if (portIndex >= 0 && portIndex < m_data.size()) - { - NodeDataType NType; - NType.id = m_data[portIndex].second; - NType.name = m_data[portIndex].first; - return NType; - } - - return SofaComponentNodeData().type(); -} - -std::shared_ptr SofaComponentNodeModel::outData(PortIndex port) -{ - // because the first port is the name of the component not stored in m_Nodedata: - port--; - - if (port > 0 && port < m_Nodedata.size()) - return m_Nodedata[port]; - else { - msg_warning(m_caption.toStdString()) << "Method SofaComponentNodeModel::outData port: " << port << " out of bounds: " << m_Nodedata.size(); - return nullptr; - } -} - -void SofaComponentNodeModel::setInData(std::shared_ptr data, int port) -{ - auto parentNodeData = std::dynamic_pointer_cast(data); - if (parentNodeData == nullptr) - { - msg_warning(m_caption.toStdString()) << "Method SofaComponentNodeModel::setInData SofaComponentNodeData cast failed."; - return; - } - - // because the first port is the name of the component not stored in m_Nodedata: - port--; - - if (port < 0 || port >= m_Nodedata.size()) - { - msg_warning(m_caption.toStdString()) << "Method SofaComponentNodeModel::setInData port: " << port << " out of bounds: " << m_Nodedata.size(); - return; - } - - // here you will implement the Data setParent in SOFA! - std::shared_ptr childNodeData = this->m_Nodedata[port]; - sofa::core::objectmodel::BaseData* childData = childNodeData->getData(); - sofa::core::objectmodel::BaseData* parentData = parentNodeData->getData(); - - msg_info_when(debugNodeGraph, m_caption.toStdString()) << "Here connect: {" << parentData->getOwner()->getName() << ", " << parentData->getName() << "} -> {" - << childData->getOwner()->getName() << ", " << childData->getName() << "}"; - -} \ No newline at end of file diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.h b/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.h deleted file mode 100644 index 19f7b102595..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/dataGraph/SofaComponentNodeModel.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#define NODE_EDITOR_SHARED - -#include - -#include -#include - -#include - -using QtNodes::NodeData; -using QtNodes::NodeDataType; -using QtNodes::NodeDataModel; -using QtNodes::PortType; -using QtNodes::PortIndex; - -namespace sofa::core::objectmodel -{ - class BaseObject; - class BaseData; -} // namespace sofa::core::objectmodel - -/// The class can potentially incapsulate any user data which -/// need to be transferred within the Node Editor graph -class SofaComponentNodeData : public NodeData -{ -public: - SofaComponentNodeData(); - SofaComponentNodeData(sofa::core::objectmodel::BaseData* bData); - - NodeDataType type() const override; - - sofa::core::objectmodel::BaseData* getData(); - -protected: - sofa::core::objectmodel::BaseData* m_bData; -}; - - -static const char* ignoredData[] = { "name", "printLog", "tags", "bbox", "listening", "componentState" }; - -//------------------------------------------------------------------------------ -/** -* This Class is a NodeDataModel specialisation to represent a Sofa component on the QtNodes graph. -* It will take a SOFA BaseObject as target and parse all Data, storing Data, Links and connections with parents components. -*/ -class SofaComponentNodeModel : public NodeDataModel -{ - Q_OBJECT - -public: - /// Default empty Object constructor with 0 Data - SofaComponentNodeModel(std::string name = "EmptyNode"); - - /// constructor with a Sofa BaseObject as target - SofaComponentNodeModel(sofa::core::objectmodel::BaseObject* _sofaObject, bool debugMode = false); - - virtual ~SofaComponentNodeModel() {} - - /// Interface for caption. - QString caption() const override { return m_caption; } - void setCaption(std::string str) { m_caption = QString::fromStdString(str); } - - /// Interface for name. - QString name() const override { return m_uniqName; } - - /// Return the number of Data. - size_t getNbrData() { return m_data.size(); } - - /// Return the number of connection with other Node components - size_t getNbrConnections() { return m_dataConnections.size(); } - - /// return the list of connections @sa m_dataConnections - const std::map >& getDataConnections() { return m_dataConnections; } - - /// Return the PortIndex of a Data given its Name. - QtNodes::PortIndex getDataInputId(const QString& dataName); - - ///Interface for QtNodes - ///{ - /// Override method to return the number of ports - unsigned int nPorts(PortType portType) const override; - - /// Override method to give the type of Data per Port - NodeDataType dataType(PortType portType, PortIndex portIndex) const override; - - /// Override method to return the NodeData given a port - std::shared_ptr outData(PortIndex port) override; - - /// Override method to set input Data - void setInData(std::shared_ptr data, int port) override; - - /// Override method for more advance node gui. Not yet used. - QWidget* embeddedWidget() override { return nullptr; } - ///} - -protected: - /// Internal method to parse all Data of a Sofa component and create the corresponding ports - void parseSofaObjectData(); - -protected: - QString m_caption; ///< caption to be display on the Graph - QString m_uniqName; ///< unique name to refer to this node - - bool debugNodeGraph; ///< parameter to activate graph logs. False by default. - - /// Vector of Data/port hold by this component/Node. vector of pair{DataName, DataType} - std::vector < std::pair < QString, QString> > m_data; - - /// vector of SofaComponentNodeData class holding pointer to the Data. To replace @sa m_data when api is validated. - std::vector < std::shared_ptr > m_Nodedata; - - /// Map to store all connection between this node and other. map.key = this data name, map.value = pair{ComponentName, DataName} - std::map > m_dataConnections; - - /// Pointer to the sofa object. - sofa::core::objectmodel::BaseObject* m_SofaObject; -}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/fwd.h b/Sofa/GUI/Qt/src/sofa/gui/qt/fwd.h deleted file mode 100644 index 2c7bddde741..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/fwd.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -namespace sofa::gui::qt -{ - -class QSofaListView; - -} diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/init.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/init.cpp deleted file mode 100644 index 1012b86a10b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/init.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -#include -#include - -namespace sofa::gui::qt -{ - - extern "C" { - SOFA_EXPORT_DYNAMIC_LIBRARY void initExternalModule(); - SOFA_EXPORT_DYNAMIC_LIBRARY const char* getModuleName(); - SOFA_EXPORT_DYNAMIC_LIBRARY const char* getModuleVersion(); - } - - void initExternalModule() - { - init(); - } - - const char* getModuleName() - { - return MODULE_NAME; - } - - const char* getModuleVersion() - { - return MODULE_VERSION; - } - - void init() - { - static bool first = true; - if (first) - { -#if SOFA_GUI_QT_ENABLE_QGLVIEWER - sofa::gui::common::GUIManager::RegisterGUI("qglviewer", &sofa::gui::qt::RealGUI::CreateGUI, nullptr, 3); -#endif - -#if SOFA_GUI_QT_ENABLE_QTVIEWER - sofa::gui::common::GUIManager::RegisterGUI("qt", &sofa::gui::qt::RealGUI::CreateGUI, nullptr, 2); -#endif - - // if ObjectStateListener is triggered (either by changing the message number, or by - // changing the component name) in a thread different than the main thread (=UI thread), - // a Qt event is launched through the queued connection system. For that, the event - // parameters must be known to Qt's meta-object system. This is what qRegisterMetaType - // does in the following instruction. - qRegisterMetaType >("QVector"); - - qInstallMessageHandler(redirectQtMessages); - - first = false; - } - } - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/init.h b/Sofa/GUI/Qt/src/sofa/gui/qt/init.h deleted file mode 100644 index 09befd79dd1..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/init.h +++ /dev/null @@ -1,28 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -namespace sofa::gui::qt -{ - void SOFA_GUI_QT_API init(); -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.cpp deleted file mode 100644 index 0e0ae9693f4..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include -using sofa::simulation::SceneLoaderFactory ; - -#include -using sofa::helper::system::DataRepository ; - -#include -using sofa::helper::system::FileSystem ; - -#include "QDocBrowser.h" -#include "../RealGUI.h" -#include - -#include - -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ - -///////////////////////////// PRIVATE OBJECTS ////////////////////////////////// -/// May be moved to their own .cpp/.hh if one day someone needs them. - -SofaEnrichedPage::SofaEnrichedPage(QObject* parent) : QWebEnginePage(parent) -{ -} - -bool SofaEnrichedPage::isSofaTarget(const QUrl& u) -{ - if( u.fileName() == QString("sofa") && u.hasQuery() ) - { - return true ; - }else if( u.isLocalFile() && ! u.hasQuery() ) - { - return true ; - } - return false; -} - -bool SofaEnrichedPage::acceptNavigationRequest(const QUrl & url, - QWebEnginePage::NavigationType type, - bool ) -{ - if (type == QWebEnginePage::NavigationTypeLinkClicked) - { - if( isSofaTarget(url) ) - { - emit linkClicked(url); - return false; - } - } - return true; -} - - - -//////////////////////////////// BrowserHistory //////////////////////////////// -/// Hold an history entry which include the .html file, the sofa scene file and the -/// root directory. This was needed to implement the backward function of the -/// doc browser as the internal one implemented in QTextBrowser was only capable -/// of storing the .html file. -class BrowserHistoryEntry -{ -public: - std::string m_htmlfile ; - std::string m_scenefile ; - std::string m_rootdir ; - - BrowserHistoryEntry(const std::string& html, - const std::string& scene, - const std::string& rootdir) - { - m_htmlfile = html ; - m_scenefile = scene ; - m_rootdir = rootdir ; - } -}; - -class BrowserHistory -{ -public: - std::vector m_history ; - void push(const std::string& html, const std::string& scene, const std::string& rootdir) ; - BrowserHistoryEntry current() ; - BrowserHistoryEntry pop() ; - int size() ; -}; - -int BrowserHistory::size() -{ - return m_history.size() ; -} - -BrowserHistoryEntry BrowserHistory::current(){ - if(m_history.size()==0) - throw std::exception() ; - - return *(m_history.end()-1) ; -} - -void BrowserHistory::push(const std::string& html, const std::string& scene, const std::string& rootdir) -{ - m_history.push_back(BrowserHistoryEntry(html, scene, rootdir)); -} - -BrowserHistoryEntry BrowserHistory::pop() -{ - if(m_history.size()==0) - throw std::exception() ; - - BrowserHistoryEntry entry = *(m_history.end()-1) ; - - if(m_history.size()>1) - m_history.pop_back() ; - - return entry ; -} -//////////////////////////////////////////////////////////////////////////////// - - -QString asQStr(const std::string& c) -{ - return QString(c.c_str()) ; -} - -std::string asStr(const QString& s) -{ - return s.toStdString() ; -} - - -DocBrowser::~DocBrowser() -{ - -} - -DocBrowser::DocBrowser(RealGUI* g) : QDialog(g) -{ - m_realgui = g ; - m_browserhistory = new BrowserHistory() ; - - /// Create a top level window - setGeometry(0,0,600,600); - setWindowTitle("Doc browser"); - - /// Create the first button line - QVBoxLayout *verticalLayout = new QVBoxLayout(this); - QWidget *bg = new QWidget() ; - QHBoxLayout *bgl = new QHBoxLayout(bg) ; - bg->setLayout(bgl); - verticalLayout->addWidget(bg) ; - - QPushButton* prev=new QPushButton() ; - prev->setIcon(QIcon(asQStr(common::GuiDataRepository.getFile("icons/back.png")))) ; - connect(prev, SIGNAL(clicked()), this, SLOT(goToPrev())); - bgl->addWidget(prev); - - /// Here we do an autocompletion and search for components. - m_lineEdit = new QLineEdit(); - bgl->addWidget(m_lineEdit); - - QPushButton* home=new QPushButton(); - home->setIcon(QIcon(asQStr(common::GuiDataRepository.getFile("icons/home.png")))); - connect(home, SIGNAL(clicked()), this, SLOT(goToHome())); - bgl->addWidget(home) ; - - /// Add the html browser to visualize the documentation - m_htmlPage = new QWebEngineView(this); - SofaEnrichedPage* pp = new SofaEnrichedPage(); - m_htmlPage->setPage(pp); - - verticalLayout->addWidget(m_htmlPage, 1); - - /// We want click on internal links (file://) to be routed to the the goTo function to - /// load the sofa file. - connect(m_htmlPage, SIGNAL(urlChanged(const QUrl&)), this, SLOT(goTo(const QUrl&))); - connect(pp, SIGNAL(linkClicked(const QUrl&)), this, SLOT(onLinkClicked(const QUrl&))); -} - -void DocBrowser::loadHtml(const std::string& filename) -{ - if (filename.empty()) - { - return; - } - - std::string htmlfile = filename ; - std::string rootdir = FileSystem::getParentDirectory(filename) ; - - const QUrl currenturl = m_htmlPage->page()->url() ; - - if(currenturl.isLocalFile() && currenturl.path() == asQStr(htmlfile)) - { - return ; - } - - const std::string extension=FileSystem::getExtension(filename); - htmlfile.resize(htmlfile.size()-extension.size()-1); - htmlfile+=".html"; - - /// Check if either the scene specific html or default provided can be loaded. - /// If so...load the page and add the entry into the history. - if (!DataRepository.findFile(htmlfile, "", NULL)) - return; - - m_htmlPage->load( QUrl::fromLocalFile(QString(htmlfile.c_str())) ); - - constexpr bool showView = true ; - setVisible(showView); -} - -void DocBrowser::goToPrev() -{ - m_htmlPage->pageAction(QWebEnginePage::Back)->trigger() ; -} - -void DocBrowser::onLinkClicked(const QUrl& u) -{ - msg_info("DocBrowser") << " query to load " << asStr(u.path()) ; - if( u.fileName() == QString("sofa") && u.hasQuery() ) - { - m_realgui->playpauseGUI(true) ; - return ; - } - - if( u.isLocalFile() && ! u.hasQuery() ) - { - const QFileInfo theFile(u.toLocalFile()); - const std::string sofafile = asStr( theFile.absoluteDir().absoluteFilePath(u.toLocalFile()) ); - const std::string extension = FileSystem::getExtension(sofafile) ; - - /// Check if the path is pointing to a sofa scene. If so - /// open the scene - const auto exts = SceneLoaderFactory::getInstance()->extensions() ; - if ( std::find(exts.begin(), exts.end(), extension) != exts.end() ) - { - m_realgui->fileOpen(sofafile, false, false) ; - return ; - } - } - m_htmlPage->load(u) ; -} - -void DocBrowser::goTo(const QUrl& u) -{ - msg_info("DocBrowser") << "Go to " << asStr(u.path()) ; - if( u.isLocalFile() && u.hasQuery() ) - { - const QUrlQuery q { u.query() } ; - if( !q.hasQueryItem("sofafile") ) { - msg_info("DocBrowser") << "Does not have associated sofa file. " ; - return ; - } - - const QFileInfo htmlfile(u.toLocalFile()); - const std::string sofafile = asStr( htmlfile.absoluteDir().absoluteFilePath(q.queryItemValue("sofafile")) ); - const std::string extension = FileSystem::getExtension(sofafile) ; - - /// Check if the path is pointing to a sofa scene. If so - /// open the scene - const auto exts = SceneLoaderFactory::getInstance()->extensions() ; - if ( std::find(exts.begin(), exts.end(), extension) == exts.end() ){ - msg_warning("DocBrowser") << "Unsupported sofa file format. " ; - return ; - } - m_realgui->fileOpen(sofafile, false, false) ; - return ; - } -} - -void DocBrowser::goToHome() -{ - loadHtml(GuiDataRepository.getFile("docs/runsofa.html").c_str()); -} - -void DocBrowser::flipVisibility() -{ - if(isVisible()) - hide(); - else - show(); - emit visibilityChanged(isVisible()) ; -} - -void DocBrowser::showEvent(QShowEvent *) -{ - emit visibilityChanged(isVisible()) ; -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.h b/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.h deleted file mode 100644 index 5a7f34d9824..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/panels/QDocBrowser.h +++ /dev/null @@ -1,90 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -/****************************************************************************** -* Contributors: -* - damien.marchal@univ-lille1.fr -*******************************************************************************/ - -#include -#include -#include -#include - -////////////////////////////// FORWARD DECLARATION //////////////////////////// -class QLineEdit ; -class QTextBrowser ; - -namespace sofa::gui::qt -{ - class RealGUI ; - class BrowserHistory ; -} // namespace sofa::gui::qt - - -/////////////////////////////// DECLARATION ////////////////////////////////// -namespace sofa::gui::qt -{ - -class SofaEnrichedPage : public QWebEnginePage -{ - Q_OBJECT -public: - SofaEnrichedPage(QObject* parent = 0) ; - bool isSofaTarget(const QUrl &url) ; - - bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool); -signals: - void linkClicked(const QUrl&); -}; - -class SOFA_GUI_QT_API DocBrowser : public QDialog -{ -Q_OBJECT - -public: - DocBrowser(RealGUI* g) ; - ~DocBrowser() override ; - - void loadHtml(const std::string& filename) ; - virtual void showEvent(QShowEvent*) override ; - -public slots: - void onLinkClicked(const QUrl& url) ; - void goToPrev() ; - void goTo(const QUrl& u) ; - void goToHome() ; - void flipVisibility() ; - -signals: - void visibilityChanged(bool) ; - -private: - /// This is use to retrieve the execution context when browsing the - /// history of sofa scene execution. - BrowserHistory* m_browserhistory ; - - QLineEdit* m_lineEdit; - QWebEngineView* m_htmlPage; - RealGUI* m_realgui ; -} ; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/qt.conf.h b/Sofa/GUI/Qt/src/sofa/gui/qt/qt.conf.h deleted file mode 100644 index 25fe40ce48d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/qt.conf.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** Resource object code -** -** Created by: The Resource Compiler for Qt version 5.15.2 -*****************************************************************************/ - -#include -#include -using sofa::helper::system::FileSystem; - -#include -#include -#include -#include -#include - -static std::vector qt_resource_data = {}; - -static const unsigned char qt_resource_name[] = { - // qt - 0x0,0x2, - 0x0,0x0,0x7,0x84, - 0x0,0x71, - 0x0,0x74, - // etc - 0x0,0x3, - 0x0,0x0,0x6c,0xa3, - 0x0,0x65, - 0x0,0x74,0x0,0x63, - // qt.conf - 0x0,0x7, - 0x8,0x74,0xa6,0xa6, - 0x0,0x71, - 0x0,0x74,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x66, -}; - -static const unsigned char qt_resource_struct[] = { - // : - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, - // :/qt - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2, - // :/qt/etc - 0x0,0x0,0x0,0xa,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3, - // :/qt/etc/qt.conf - 0x0,0x0,0x0,0x16,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, -}; - -#ifdef QT_NAMESPACE -# define QT_RCC_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name -# define QT_RCC_MANGLE_NAMESPACE0(x) x -# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b -# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b) -# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \ - QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE)) -#else -# define QT_RCC_PREPEND_NAMESPACE(name) name -# define QT_RCC_MANGLE_NAMESPACE(name) name -#endif - -#ifdef QT_NAMESPACE -namespace QT_NAMESPACE { -#endif - -bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); -bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); - -#ifdef QT_NAMESPACE -} -#endif - - -namespace sofa::gui::qt { -bool loadQtConfWithCustomPrefix(const std::string& qtConfPath, const std::string& prefix) -{ - if( ! qt_resource_data.empty() ) - { - msg_warning("qt.conf.h") << "loadQtConfWithCustomPrefix can only be called once."; - return false; - } - - // Qt wants paths with slashes - const std::string qtConfPathClean = FileSystem::cleanPath(qtConfPath, FileSystem::SLASH); - const std::string prefixClean = FileSystem::cleanPath(prefix, FileSystem::SLASH); - - if ( ! FileSystem::isDirectory(prefixClean) ) - { - msg_warning("qt.conf.h") << "Directory not found " << prefixClean; - return false; - } - - std::ifstream inputFile(qtConfPathClean); - if ( ! inputFile.is_open() ) - { - msg_warning("qt.conf.h") << "Cannot open file " << qtConfPathClean; - return false; - } - - std::stringstream output; - std::string inputLine; - while ( std::getline(inputFile, inputLine) ) - { - if ( inputLine.find("Prefix") != std::string::npos ) - { - output << " Prefix = " << prefixClean; - } - else - { - output << inputLine; - } -#if defined(WIN32) - output << '\r' << '\n'; -#elif defined(__APPLE__) - output << '\r'; -#else - output << '\n'; -#endif - } - - std::vector data = std::vector(std::istreambuf_iterator(output), std::istreambuf_iterator()); - int dataSize = data.size(); - qt_resource_data.resize(4 + dataSize); - - for ( int i = 0 ; i < 4 + dataSize ; i++ ) - { - if ( i < 4 ) // first 4 bytes are for size - { - qt_resource_data[3 - i] = static_cast( (dataSize >> (i * 8)) & 0xFF ); - } - else // next bytes are for data - { - qt_resource_data[i] = static_cast( data[i - 4] ); - } - } - - return QT_RCC_PREPEND_NAMESPACE(qRegisterResourceData)(1, qt_resource_struct, qt_resource_name, &qt_resource_data[0]); -} -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/RealGUI.qrc b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/RealGUI.qrc deleted file mode 100644 index beb9e99031e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/RealGUI.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - icons/collapseAll.svg - icons/expandAll.svg - icons/sceneGraphRefresh-locked.svg - icons/sceneGraphRefresh-dirty.svg - icons/sceneGraphRefresh-unlocked.svg - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.png b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.png deleted file mode 100644 index 27301b6b526e5e28f123120e33ef5594f228655f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 519 zcmV+i0{H!jP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00D1FL_t(Y$L-clPQpMG2k`OU+cqn`tSy)d-s8Yh(CLmt)2BwJz4q*$z|(mLgVW|M$S zBxOaC84)m~j=rxD?<kZ*C8bZwrzYbVbV3Y2Z9*cRkqJP|%m2YL0G-f>>5%nWj%ncQiMa1m zSF?;Dh|IfwFO^cy{NY~}Oe>1w`op02It+uwpa1|)(X#z8u6u(%SNO-H%`Mpte-xkI zbA%I}r>^VteUA>F2k!s?002ov JPDHLkV1k`;+8h7? diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.xpm deleted file mode 100644 index a89a22568bd..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/back.xpm +++ /dev/null @@ -1,55 +0,0 @@ -/* XPM */ -static char * back_xpm[] = { -"29 27 25 1", -" c None", -". c #619E78", -"+ c #5E9C76", -"@ c #6AA57E", -"# c #619E7A", -"$ c #6CA681", -"% c #B2DAB7", -"& c #B3DBB7", -"* c #BAE0BD", -"= c #6AA480", -"- c #6BA581", -"; c #6AA47E", -"> c #B1D9B6", -", c #629F79", -"' c #6CA781", -") c #B3DBB8", -"! c #69A37E", -"~ c #619E7B", -"{ c #609F79", -"] c #6BA680", -"^ c #68A37E", -"/ c #69A37D", -"( c #B0D9B5", -"_ c #67A37D", -": c #69A47E", -" ", -" ", -" ", -" ", -" .+ ", -" @+ ", -" #$%+ ", -" #$&*+ ", -" #=&**+ ", -" #-&***+ ", -" #-&****+ ", -" ;>*****+++++++++++++++ ", -" ;>********************+ ", -" .-&*********************+ ", -" ,')*********************+ ", -" !>********************+ ", -" ~$%*****+++++++++++++++ ", -" {]&****+ ", -" ^>***+ ", -" /(**+ ", -" /(*+ ", -" _(+ ", -" :+ ", -" + ", -" ", -" ", -" "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/collapseAll.svg b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/collapseAll.svg deleted file mode 100644 index f373614688b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/collapseAll.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/expandAll.svg b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/expandAll.svg deleted file mode 100644 index 4a1bcbcbf21..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/expandAll.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/graphicon.ico b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/graphicon.ico deleted file mode 100644 index adf0a2071a539814323c2b09f3e68c2d70895ce2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1406 zcmeH^&ra%45XQe&ThVI8TB~TSC{?lktG2>yNMJ`uNLUdbfCX%L6kdP@1V|ukcm=j> z*s&ul;0+)okPx`X+=x3jcX|CLGs*8eIcG9+0FH&%3sybI34jJ5$dXy`v;6db6321i zc^-lwKomttk_1_np(qMeRfVQ$&~+V#VZby^Se6Cbw&6GqT-QY;5y| zdcFQ>^xw1J4gA*|phv}X;3p>kfk%0ycj+i_!9Nf^@E3t2>HT)gAv!rDIy)h9wr;P4 z5Rp$K(tJcA;mQ^+pH1PK=vpwJF9n@JjBg=M+V?heZW+8QBJD~&#Aq?OhXFYyJdeP}I-G5BCo ziIHeh-)y2OO?{}THGR++Obcy|Hfo?DG$poZp|ArimzL#H3zY3HGduJ7(7G^^PDXlD4|pd1V8nw-XHdT*`+*Cz_03d zSk0XAT@7m8#CWBp2hi^xlzaOml>k>1MLAg8bhd>6G$w%G*1u|2l!aOY$29OfpHWim zG}~>tFtCP2_|4fKqrn zPGQ#lI|>T&QR2u$YHG61&+iYwEqS!w{sEaG%w@kUe>{|4_G4pXqqZX8v3Is-m?&FM z8D_sVGo39i5|gZ%7G26zRmH&2DEfx3BcQ0TZmU5?+4C@%5_J~`13pZ3{RD4YGfW(d zB3lj|wmh&bt1Aib#3XwAq}vmdH&v+WkpNK-?fK&Dln(Igx~fXvX!;Nut#pV2S5#={ zk~ZiA&d>YM(?5g(&j^z9OJLphGLps3AY|n#p_F1yx&m+8_m~^$fkVhgiPMG+|GNM7 zybt~EL0OVKK`^9UUI={hM$@@=0szPBcF-rwH&KVJfN-3?ZYHO1qQ^ag@f+jV_*f;Z zTVFzAwmqVj;k!NnZ^tS8^+!9hbFxq@=EIV%uV+P3FfcSsFJ9^zCo-u$=gyrcPJn`l;V2$QAHQmG<2OO`|L)iH?rY`@6whPT5ayJTvToj1{c%B2t zad0_Ba`93(0Kl-U=%o=1kBlKjd>q2-2aqh3Mtyv-Ml-AxRj^i6Va{_EqwUT3v*l+L zDh6awaG#$l7&+Er*B}Q<226wavq6E zsiE%-05F7fcJmb|Z#W5|dT-p|mYO*|8^X?gC~r84Zes-)LOMf$wTD}`%%-?N42B24 zy%-FbO>v?2aO;+3H5jQ;N)cR8z;Y}I!z>0PYhRY4CYgcf?lyEnqN*qpsbb6i-v@4~ zPfP*-2}CK?1zk-#sYYW9NGT105JDDztM%8kFt@=76`SD*j@ diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/home.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/home.xpm deleted file mode 100644 index 89a8cfb2f9d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/home.xpm +++ /dev/null @@ -1,150 +0,0 @@ -/* XPM */ -static char * home_xpm[] = { -"40 40 107 2", -" c None", -". c #A87050", -"+ c #A7714F", -"@ c #A86F51", -"# c #A66F4E", -"$ c #B8805F", -"% c #E2A883", -"& c #E2A882", -"* c #B77F5E", -"= c #A66F4F", -"- c #A7704E", -"; c #A76F4E", -"> c #CF9672", -", c #F5BB94", -"' c #FFC49C", -") c #A97150", -"! c #AF7756", -"~ c #D9A07C", -"{ c #FBC198", -"] c #FEC39C", -"^ c #FBC098", -"/ c #D9A07B", -"( c #AF7757", -"_ c #A87251", -": c #A56D4D", -"< c #BE8663", -"[ c #E9AE89", -"} c #F9BE97", -"| c #D59E7A", -"1 c #AD7A5B", -"2 c #E8AE88", -"3 c #AB7352", -"4 c #A97252", -"5 c #D19874", -"6 c #F6BC94", -"7 c #EEB48D", -"8 c #C59171", -"9 c #A67152", -"0 c #B69785", -"a c #CDD1D3", -"b c #CDD0D2", -"c c #B59784", -"d c #A67253", -"e c #EFB48E", -"f c #F6BB94", -"g c #D19774", -"h c #A87151", -"i c #AA7253", -"j c #A66C4C", -"k c #A56E4E", -"l c #BD8562", -"m c #E6AC86", -"n c #FCC199", -"o c #B27F61", -"p c #AA7A5E", -"q c #C2B7AF", -"r c #D7EAF4", -"s c #DBF2FF", -"t c #A87150", -"u c #A86F4F", -"v c #CB936F", -"w c #F2B891", -"x c #F3B891", -"y c #C99270", -"z c #A67252", -"A c #B4907C", -"B c #CCCDCF", -"C c #DAF1FE", -"D c #CC936F", -"E c #A16A4A", -"F c #D79E78", -"G c #FABF97", -"H c #E9B089", -"I c #BF8B6B", -"J c #B89E8E", -"K c #D0D8DD", -"L c #D0D7DC", -"M c #C08C6B", -"N c #D29A77", -"O c #AD8066", -"P c #C3BBB7", -"Q c #D8EBF6", -"R c #AC8066", -"S c #C5906F", -"T c #B59683", -"U c #CDD2D4", -"V c #B18165", -"W c #A67355", -"X c #BBA699", -"Y c #D2DEE5", -"Z c #BBA598", -"` c #B18065", -" . c #A36B4B", -".. c #83879C", -"+. c #DAEEFB", -"@. c #7496C4", -"#. c #D6EAF9", -"$. c #D9EFFC", -"%. c #DAF0FE", -"&. c #DBF1FE", -"*. c #D9EEFC", -"=. c #DBF1FF", -"-. c #DAF0FD", -";. c #D8EDFB", -">. c #D9EFFD", -",. c #8FB2C6", -"'. c #D9F0FD", -" ", -" . + ", -" @ # $ % & * = - ", -" ; # > , ' ' ' ' , > # ; ", -" ) ! ~ { ' ' ' ] ] ' ' ' ^ / ( _ ", -" - : < [ ' ' ' ' } | 1 1 | } ' ' ' ' 2 < : - ", -" 3 4 5 6 ' ' ' ' 7 8 9 0 a b c d 8 e ' ' ' ' f g h i ", -" j k l m ] ' ' ' n ~ o p q r s s s s r q p o ~ n ' ' ' ] m l = j ", -" t u v w ' ' ' ' x y z A B C s s s s s s s s C B A z y x ' ' ' ' w D u t ", -" E F G ' ' ' ' H I 9 J K s s s s s s s s s s s s s s L J 9 M H ' ' ' ' G F E ", -" E ' ' ' } N 1 O P Q s s s s s s s s s s s s s s s s s s Q P R 1 N } ' ' ' E ", -" E ' 7 S d T U s s s s s s s s s s s s s s s s s s s s s s s s U T d S 7 ' E ", -" E V W X Y s s s s s s s s s s s s s s s s s s s s s s s s s s s s Y Z W ` E ", -" ...+.s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s +... . ", -" @.s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s s C #.$.C C C s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s s C %.&.s s s s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s C s s C C C s s s s s s s C s s s s s s s s s s @. ", -" @.s s s s s s s s s C C C C C C s s s s s s s s C %.s s s s s s s s s @. ", -" @.s s s s s s s s C s C s s s &.s s s s s s s s C *.=.s s s s s s s s @. ", -" @.s s s s s s s s C C s s s s s s s s s s s s s &.-.;.s s s s s s s s @. ", -" @.s s s s s s s s C C C s s s s s s s s s s s s C C $.s s s s s s s s @. ", -" @.s s s s s s s s s C s s s s s s s s s s s s s s C s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s C s s s s s s s s s s s s s s s s s s s s s s s s @. ", -" @.s s s s s s s s >.C s s s ,.,.,.,.,.,.,.,.s s s s C s s s s s s s s @. ", -" @.s s s s s s s s $.%.&.s s ,.,.,.,.,.,.,.,.s s s C C s s s s s s s s @. ", -" @.s s s s s s s s C *.C s s ,.,.,.,.,.,.,.,.s s s C =.s s s s s s s s @. ", -" @.s s s s s s s s s >.'.C s ,.,.,.,.,.,.,.,.s s C C s s s s s s s s s @. ", -" @.s s s s s s s s s s C s s ,.,.,.,.,.,.,.,.s s C s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.s s s s s s s s s s s s s ,.,.,.,.,.,.,.,.s s s s s s s s s s s s s @. ", -" @.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@. ", -" "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/icondata.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/icondata.xpm deleted file mode 100644 index d74935752fd..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/icondata.xpm +++ /dev/null @@ -1,32 +0,0 @@ -/* XPM */ -static const char * icondata_xpm[] = { -"20 20 9 1", -" c None", -". c #000000", -"+ c #00007F", -"@ c #0000BF", -"# c #0000FF", -"$ c #000098", -"% c #0000E6", -"& c #00008F", -"* c #00003F", -" ", -" ", -" ", -" ", -" . ", -" +@. ", -" +##@$ ", -" +####%@. ", -" +#######@$ ", -" +#########@$$ ", -" +###########%&* ", -" +#########%@+ ", -" +#######@$ ", -" +####%@+ ", -" +##%@ ", -" +@ ", -" . ", -" ", -" ", -" "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconerror.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconerror.xpm deleted file mode 100644 index 316886636ed..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconerror.xpm +++ /dev/null @@ -1,27 +0,0 @@ -/* XPM */ -static const char * iconerror_xpm[] = { -"20 20 4 1", -" c None", -". c #000000", -"+ c #C8C8C8", -"@ c #FF4D4D", -" ", -" . ", -" .+ ", -" ...+ ", -" .@.+ ", -" ..@..+ ", -" .@.@.+ ", -" ..@.@..+ ", -" .@@.@@.+ ", -" ..@@.@@..+ ", -" .@@@.@@@.+ ", -" ..@@@.@@@..+ ", -" .@@@@.@@@@.+ ", -" ..@@@@.@@@@..+ ", -" .@@@@@@@@@@@.+ ", -" ..@@@@...@@@@..+ ", -" .@@@@@...@@@@@.+ ", -" ..@@@@@@@@@@@@@..+ ", -" .................+ ", -" +++++++++++++++++ "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconinfo.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconinfo.xpm deleted file mode 100644 index 5af3d7f69bc..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconinfo.xpm +++ /dev/null @@ -1,27 +0,0 @@ -/* XPM */ -static const char * iconinfo_xpm[] = { -"20 20 4 1", -" c None", -". c #000000", -"+ c #C8C8C8", -"@ c #77E87A", -" ", -" . ", -" .+ ", -" ...+ ", -" .@.+ ", -" ..@..+ ", -" .@.@.+ ", -" ..@.@..+ ", -" .@@.@@.+ ", -" ..@@.@@..+ ", -" .@@@.@@@.+ ", -" ..@@@.@@@..+ ", -" .@@@@.@@@@.+ ", -" ..@@@@.@@@@..+ ", -" .@@@@@@@@@@@.+ ", -" ..@@@@...@@@@..+ ", -" .@@@@@...@@@@@.+ ", -" ..@@@@@@@@@@@@@..+ ", -" .................+ ", -" +++++++++++++++++ "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconmultinode.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconmultinode.xpm deleted file mode 100644 index 1e7579a6034..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconmultinode.xpm +++ /dev/null @@ -1,27 +0,0 @@ -/* XPM */ -static const char * iconmultinode_xpm[] = { -"20 20 4 1", -" c None", -". c #000000", -"+ c #9F9F9F", -"@ c #5C5656", -" ", -" ", -" ", -" ...... ", -" .++++. ", -" .++++++...... ", -" .+++++++.@@@@. ", -" .+++++++.@@@@@@. ", -" .++++++.@@@@@@@@. ", -".++++++.@@@@@@@@@@. ", -".++++++.@@@@@@@@@@. ", -".+++++.@@@@@@@@@@@@.", -" .++++.@@@@@@@@@@@@.", -" .++++.@@@@@@@@@@@@.", -" .++++.@@@@@@@@@@. ", -" .+++.@@@@@@@@@@. ", -" .+++.@@@@@@@@. ", -" ......@@@@@@. ", -" .@@@@. ", -" ...... "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconnode.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconnode.xpm deleted file mode 100644 index 9a18662b8f3..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconnode.xpm +++ /dev/null @@ -1,26 +0,0 @@ -/* XPM */ -static const char * iconnode_xpm[] = { -"20 20 3 1", -" c None", -". c #000000", -"+ c #DEDEDE", -" ", -" ", -" ", -" ...... ", -" .++++. ", -" .++++++. ", -" .++++++++. ", -" .++++++++++. ", -" .++++++++++. ", -".++++++++++++. ", -".++++++++++++. ", -".++++++++++++. ", -" .++++++++++. ", -" .++++++++++. ", -" .++++++++. ", -" .++++++. ", -" .++++. ", -" ...... ", -" ", -" "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconsleep.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconsleep.xpm deleted file mode 100644 index ab5428929ec..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconsleep.xpm +++ /dev/null @@ -1,26 +0,0 @@ -/* XPM */ -static const char * iconsleep_xpm[] = { -"20 20 3 1", -" c None", -". c #000000", -"+ c #6F6F6F", -" ", -" ", -" ", -" ...... ", -" .++++. ", -" .++++++. ", -" .++++++++. ", -" .++++++++++. ", -" .++++++++++. ", -".++++++++++++. ", -".++++++++++++. ", -".++++++++++++. ", -" .++++++++++. ", -" .++++++++++. ", -" .++++++++. ", -" .++++++. ", -" .++++. ", -" ...... ", -" ", -" "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconwarning.xpm b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconwarning.xpm deleted file mode 100644 index aa87f73bf3d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/iconwarning.xpm +++ /dev/null @@ -1,27 +0,0 @@ -/* XPM */ -static const char * iconwarning_xpm[] = { -"20 20 4 1", -" c None", -". c #000000", -"+ c #C8C8C8", -"@ c #FFFF00", -" ", -" . ", -" .+ ", -" ...+ ", -" .@.+ ", -" ..@..+ ", -" .@.@.+ ", -" ..@.@..+ ", -" .@@.@@.+ ", -" ..@@.@@..+ ", -" .@@@.@@@.+ ", -" ..@@@.@@@..+ ", -" .@@@@.@@@@.+ ", -" ..@@@@.@@@@..+ ", -" .@@@@@@@@@@@.+ ", -" ..@@@@...@@@@..+ ", -" .@@@@@...@@@@@.+ ", -" ..@@@@@@@@@@@@@..+ ", -" .................+ ", -" +++++++++++++++++ "}; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/openFile.png b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/openFile.png deleted file mode 100644 index 5bac04160cdcfb46a14fc1e5fc28400d51f465a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1247 zcmV<51R(o~P))oM+BKVoV^Qz|~%T4-XFQXqxU0yD#K@15Z?Gxv3_3xrH5^|5l}m)xA3 zd%paC-{YKo@W1_ydH&+8K0n}lykTAV(b&xFO+Z=3#|zvK>;_Ume5u2VCHp-)A6(zH zu`#l>rJ*9y)lo-K&S&3?AN=<2XBS%l8)#k`EZEw$sdh(0b-1&mxl(RxjBw<5w|4YI z&uSohCqU=L?)Q3IBO0uj|1E@z5Q3?g#vAXS9|;x)N?V&MLT!x^@_ZhI5c58c;M!=M zEqjjb0?sT=alvd~Ac*ZK2uI)wfe`cSO4-k$r?yq+3TDz4w(Vfq0@Ji8F7Q#dO5PDy zbbthKd1(fr(;vR0?yQY3MxHC^IL)d`lbqc~hgV^alpuPH||XCRXRp>Wzs-CV9j zsH!?AEU(1?`)p#8ZGI4McpeDd|!JXH+^y~HR zWdWM1Ms3QOQFNxJR7xw`sBEdEqAEh3I|rE<*a~C64{0BOid?w_UIYfI=YY~iHV64cE9uqosA{Du=gSI z{ayw}CIAK(G^JdC&*z(y0znEws}boL9NWgW3`{f2jfrUvy!tik?`y{}3=G4dtgMX9 zo3}6+li2sl$Ecb{YIZJ~``B*D;L@dEG~t3@UWutsBeLnm>-zL-U(?XsfoYo9wv8l7 zNRmV-6r#Sqp20!bf8-lVWhrr|hejro(Oke^Sd5`72-{e!?Oj1HZg!TeC$K2K@Wm#^ zDU1&h4V2S=`Fa450sS_>ytzmoAKA2m`=_`o1kF`NgyOwi&VK-r1GzCe!e-IO+G>aE z)3cl{&#(So_q~-dtS6QSxGs5lKFpl*2;pFwCN;8+-{|L@*@W-}NJJ;-wECzkmypO~ zLzS1N3K)+vcGXy>$pEHd5-2DnolY~W>nK{1*tCk8)CtN#Hiiq??jJ HZU3LTv~< z)sGdl>y{*MzJ)5C_G{tP^ zf$YG*z=iKVJ=K%Qiu1sQrGw{RL)zCCeO_AVJqWY|f&Xmi{{f*~TxW|idpH09002ov JPDHLkV1lIJQ-c5i diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-dirty.svg b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-dirty.svg deleted file mode 100644 index 24a0392cdf0..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-dirty.svg +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-locked.svg b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-locked.svg deleted file mode 100644 index ed98f1a5d03..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-locked.svg +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-unlocked.svg b/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-unlocked.svg deleted file mode 100644 index a9fd939492d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/resources/icons/sceneGraphRefresh-unlocked.svg +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/sofa-logo-alpha-text.png b/Sofa/GUI/Qt/src/sofa/gui/qt/sofa-logo-alpha-text.png deleted file mode 100644 index 7b8fa847a37539f9030ea66306671fc064abafcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34666 zcmV)jK%u{hP)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000SaNLh0L01FcU z01FcV0GgZ_00007bV*G`2iOJ}7B2`aIMJ^F03ZNKL_t(|+U&h~v}IL!?){r{u4b>@ zoqgKs3kt+S8X+o1jc8Oboo$RUi5heD!zALp8S1^s&}*(F-e_VZjbaChiP%I`1ni9x zP*4ntfTFYo)pw`g&1z=*{jqjo{Jt1Lp=hjkj5SW3QRke!)}GIP=i5B*GvSCGv4?<( zBX7Y&#}0n&gJ;{t+s?B~cM-|~!FjA`qg(3;6PpGnKJPW%BS1Z34;(l342*6^4~uQyRxeTeO3u-J`qd6xN;e)C(SY=Ku4`BS1Z3_lqrl>yumZ z>pyyD+TYH~K%<19l`4ihu$Wsa7x2O(@ksB{&f%O#DZ$>A0*@z&BypTEdD63Z`m6r# zA-~S@2rM34w&$u3o#n25&z)gm8wXYbaih!Z)HFVxV8u5X`3&t7jEV400ut>6UI@C4 z7%3H{6%4Ats3=&x;gekQ#%F~iKs{pjncaHjMb9udTzLLyWtjt`1~YSO*|cdL1A5%F z(quumX*D}cciMEaCTZM2h!`IfGAM!%#8M(cy|B&+O5<_!-{DJt{+w_Gs7LHRvG~?c zd^xUG7}^OoZrIG)jqB0TBnM1~W^00D=X#v7X_C#eU3%>%aooTWBSeH!iVy^?BqCM{ z0t7rRKw%t<+i&2LZ+byE0@Ne+Q`wHo-W=4*PWnZYnYj(DS+^FeCRx=TI^7;y=6W2x zri(~2_7w?5NJx?tCt{E>ky50wqM0bVjfhsFh^4@Lk97g#E&0Chan%R^@*xS<=mN2SqV14YBTU3%A6A_uiY#$(RMrA9v2rLGD6D3=41`c$gg_*r zCF)SX2am`PaK~5w<#~^I%5PtK1gH;UJNUW32zFr`dgTCv>pp=96(TsgjhJ?(5JAu{ zVfog}_uTMzzk%;;VDk9WPu=nhzj5RJbx+$aeskFW%}+8hwT`sigJc3BGvY)bl!Kzg z4q??ff^wv(MOg>hAfgE6BET_U1o|2jb=}c>k0g-Al1`$ioX3|V$~&*QgojvZ@@EF9 z^Iv*<@Vl->fA2B|!wT=AnEx`u? zL7*h~0NMwTo_4Hg#uDKjc5%m%Wa`0ayFU2JP<`hjhI?;iX|+Pg22;H$+TCeHI)h8* zSY?_6)dYKn9pdE$!vDuYZCsz4=+;mM?$s?ECuuvUW_82oeP@NHh_m zkwBvXDj`G(LB=Q*BUOYK5ke`D3Kt~COGXB?lSm{4Ab=DCDZscuWj%?K#8S{-TsRV= zKA7ybD?a?Y>$ZRN1FL(lW%rUM5)EdjCzzX=K+24RdCZbih*Z&R0Kub;MWGRtB(h+p zF(RY(6f{+9R#tWQ-T-ST~p_JbF`g~^60lOD9 zLN?hjJH^^flLXaa?@G*mn-FIS)2)bhD!_U2(jvTOc{rjha$=X#)B-i~Xg^|9abi@`ZW2qdYXkqBB%i3y6n2IK1O z-ME190VM;$10vvkz!MOn2571TN_e6uqPJ<&5uiR;EV=#Co8zj_ws}n)x0svgv1WD> zFS;z3O$wPYH{D>So6_t?5KH{f(kKi?rAb0e5DBrBq}r3F4yyy&jTmZ!y5_z2*}YDm z^4!5)=RXU-w3BjaAFeS++HR1^CR72OMMR!P{n{BdYhgQ2yyWOGJ?l9Hq&`4Scky2SnUXJ+U+h2B{70(yN zCPFYo#a>nq+{MbieXz2E84N%dltl@;!f3;wGFWF2!BT3+sI(Nup{>JthxH!D-n5|v zO(lqhpf}TH^J7k+F?ZtWM?C6-!1T^**}1#|A!2r-!9=q~-)D?;hG;bDb=tH#Eofzs zBm^h%F3`w4NQ(>+sg=Y^Agh2X4ee%0WIm&Q#zu-Wv!O>kK|PnhLTAq=a=_ zx}13G6qK6X;^*{3aa|vF9(A~X`#Je2M*^)Rq6&(Axx{A?b7?}e6(brkL~;H2Awo!r zP=E|zB~ctmQwwOy5Ha#GmWUFCwu)FrG}9Ov9HV`=%-mP^e&!#%Reb8LFAr?{Jfhmo zPI6|tGgPuo6sO1t4lWsrq9W*$!7yhvFA%;$gbL>j0Y?lZu^^2FGu@a?y$oMS_D4r^ z>>003AByYxu=A+>m3g$Wq>)4@#hzhcp#&ur6PY4T6$m+gbOk|yk`Sr-k`f^$v69#z zDT2faarf_39tu|{Cc=9d9K28O|2eOJzo?FW7KgS&ELtveRpDqdq~ZG zd@+wJmY9x*tj!99%TZ`%TF_|-WGpCMpfnzDJ!Nj$RUFGPzj^*cmO%Zm18SN|dhM7- zEHK_PKXhmtXeemJfDZ%>!9xfT96wxu1gr-aU}T~4AP|J`gP*BfAcVSA*^1qL{tPdC z;{{^FQ~!`rm}Y5p!1BsG3rqXhHNTIloX1v+c;6=$IhiQwB!*4{qzpJ8XtpG+D9}ql z$(VfoFR}F%|MZY%`9JKo{@!E;?TC;Y;s`2jNfJveJu+BaX(6@9*y6E(K=}w5BiDMY z^=R!Ww8L2s{!lh;5uyHGDM&;>iTh{$&;0#2i5oump|iGq<5TA^@4OD|fWlc~Aoze# zFt7sQVIl@AJjTLwBAIPTWQgf*I)%v-e{t`|Xa3QKhx)qyL_l4*>Yv|KE$u!h=svNq zB$1>v0v)9!?U{uG*f6!+;5L^>aV`!0^owLef&LNzT->p ze}-PTizt(LrEm_?2+~MkEqDY|-5$+m8`WLQniEdrnCHDwz$Fh02Xv2ty7%(;U1E29 z{dtYios|FnZt_u4x8;DfnnH=Ruaupt z+Phpfea`V`y!b-6>|wQ2{#c+M_|iLX4&VRO@%q~rFw83!3QJ`?Qb;;!M5-hqNOCP1 zEel$$I%(-JV*mF)%@_XYQK9?jXYr(0{Pkf0>Owkwyv2eZ^`OkOcD5Ff1yHBBvY;84Xt{Mtv{?5?>%OOiZR6 z|Jco}_7$6-{_A($-_LXNrSH7ieE0KoO@%z>jC0^aKWjMs(d5}X-}&s&^7HJUAFw>s z7#HYe5l2mDOiwrPPO)Plux(jT(4f`GXg3>VNkSYaB$2|0Kwjn?Ts+9a(gEhyuj9-& zed(}(_2Yl^gs`=F0E6I;dB0xb#^G!O_J#^e6kr~}a%8r3VdvM-kj3qBCigH9* zj3`C}Fnv05NFy?ICL$hv@)W&Rmz$fvb-@YGy#ECrw!QZiVRdyknQQ%||C>SYznQy624g&kz+5Y4Loa2rolsSRohzQ5s}Yq*nQS##H`!!OuZ0&GB{iWV zNJ-m!RHMfzWGo%n$>;y{%3x@r<)yz4P;bcAlg_Ny)Ix$&{rm3*?}}$`*xB z8Ab^Q2a+ff3@XpCvIJXUO@YxlPUoZ|Cr%8VRC3I0i?~wU*?a*Q%sBEAeOD3{}$uuHTlKlh6!91{B#zaxVhIYnOyUE6x z7E#t>MQ3#46sH;l852u^XmnWh39HgEJa`9Rec$WCQ-1&4`xUHDeD+J{jV3vl*-{ex%sci(nii<~kqsf@wP1l5@%U31*? zk9q2SJCpT8Z}u&pzu*J?Z(Q)Zs$3!0&`JbrIuVJI7%%8+!D1;XTudv==r&ulnk^w zhiaZ)Thh*Atc8gzVyd06lEZ<4r;#Z#3H{tMs4PNyjI$u26GJbSbUPW%6Q9e8FMa!A z+kS6<*KdW&j##sy!|ZQ-C7I*+#^nV-6PNV-M_g{fqMNrUlNwKT|-rR<~lL6t%yb<=~tem3I>%Rh?H(K zW3t^OO`1e$i$>O>PsS)Tnd-Kgo#-Ib3>q0SOTc-`H{Myx%(^s{HD=uUpXh5{~oEZ80Tu_ zD1kPPVQyH-EtT~QwPjdYTnMC5MAn{UYRhBUeCjh^dEC=qa=}jx)SE7NRT%B~7AwmK ziBKFp9g`)B`JrR6^o*<^k`cXDli7(TNu1$ChKQRKvPGXJ6RkFDCOfp-9aJMjw3?8n zU<2eO%Zm$azvC8mZTmViQyqTcOnec9P{kg9d>Va!~0$xT6RBKw_xK-Kl^}q)7wA(e?nu&m$BNR zg2(#6!I7a~83F+r91)(8_O#Ln2<%xcSjsK26et;J#1U!Q|D_lPLM_sou*={t!P97<3UqjD;|0=&-KV0@QY`? z`A5E4H(mab7w!JU+dk@c+>X2B`wz(defy%fhi3m<7*kNTPde;k5jTDCk3(nWIu2G- z%*?cC#erM)4cM`4nNCtBTatcR61-zn)x;d@0$$b3vRDZM^(c�)Zf}EN1&PeC4lR z6rTDg7u_qc-p!ucIGHllRCF4WG_FfEOGAV6bw9bCO4<#9bAgqS!#a=f9&G}FT9w0( z)j6~c7~^op;urN=&+*4C}0`EG9h?D-!(-1i_C zZ>4e-Q?t{of6DJa|8Tzcw?6g0OSa_KGm18`X5-P!Y*@>pZ?UXXHcn-nyrIe5M2d_e zl1So$Knj5pf=o#!8j6WVL@So0O4MQ)ArMJ{b%K4jex1*~^`+q_0&1rl5yz5l8qrD> zxpq{}(})DERMJQU5?C76vpGQohQ?DmhYF5{@Cfgyw4pKvtqoOWs49&vOY%`&JlEv_ zX-i~yaBFpSAMu2%CpJv7>F8;S`Ry+{oUeV|rSH3>6P77$LG}P_`xAG4_Iah8V`|+o zOs=1!v>Am-S<}tfGS#5+idz;uBQ2no69(!nzaB6YBvR0h6`fSkNg^6b;sZz_S;{qo zJFes#7ri~)YoMly!g;_48i_!Rrx?>j(#{m!hM=fCc~u9`vGh!2fulNsUgB8S^rTqw z(oj|vMOjf6CA!SX^C5%5fMI_HpD*Fd0h8+<+|0AbKJQhhH)c1{Z3WEg0q(f^(wW2c z+HpSryhJ&oMnaw)_qxOR+_zo*sibK~v}TW?xnT|(9deh_Y9!2d5-bsW2C!TRBnsnd zWfp`WRs!n+x$)TG@qqUMMWCH1+KEIG07;<@`5jl@dym>`wdgb=D(_j&>+*sUkSNIF znsmI78!BtD-jl`k_^z>r&23LZXfPGSqNJaf3`PZm;edX>&+5tw{pAIUrTv8E-At|P zGIji89`xOi)#f9JMM>K)G1&f{`NQ_YOWP1KAkzufKJlloLEfuc>8)R{Oxz=$-H7P) zus$P6QrcNU9K|e^f&(MQTYX($4+w;i2mvdlV_{?%R*sSJ^tGq29V6{f0$QmejU<%? zvAmtzFMUh6S3s?j4K&i2G=j2p7!y!Zpp+nqpwymGsqxN|r4EN>R8&Mk<4ncwrJO-g zFdXHq^oK01^jTV2VPSERh4}-l9@tH>u#?tA#MZ}bqUfIZt_M3%PkG@R#VDF)eY>Jq zJUqgFw}0jxcgAi7jYmuzd)S{@ENnw%lgQpA$P6J9nvH}kiP2uMTnY*!h?PXiT9HLb zK_ms*Lcet6+GCtR+b~vh3FO8x(jFloizP{+ko#x;U_7ORFh~8ZC}_&N+v@ zESAZ7pphg2Cy`1a6N!)l?Ld1;KoX>^$H=I`>I007r!WCeU7k85h9N{f+EduTNPDD! zRwB{HP%Z6Y_rL%6uq$<$E~$n!Rv3Y-RG!FYrW1X0hC`SG-lqm~mgt_}ezTUUB= z9nk&q%LmbPlCBvX}G!lsk zfk@RaC{=Y)sv)NAv%I>@^710X)q{*y_A^@9L%y;bWe+gZHe@nk z+l}*7tNB9)sHdLsn^!M19>sJzq7^y5eepZ)yuV&6>F<7RD=u)}Bd4~$^?`U^kt$N( zhtUeQsvuaLt>x8afK)=JAeHriqYnY=1Ca}_NsD>VCU+8CraSU z5}&U;?;aQY57|*qd&L>sK7H<&{a_a&5)8|_pj%pBw|8@k41!n%2Bl+lJlMy@bx^Byl`nmmI{pU9o%X`jALO}?I!DxW9o@S##Gi%{gi;&G+q*^ntU-yLn zgm9fN&~7SpbCQiu`fqP|AfDA^b2NtErwF?wZ#u7M@n3m~1FY6WCWc6af(hqzv>D$z-cd8BMcuZ;l-9CyETM z$sV(_n@C#IbWV8cH;?_*vmey)!1eEbX*fpi=JvrF;$xq%5I4IQMvJ$;wzYCI6LN)C zGiDr^)v=P2wV*|1DTW4ZeceiS4(lMdFbWyIw}p7)V{S1EcO7pQcCm4`VzllT*z!w% z^1$@=|MlHhb-(xiCx>h+e)>`L+9}SJEYGiyxIVh*ljkEQqJo2~IeV817V@%IXmPe~ zrQ#96kHJ-Us9Xq0A!x;tOo>_(E0(O^vWeN#fA50nC;r#m-XHm9eC3i4o_+JD{{B2a z+=q~kjZ-ng*Kx>nM={ZmEDRk33+<+&9GbdjmPM2%&=ih!-IOG2 zo*n#-uOZD6)|9l`lg!R-Vsg!9+FMV5>-wiXFrMVc*|neeyZICMeRO8Ub&=IF%~;Y% zBtg{T70wF=g{7zhN=hOil2D741)O)3#xbl6rFD4k?(XCvAdXWAlHNpuc+ZLo8l-PBXq`Z7Vv1%0{gn~Q4=KwbSAhmztGP#le2bYF<$pgK>_+))YA@JgrDF-J2mf`icD9S?4_S*ofq~<|?6= zC=vlyTh^@U@^eqwN;P>BQ%`y8PY={X_KlCf`>Gu`eeKDko!>^8K3N=S#dSl#dclE# zCyEj_op2h_+*W?!<$rOH{`P0idt+Gr_Qg!Z1B3{Ks7-Hn3*G7UOg{4QpWE~R#;~_v z{^8$^Zu`s!X2e0#$S|k^3(F1{l3EK&)?#XD6eFZUC{-s2B49%xNH-1#ED}TH4WiNv zi;Cr8#cE!X>x#-6^2$&-H?A{6yOEMMr${%Q#*_Z=@B{YBH=GtGqag>&E}LhkNkoLh zQJ9LVDDbA@*8K$`SVAxq+M=CiASj$RbHQkwgNVc5GOianj?CX0q2}uXrLG zf8~GQcR>CB+Sfkz&YMU5)#F=@ghtl9G49U2`q5|pCA^NgOpulLqZ}gDi^? zN`e=RD$io+FxKOp#oDpLp4C{Z304!FCb$Y?Dx9hC-q0^9hLy&J`pl?ULaHQbnvnI5 zV$EZod&`N>J$$6?%U}OXp(joR^HOt7B2ExnsUS;4sdT>$+n}@Q6bn z)F9}@im6N@BZ&;2ZZGAelO~yLH`uF>V#|x~+0?>=Zldw>_x$g0;QG(dbPF__2`X)q zcGfVt>15iQPI}i-XWqY!f;+GN-BwE4>Oo_Q?&edNI_A_jY<}9y?(;h1&dc9_ZhXrnukF|a3~XRw zB&mExnoiJaP0+|XG+Hg%y(V!dg(!g#;Vf8Fi>?Iku+Cwe$6Jdt6~=0;)S-t5=k?X^csRKb4`#9ny0;lO~3NL?(uUx=x4;g_>TV>`nP|T zXt+&JnVNr@t0xq!7q^bf_;6%VlL6NX*8$kb$fK% zU9yP|jp-Jum4S#rE4)z@7PPDB;fjEFwpM<&7Na$lsR%}s1`W1kP!z1@B~@ACT**x8 zP`=`>#UcCp1j%yYcHMIe*M4A@44|x zycwc`CP^b2y|tv9AIJ1@r=PLw<{Q3z*VjKuOD>Znf;5ikWr|VhSt&i!-Iyf6-W5${ z1I;YLxWK?TRH}#_wDGK)OmI<~?x`>2=U#H}+QSbCF@tY@@#5nT-1z02?cQ&rm$uQ! zGG^vB)9B35So;VjAMyAz);;M(m;b~`)922+Ve`RDP7x+&an-WF50*AjHc6*5$yB#X zYqCo++ks97ApxyGON>)g-fP@Fq*OP)`Gt?4ws7OWUhC(-OR;b# zsF=ywjZDw1M|IaSdBRhkzwycUZl3(MfBmPoY}xan*AMd{rS=R*lH6yAc#=kIlF4qD z-t+{~Y!|xqwuMz-6nKeqk}y7aObQRujc0Hi7y~2CXjI~Ch1V6sykJn2lx2lCCBYWp zG;LL}f3;-yN={yth@epzB(4qt#$kXE^@n1zAxOLHIqJ;+@v`IZC0MV2|DS}V?_JL7 zu#c`rbQ_B44Vz)=ku)Fiv{#?}OE3MA%(kz6 zW1eu%(a-q3Kl`zX!_}8{rfz&^KXt403(x!@5M&#bc8QvkOm=(BOivKccA?XTI0aHL z5jaH%bu&;X0a1OFBayFxIzFY$4=YSwA#8=wWj!31mzb);yAo`Pt}1#_#d2PZR^CQW9FnYG99q&HoDkJj;qe|T+Jz5N>ImzOZ*fSHMyiRm?n z=||Go`pd68`I+}_ocXK&{1;(q=PlULB1tGwLa>^bBvP<>(*}A+Z6#fM{BIp~`cE%G z`jFQ#y66or3hCmFD8EW>9Np>lY(DCERC^A)=EO@+`n4aORqp)At3!MLH5^ze(IKX= z3GG&oko1`7_L!aS(U?92(k4U=a501kP~(cWs2kUk8l=kC=a-fiw_0IxP2wx0(~OFW z1l1f)puBsEOaR^XX0uBjZ3&1noN?3F3<9O_A zKK>)u^5zTwSJ?BtYdE+#j~VsZI2|)L+oK<^MIQIuZ$9ybXFuraY!4g3t&89ElEBWZ z$yA9GlE(A~X4W1<+F46>^kd$zq91kOmLh5c-B@qdkBkN2c+8t=LAZmh4>q{jy=_HnQ&lq4#YeRUj4h9C3*8`5iX;QBdPBSb@Rz@Xx zS%(3Us|)@jXnIn!G%A=MloVQHY)P;c&ReXvXj6X$j}o;|hM*onZ$y&yYu7XP^#A^{ ztxtdPh1);%_OSQnZ?WU9TcB8AZbH)OG#Mrv$xe9o-Y35Bp(mC8u$3^p?5%$gitm4p zZo`l?Qd}~@|d0FC2g>n_zR5XPqb|v$plGVJH zV7FG+ajLVp;IP)<@MvrCA)sVkU-fmsN~e)<+?L~57E|ooemk;UU~Ny(Xk`rI^-P@l zqKh8$oLBzVLv=kL)>@n2`O?M5@4fExH?Q9G1sah>HX0nYVI#(AhW%xls%9-!p+P6> zGCeWD>{JiY=-{I^A!*^08mKZ!i5fAaF(l)y|8C+XwKvrPH#F$7KAgSU>l=^&84wZ@=;1AK(>(f+x>Csg!&Y|!G zU(auNUyolH=W*T>I7HkC<6?ebWCBA2g&iL$KP=YrVGYzn_PA%g_(I^qt1f(7m|Ok=VR1hPeE=m;LeWkl z+NnYa!ARHhK_++{p_W&O!`;Pqf~W!N{CGnWU;{yWbm1`0;k|`m>+IjVnk;Q=u)0GW z)ZlT!lMpb*vs`*sD^Fzt!qp+Ka{+AvcuyoeN_ZM7kVt`yB&GG(@v-L$fwi8jkx*_q zozs8)4G*i`Qt~roz1cNyNE1mS1Cgj@Xd(rzR1!y$%0XXyR<&m^K4;2%H`W62HBh~) z2j8r%oBPH6zy7Uyb~QE(3D9M0ApfZ%KPd+_z8@D$cF(xKM#a&>>)`ueM{ zoi&9E3{7C5$HQ?-kj0Al2lXmKa14hfE#H6GtzGo91XQ=}>bKhgy23p#*Ww z0VlVfq4!kIL2xvLLwHLZY<(1^7xm6>!nmDTe{Xc4)E?tKVeC<5aL94Sjb!Zorlr|lnW@S>idoaSnd`iTg^3_cYftzw{|~M z9yOoe#(ckIwWyU~qOqu#k~IL9OV4WQ80oqkM6g6SM6lpZy_IVNM%Q1p#+I6*(v(JH zj7A%c)dph?-dcjSIQs)n>;Ho{6~Uuj?Y%2ge=kK1SRcaO?S1$UM`8xZb)dAhN@65x z<-9{X#IW?_dCpx|f9%OeJnBQ#MrFxhSfO1V)5Q@aiNFHG%CJ&KjIhMP5k(F~?M;=p z;3XL9)@Z1Mfq>-lShy)RWAnP(!@PU3_GTGmL)x)W(^E2a7zyEKaI0bL0 zT)js=BrtmKw{>8Py3+By-E-l2j;1Or|}Wzf078H2EOF&}I2#^9{M+Ipm8}!4!aB4YR|tY9gc_`F93F&F56L0I*t^zKo!Zs0t@HKF zni@wU0_r1(_I{ru9`&cReP93Blik7ZU*(r}VMj~EvThC908%QXRFtYs5l_?Dbn2^* zefmp(YMrXlfo(Tz=t}lgiqd!*aUGiq0X}$2<0&eO5|-c%!kc=_59V%fYMiIglGH2G zSV9m~Rj6fb0(kFn&Jl2ooX22k%9`oVI0Vq9zT)7iLOl(jt*b+Vu_qmiH{yLg!5XN? zJHq&gYcZD0scfJWo>o%JK8gTd1e_O?^Sh1!^(VFEe>?Ana`(4SvDdvHJzQoqvIyB= zveP2TG9r->Coyp<=(wE0$~^n`+;ZN(z2ybxt=;-KPI$rVf8wodeHXG`!s4>5S?94N zQ8gpqc|oBi+FBBOs8DagS2!!c3B2G2hO-P0%3N+fn%LzRc%8~8zj<-xc*jf%$gR51o{@&G7$ z@4n*w=bF`huhqj965&yiq%fY5QN-ODRA=s-6Q23wS#1v(P?x@aS!d;jPxqI;aUpqC z;C+OrL8mpzM6XA)*}vO+Nb%-xi1N8Pka8Owm#(r zx7^!%n3`L|5NtgzZEJAi9rzz4S|ND+n1~WY7zdl< zI+PGKY{fX+3Uw%>sI!0L1v0q90?x&M|JajP?)dks%+fB*bswN33nBu;!mzJju`s9@ zX-Dn_QETd)PrmWj&Y9ZyNah}K+Hak3#yzM1-S0r1|LQ-S@4t1yS<%8ycCTo(OPFY8 z%+2(end(8*VKubTvPG0MX`~rZ+(1MEAz`Xp(dcc!?YNTzJ8t9P&cD9->z{b%El>K5 zdpD73eMn>@LQ2raBPDd3l4`uA8)xxOA-qLlP{AO)L^z4A0)4G0wIWLt$~kf?$V=!c zfd&S;-lm&TAQ7ICud4;td9<;V+MspqU4yq2&QcnKwRNpE;OecPLtDSUJJt8zgQ%59 zq^LV#K2U2c5U}18NrjSii8qMxtn&RG_kZa1VeyLd=|&~a1uE-Uk#*9Sm!3i8FoE$Q z6`Fi$ANk6D`nzsq&yAOV^osYq=A%#h!@m^|I8blD?A$Q=`up&%;9%dOZOm-D!=^P| zI@4V$njFYeRzga%l`-3H(dxE{lC-`xB}k2@+v_5;4puf<*!5kuees>gf8~R33r~IN zAK&9p;J^qrG$N8jVtrlr6cXB*BwBT7>j^>CVwh0gszeBfCQopot|&+u z?&iKQroq-{C*0j5V;sif!u^-<-*wf;Pm6E96$9JML`W{&7Zw zK6{rmA}H2RWNeyh(nuSu3>CYUBz+SxktM9}B}_~vMBOp*qme+GBC`xy9VTXH*s%Fn zx@#XrBb(yDmG9yDFaFE(?&P?T6xB7KRjYN}p4)+AC>>I!cvT2j+ennY+CQWFJ3uo|s3S{v+mw%=NVbB5p@ z;y+yBhvL*Rr=V6FtwA`h20$PdV*=M0u#u`6hBiPX>WaqwVK;v6{pYs7_u*?N8yRZq zIJ&bNDAWY2HU$}z%9v&plSYaVB*6>3hcv1aK0nq{HC|9!&+37@xZ#qwop!~0UK0*G zP;a{O(iw5dc$=a5n*{EwPz6khY>>>^g z2}KccmNMDvFgLfB*5oFLGxmJ`uP(W#_jK|zUivN}VmetwBbK$EXIW?5Ley#|A=DXv za0Z-#Py=gJRJ8<;u5h+yK{;E}i48?jveYk;PScTwMAoG&V}5W|ra~KyHgyThyK(!~ zS=_kYYMsOVhh!??2tL%+0BXUxx^qs*-}rd5rb6n-Mc>d-wUe-g@~5 z&z`vb(${t;kHJnolIaa|lqzFeUm;b((UU3bx(RWl(0&}dQ=g>MP87{3A{vu;ysrf+ z9D-6;?D)nfxa`k=BOF$su3Y!=`IY@U*t=Yi#gdt3ebUN85x8^JabOq-LNJ+0+R@ls z*g!e-3|DR4YBauXRr)$!lS0r*A|^X6Cc0B3*)*5|S6}eQ_c$1{rJ@l_+F1m$mhm3u z7RK>m7;nEKSVGVQUwgx0t|`ij;456E859+%G$cy1)Grwo6^YbDXuQ@GWj)7VE23zu zsjuKn%`bJ9(ppB9B{!DB+PYG3sE#_0P1T{cf~X7m^+&fp2qcj;2tp9Z@d0F|3E&+Y zj-I4-?8*1}y81i+U-sTST(7FU8~&}e_VCQZnR7DF1DTM78N(n&5k#aBg%)g`E7q}n zeXaeZR@?fuTKj6XDr(Ue6bD2Z1R}FQ0wE!D$UK~!`I(v!(! zdajczIoZ!%YyH-}?sX5p`|+<$pE(z-dl7Pz3gE;**&%34F)ZpZVHlAoBcMhxP9Ts4qNp+YJft5bAyiAvIbO3)+5xb%b~ z&L)hT%^4I?`$j}8DhY!^Nd+k+Iy=&6J$(_v^sAf1zxnph>Tc#ix6KFZXn`UI+`2}} zB$%9I2qmz)Bv5h{l#Y|jbhNQ3CGfchAqpl15|koqG87U9QU;A!tffZCC8}HQ#q;;y z`oB*(P{oe>Z`I8qXsJ+0ME$8sp1`51M8#Dws7B5Pa)ySM3S3B3T#kWy0LKfUc>ooL z(0%|J22oty58yZfsvbv!ON5FbVI@GR4KzzQ{P=A*jLA+VtpGJ(8U$1WCZjM60-_`T zCv=ohqNF(b(~mWzp+h7{2rrB{qmm{^(+yE~0zieZ5ZSd2FTijkM9mGNk`l>5G>@9w z1^}c$TfZDl&JoCnqEX2xYIW2ujkW4XC{`$aRMU%)L}_HqD9n4HB2f<_bPA~;Wkj5z2_U4xP#pPl zg+h}@5jv?f5-cWAV-Z0r=K@||1$t=zyCX56I<^`m}y5Mk$|q(p?m?GDFj-f>`4qXIi%EJ zOhZaQf`Cy1ts^&8)e}%quqXl1Q3*{TWYi$pq{!J6%`gHvFZW>I!{7bVtc(Bh6Q>NQ zf$$-fMlQAk`>O(j4F$tw$l5?Ip^%^w6(p*atbfLJb6qb#Uwxs1Tc^=2|TXR z2n50)fbV&5g8)t-q8K*=yaVg8>&KthN)sS#KyeSvS_!)!{4QL#2H$hg=pBGRG>kMl zk?Y99wj#R-I%+~}G9VNZh6X?w00FHiw2&Y|gINlO27*8%n=@fhib{h=tfJ`oUL@HKtAG6fu{G0aRywqGb;oTQ{lQF8@M zBPv8@M1ev=New9!45px^h97E7vI#<0qv~)#0ZD2=35tfR5QG9|oKq@gq#*zW)6fti zazhy-&U{2#R6!n%?`x=|4t^CUnJ^t?N2N@9)Q>7OflwMrB`|$z7pA}d98hrp!JY%y zx2u9mNYRotK$rtkbHJMfJ{Vj=pb3E@7C zkg*&8XBO3@Hqgz}5tiK!#{oLc;e#xRQZu1`r@n8X*_pegNNXz;~PAp$nxs z%mhW~yV!lCAN4@PWCp02LbBKeJC#Ga(1BFzWTf*&6sOI5b5JSWJiPJ8D~Wpml2Qah zp)+rykfbi|4XqG_8e9U|q=}&lN6qE1O$v)Da6!@Z6@(NpNz_4v zD+M7U4M{X0g*>V;Bc6MGbW`X!=|o5sK~_bTtp*{mD3CCtc)l0s6)2^UF$v~Q&tvu( zT`*Dv;f5m^-0#4hdMVP=GRP_)#4EuYIt<>dAZ%6v<-;HfR65bSs3v%wz!N}?P*9VB zG6q7~Ol=o;{QB=MMB~UFq^B*0b{zQ9Lg2Zub>!{fVF*9uP*Oq)1x^&0Qqko|DQKz@ zjEo5yL`Pky83ib%&?;*B97qjIMExKb2prc3FCYF9fL9-=AvM4ZhEPUeB_4s43YN)` zwt_*D4K#nY6=hg{X(URtk)1C>ix) z5;A(GihAEbk7#ca*`rFUqtQWl-LP@~Til6Wpmn`ArZg2p)h@AZ*r9 zu2OX7lCZP`SuZ092t??C6BmvfKuQi1A#5tam;@zJaii8znqnZM@h}qkfTPreD8q|D zgHV9PQ8XF5&rM1ogoJDipPI{*XSDxkE}i(0Ujf`uMER0h!)8Fj02q}hH6((N!ec;Z zh9TqxJQT&dRVrF=AvtvDBM2O*pn;V3kbr<~Q>3Ra!8JGiaLh5o zbKdiL^2<+Ns7Y-P_6!C9A()&u(3&zZ5oF8=tRV4=*CTA3=kjO9%Av6Yk6%{$k=qE!I z4wfJwP)ED^MZJE>QI7`02)!nO0R`dJP7P4!T=?#rhQ9TN51A%K7%2FD#6oN`L^hff zs5%M>%3_8O1BYt@ASR5YLSH$ABN;+LQFnnrji-i*NG=B}lP|6IBy} z5E^Y+14Wa9TLhD*XOI;frRQoGtO!_zJnSi_VfNMIr|CK4@~BGpc>ngqPrvguwdIZv ziJ%ujy&tZ@Ac=uYGNRB-=l}^OkTxXpwub8iASy0Uj4p^Hmq8WhFVHyqOT{J*B|y?3 zFll7B3MG+FnqUSwb$(P|n6May5pNHTXtEj62t$QXa3q*OCZW&>LWCkjf&{44JZwGE z#NkpCl|~cXcMy0D_+A~J+koRV;J9@t(S#vg5C}|~+l}0mHk@|#_)CK?y#C`hnRzkt zNfVR+162VXA3I*4-~x?F<}Q{@LAir)D*b5G%kbO= z1oxn1fTkY+;0SmWbxSY}N>tRSmrJ-j?r9KL*6NtgfRPu20yd+tD2=>09!GIf0mbPv zP90Fo$@vHsgKb3dXCQL@*bERtM9g$rB9~Gas(WBM0M#MNjtf8Z;J7Yoj)TB=ph5>a zbRdH!e7^w*7fkvfRG@oW8nfmV(bsqKd6yS|wC=dc3k4jxa5iMMl zU=op@X{C^`fLz)@I%R+{3WsYnxB{gFIYLmX38d2oQbeHaCc#r(nA)8~l9}k2v$5pj zcieX>LgEYF^!}>@yA38>gzg}mdI^Ew1Q9NXj;P-mII2#F1El~}R~#);3}W+7sF95r zC40yH;lNl__myGuw)=V3b zUr{NEnj0cPI9xx#k%|MwT?p>L_gyqy2d>wI<2BKA8X(+3hWW@P1SWS`m@^}Z>Y) zl17wxUGq7Fh%QP}E97hqE)?p%L^b|2!-$}QM%O7QtzpNu=;SOzcg{d65k<>1G`QAa z7DL*kaC`-qYdC>K=qcpV1{e_-=nrtvpNb`K|Ho5W$QNekKnji|sRFzL&#Qw82U>dI zBI3vjIfoZ=R6UM>OC(s-1Z|`Ts?w20Xt%aBTIcp~x4 z$oHR;!TsthAJJ^jy|7J=k}ClaES;8u=L&ePL^5Td?khAoK}U*VsHxFYm9R~UCfBI@ z(a}dqR4SrkhLD1#(3v+ddvYEf?O7aQi?HY~Zh6IHSa;{QZ{766f4o7d08Jj1P$Vq^ zivby%p^#=E1Za4X?NxOpER*82$u`7$>yP+RU^G*uF5+eT~B1eXeBUn0dc%FPh{H4b0IJXvugUrnN>aEwN#j8K5d z2yzxh+KQQHltv-TaQcdA=$_q)p&=6;*S^?PL3-It3^$^LWTiElzJw2Z)z4k(XvKig6gNhTmQN1!5qBtnVZLz!0vqyTW%+unO) z*TwGxB{s4w>iO*l3L)31I1&|CBA;TI*=E8dKwF9-K@rjK07%;elkyCm85T9LRS`90 z!;>f`DQ35rSl(^ptSJf1EEq9sWn{n$p+G1>J=Ac5D4J!`sPkXSrVxPw=L&()NE!s% zU?_2*QVTK2TYhgK1pv4Ed{kT@3|%-u6NLC^xE_cMAr*&+Yr%|>V_zzWxT;ntjZj9_ zvr22E4T6G2VHpg}1X^+i<}YhUYhJ_YucDMWXZZJ$IKANV56-Hwsc19>s?8AlhkVq0 z1;Ye-${~~jI&%~m8=#O7O2Qx#({jM{JdiRZvUZ$tW0B}$6SuPLm#r|)c=xN?Anh$5 z{0y0S<;RE3Y!}juz>2S`I^JXhH6Ck+$gWaaW2hl8)D)=s3YI~Tu?gHzMn!{!AeFPg zY=%mpaHt$&&v1ZBpkNymX57)Pt7yYw6pk<8`vMlxm^LGY>GN_hO$Nl9!Lk_g2?H_^ zaGL^V*K*8!^Cy0ivc%>g>U|7`{?gJrMq$cgLlr{e(!(ns~p$} z!_sKUm}pHK7_14T6Abe@Ed*R)e~H88K*pv>5RHHuuX!NG=tWNSW04_YSJXgCmFI9 zL&X(1Q0B6NLnW$1V7sXW&hLf7@$DF7fRTU#jWQrpObKj7*=FjDfUC&|eoQ zH$~jVCAv5bITDmc{$R^y@T3M0Wn@+*8S*y8q*fcP`3#UK!d?2_tLLwJY15G3%V2+c z^NqT+XDz6#!eUWWn^C}GkwOUpi>V(&8EKGQ)XF&PkC*G{9 z`=3QIM`5tYg*UU+Lc>=$P~xynhG_+cFx1%8?}HG6Vv0e7pyEr&5#UN7mn4|nYQxTU zB7fGq?wWns%lj_;-Uj^C?f<5GH{6HvP(MPyjx^(OGHsN)7AMreW`J!F2%%wH3ADGj zAk{t@iA7i5HTSZywIh7BslLF-mk9ZVp3T813*FtClv~?sw zxq@zRwB${sTBjnv>?$nz)8iLx{@w@t%rCz4wL_bq_>ivbgJ_fhEx>4GfP*juia{|O zGp5ZzvSkXAGtT(ug_r%sr(eqj`NcoIN7KIb@Vq((>n=jBV2}}VohTc~WCVs05k;6Z z%4*k$QrajY+d64cq%De2X$&?6nt?(~g2EyML8y_iDB3fTnL|M#hzZxsqt{Ji-}V;} zl**V>AShn?=eX?CxBNkX^~pQ_^O=Lc`O(T|xd%`I00Bw}EJ~sxKCV$rQkW*ipeLb( zhRq0Ck_@dG3wA0EKRX>QXWw|iqKi-5iSRWa?6yaL-rcB{KP?5H*-|WidEq4|-+}K` z%ROKEh^}mZ7@=1NAd!qu0zcGf1` z!|U#TuhY93T6mx_J zvPlbpV(_xFkX>>a&cFT>FI$^$f8+{X+WZ?#frmnC4ykkBj*CD3pMP*`xcUAce5ic* zg|E4T`;le=296v=y%D0=Jsn-s<{{HH>o?2Z`d1f>=a~~geTDMG9bbFCbYSbU+QIGM z)q`kH1GW)mLopU*3n?XFnYuKJ`1-2$*Fhmnxy#g*2w3!5_Hq3MZMqvt0 z`_oVTL1SS8sIRt5?*1QL&bW8J65&G4z4M*gaGL-{y;ei#q;BLprd=Jt-2b{u|8&zy zUt&J-R_z~H3jql$(}p?cUX6?1|4%Pj%bxqcx}&yl;{xW_k!Au+3nVNJ3IWga&{uX) zYI>-+9s**+$`p|)PC?t8GjP^B|L{ON0o4DY^4*VLt(*IvLN;xnP-sQVvdgjReg8sU zc;LHVG7dfSanmWo&g78KWgrznx#6SfJCNLk^c^&sO*B0hO8OXXIH(6<+~X~Q_F2m@ zbJ>Oa7hm<)vnGH#A+K1z^N}mG>feB5%0fP!LD$S>DEeh|OqmI*YbK0r20G-Zmg*>1 z>TumCWs-3Rj^`i<926~qzFHH9$_}*VFsX|C#kPgHE8mQjANcwo1V-q@a{tejcmKyd zBsJq~IL!d9EWi|1LifV6kXd>z?76c*GC9;k1HNX+rww#w4CE3fl9mCGh$K^M3fo|? z&8QKv)D%7^sJH>PKlyX~;xkw137}5ME0*iOcqf@$EMijIBor53h{U|5Alq^%R2ovn6qW=?SqypGK!PzaLSqjFMV)K(?OBK4eDP{M0n`b3MY8qL zyV~Y<70@yNT-Z}*fwUw5E}_dIjF6*{lt?j&;bxSE7q2{~!0K6TqrYkLRG_NhR|h?soKK1k@pAW_<6rRJk& z*pGNwWmIJV9kCb^0A8rz3k^b|YK)Xgk+T?#n8n(W1f`viWBrf*MNa^ALdGrYe)f%D zXX|@`++>(38xS12>;bL^@aWTQdg!V8X!s$hPrwYY6N}=HLz_$qfW@!W&4^Rd`L8hAQXWX0R~D9)angT-hgzQa2*Gp>mu+y zgnD6yE2?rw_uG2)XG>}RdfJIRc1VTSV)A8VV9z+;`s1P9uKuM%gmE`cGKpCe!K0?af%_PzXQFR1O0i6sH`V37+0zx8hODHpdj}Qe@pyqN6c~PHMt|Fogq9fK8sYiNQ z#dJG5ZeBB;Zv=LFX6D`1{0OtZy#jJ(#N6Uy3lhKHBN9(9xK!TB@^y^83y(SqV6F~hRDyE&i zgV% zWh!RZi%g8D2+yVzoO2|yHm1y-Isw!P8Jo;F`>n$&Jq@;@!4N`m7h%{$5W1i;;`9o6 z0HQ-k8KS4+<6zlGBMiZ)1Q!vP!bn%Zk@)`zQ5!*22bMA@3>viz&R7OIW^^Fc*){>x z2^qVP;#^pk0h0-s@WF)#B7IQhfx(YCp`!j)Zph&T9K+41QLs%V%$W6B>BvTn$jpF< zkSF2}vtrJ$W-~z7yvdlda0)2Q37}5M*rl0U@Q$9cfgAZJn( zEecHth*Fq3w}^$yi%5nw^!2CFdG-xoo&f5Ej7#41H@A?!uz;o)M$I0igeMiekb@$M z>APV>vTHGggrT6MLMSAJR&lQZ4NoZeLV?kUU_%oil_Y4-o0!p+0DK>fx~|3AEB6jG(<>U|PXIF%glzr4t4~ z3EUv!YE7jWd_VgCra|G+0>W9>+%fl@Q^TM*CJ)EN68~|@FTVUqJ+OHVxYGyQARsg% zXESKj*EN|oz!*WP#-ZW{WXZIJvcutc0>z?@bb^9cIi|GPXz7>&`*k;bf9@OKd*f^B zikn#4KR#K1&ksJd`=RfBtvP%UJaoad1SNnG^Iu67wcN~D1g1ey3pIQZvAbjpimt4Q zmi8iO+f1DH;k*7IFfswuKVo_M=eK<8;L|^QuiLW)CgHJklPvpUG|D)!EyWtP*g{3_Z>4Ap=m5?EuE26D) z3KHE5an4_SZUPe%G9eQ(Armqo6EYzaG9kam%M>}uXX;n@@2C3xj(rDx3cp{U!u8az z;Je5e=S{!LYxWW`UWG|Hb`i+$7~JRq=~D>WlYPJAy`vuW`{P*C-}+_`hfh7B9!+O=y(w~AKB0ELWq za#yWdMX$T=IxCaO*oj2KOeT|-X_}U4nsy?Qu%wifb1sI5hk3153oDfhFO^E+jvYJ1 z)~#Flo;`cSs727nyc0PA0FJ)PkAM7Qv%9<7_B_wxoYUdqVbW|iQK?jPv)M$wURO#* zHJ+~P>d`+f%R1p$)9Lh4uq2a7LMf%TZIf&^ON+%KNhXt22%$G@*bv@%=bhoez=;=huqLw0~B{#GPh>}ujLVZxfk(yLJ z-``)Y)%W)f4DBDT)Q2r->)%qiyc`R;TowTKb5h-x(*S``RXT1#PR$qg+z(Mm~8hyXP_1=LmP}Sg8(+6 zG-WWBVU!jqB^j-xsFsH}JiO+?`#*K_KlKb%>Ksw>z8E#P$J4gtzWeU8&OGzXS?P4@ z3L^Q%n){QaS2KmzkV;8k8_9Ch3pZ`p`24TGdF$=F?tk#1=BQ_jQS*b}v1YG2P)WQ1 z^!n?s?`m&vUum245)!&Acw?x=?|VUby*mW2^cu=}kaZrZ;0(7HQ*e$V#%?tifAI8J!XV#{OSX~&KonOQSuz8j(Q z9=B(U+1&d~z$?8}OHM%zO$)$;H zz>lBJN6nFbHNZ;73ewG+H|M*%yU$3cl2>W3dXd+&)oAQ|f(Ly&v(l@zLWvZ{l#N9M znBh=6T_=g04-pv3tL3!hHnmc9W6JXV2YB)4fAi1ZcwpnUUA1`d{;0tpd$f>^8#m@A zPoBIinXoTpD!4#Ydndbxw@PRKdhp=`c@;E^P%??JXNzeN>Jd9#Gg_vXjY*4YUZP|B z^LzRp{_3}H-SG6fXKV4Ik6w_Y@72@OGr7H({eETLk6Wu7e$lQ1r|mdqRy+nGL5MoK z5ebPGm7MTcj{llK>k*rgMt|09lr0(kvSC+L_vuf3_^Wq+>EUO#_5*MLxTD^G^vOU5 z2M6cmGO5poeLGeTJ^CFH4D6W!EtAJzO6s%X)PrKu>Dzw##J1Z$`=xJfiJ$Eq=lQP) ztZXbG-M@c-$JD7)uS+s@li#y-N$Key%KFB;Tf(7z(=>Nmpp`Wa?M$InLUTW_y;`dd zoFbG+L2FBkFe7Vyg}hC>7cD(qKk?kQ-iG7pV{F!!yxZQrd#B8pG2>k}mG2h=FPv3- z{=Q`8*`M0(p0$%iwYOV~pa89{@tZl?gb1^$G1w-CcIQ~*NZYhY?Mp9Qb-@&=N#Dk; zJHr!QjxN9aa=SA_PcJ`l>m2Enr=4Jfya+OA251A&CbYJqkFubZeVmVV^mm}m_+!Lt zNniFpN+zja$<14GM)<=A)*TuJm}5@@vU>Gua?Lf@oR7x9+lLKv4nMbLr+W-AGyqaAm&J;@k#k2$ymWk!lvCdZ5Dm@g`S?la@`+o^Q>C6iu~j!KRLTtEPP5<4qq_%&^H`s z=i^hAU+;oerwSAlS|+tuFVIGB?(8#HEHLt2ed{)EZ5*RP$gW+xaPYwX^8AI12C}V_ zz!+mXbP})N-4qDrAcRK%Aji{EzwNn%NZ(9#&KkV;$;|_?9T^;Bw%~#bF0d{*|J-xJ zBb%4`hc>mu=F-^aMusVa*Aw#>FUxG*-+#DwupAz9A$~<3fD;1sv!DGeyX>;d&a#R4 zNM*w>t=h)BJ9Ox_k3&l-Fss7t;z7@BIUHKKerhJGR7=DfhW>UfCK9&6v}+Uwp4zl) zc=V0+o_p?D*gdK1)8Ub=iw7S3YTzH)J`+l0#|Q%b3IiS#BFLiNn}6Nn1v7P`(6@f; zuKKZH-F@%~?tbjK!M%fx7iKJfJ!x-i>(Y(BR1DT}tdLc1B)YaA5yf4@y0E{&iU(b* zc)+)chqzVf5mvsR*r_UmR*>SvcDUBm$hMV!ux8`F*yaz8xv1i*tFB7CZrRccME{OO z!IAC7_*5Ftyrk1KOm@#cEqr+0)*~So@))q5G*FG-;^xWOmU*FnWJ_y(^Zk|%-HvfA ztX5{a@7Z!@=YOx+R2ix?JW5H}R>;arS1!n0v~b$=LfAJ0L8J4x_;MNZD;;h3$5|LwjP4m`ebS6wOXm<9_B#=>OM){IiZC?UmM+P+}Lo?!ueYqx(VJc^{ylt5o0I7>Ex~T1vOD=v3afe?& z_~O4>w*izti782Vt{g442E7 zf>nljYjDe=|L2BFuJ0Qdx^>geeWQ=$kwpp|*Q?M>yGs(eK)V$+=I^0~+v~FGqtCq% z3{~n5fGVZ5Ic3TewfJ=_v$*tuh8bM1x=Lr*^cLjOHa&F=p{AAMW1y}oTBLg%HY zA0gTk;9N>G2I$D;YXqoz!GZ-{2GnfX7$Q*e*vpUO zu@SGv(N9*bTE$kcUOn4Z?lqP5KT9dM(luV2il&N=m!9ekRvLBB_bXcKkx$L_gZd-S zZtLG&l07TVKF>(QGa-W1G4G?bVOMrkja~OXx%G%)TJ9%5`NOei<8X!%O~`k8Hqy&!y<4{_PDWr@o!y?B-C*_c;Oxj5GE(9EuG zDY3(MJ-%sJDO~|jnmc!{`~QCNi;Lg)7k_@)C1;+t|D z*N!uUN0%*LXs){SjoB4vo@FdryhL|&ba>1#>YnE{!!UIA_YBm3_4Kv_r=NX3+OxJz zg=a%+3J?Wm*6U`+?pxMu+p%?T&(PetbLCBc^}+LVqO`cO?v8{GoH0%$;p?l}t^a!4 zugd@`0EPh!#Xrjp$1NWzy928(xonc{_1h3Z7UOkgi6BwPrI~N!2iI@gTRA2Iq*kn0 zVgAX*t1jjT*SDzVaLZUVsy339^}XWoL+f`A0VvzHUH-raK2TWw);GUJ?0Up#uKm9W z9A4isuOl&O=G+DSzk2fd-u|Jovv%vg!}CsC9=7Gv8q{nGE7!Mf(0cCgzkT;kDOC+X zH3q6P0@N>j;S0rivuCXid$-PWc0FE%o{(~3IZs3GA5Jcg^z~;f+%m1RSU5CL5o^|NsRSW+ z;?3F|6+}_1R;^-7mMmFdAUv;naHG`WxE0fJF~FLA({H-!tc#x6{KCND{$X!a)M~_L z6(1B<2`q;d1B}HZ~xKWyB>MAf8osTBD6Mk9~$uY_YO9sR5i=8n&+K&-n0aj zosFKYfRxFS+EB%)B`>&ugr` z%~f7)){C1}TeRLY_u5NW&fK)?;5Gn$-SM1z9^X)owKt28+91}X^>{uw0Qvs+zdzej z$X~_>Uuf|UZ8DEDzY5gwpp`MM;EocRj_}ZezkS!0XMOlzzISYtQ5~aM^+{c(9{BY` zm1VQ9+s1O8b7W&ky#nVsfmTTfKdFTe=~k2+-WLeNa$skg-Pw-L4_-2R@pW(f%HZw4 zdh(fX-16T&p687?_I&`2OeW(lU9z}c*7~Vz4(7&pG%KUMkk#?CoOq!cu}1ad@39W| z90?zNe(!_Vu6*4BRqJg)1TEv#s&*nQcdlGGeaf1rH}wdqMvhi4r6h!qap!AN?&Qwu zW>d~P>&mHix}YuFWX;X@3V-iY`IlWHMNn8gWy&l7dqx4m$4k@jL=4c8FehKSbSXLi z{PUMvR9!x}?IBOPl_|&0ud;H7dUShlN5&{7>ifGO!{S)ip7_9b1|Q!}ik#K#k_u^@L0&8i%KT@T#-VX)9#g0pv!{ z4NjcrIwqi^R4U2;ee)N#4D#d})-wGFK=>($_7Ff@kYPbP!&BA4wX-J=J-*_WPhI!+ z_gr`NWX6~T5T?^cR4&B;`w!iWI?Z~gl9!#!2L)@YyQ zg3$0JE)c2qG;J;B()rPgK`EsGp(hb!pim-<(CLI<>(+j45=2lu(PhkpOvc|kVz!Jn zd1~>`X1qZ|0O}p@c*jbE=szhx^HX2>jm~4A8QLueKmUV=hV~uquYdKwf4YB5EqzF5 zItRvKUlN2)>r|^T?;V$4umC_FKn6e(fEAC0{4TK46GUw^0KH}V3;qW`^KU;ZXXZXa zvh9ZeB5>-2K&zB?O4FXAntDYmt>z1Kao+4GNVoAR;^K#khkKDuvT&!7vS?t1><-+$$M zYnyG$`eCI?V>e^8WjF)f*PJ_l<@_0wyN=PS=2*NS^aLTsqc+WRTXr_C{p7!W|4?G# zeaKJV142EVS|JcY3me$7@VaxSUH--k&Y0e8Hj|Bdou6d&-+#aN zmYY8Rv#)*neeT&^b1r4I12Z7P{5T^y!#8yDCqjM(3rcIj~K208AxkhYqBjbwNDmbcBB_7-Nksbs2|PN$ldX@&VhKAoD`Za0r?sKRfg#=ME$;qLQh z&0l`u%Ef!vJiTdjz=6j=RpYw#fAgE)WLI8!<>GWId0Eh`c6{hv@96zM-}v^{5B%dd zAAjfN7Yu*kP0KGSgnhGUP-}w-b8$Z8t1n@*b8bN|n%a@yxoPv}`jT^}D-as|_8iIM zM@kC1+I7Pfub=ks|M%YBcqflG=8vWj4h;a7=hVYN|O31;cY#v7gzs%ck z-+lL`TUuJK64fKKYMbs=kUV|7uWzwr%UjQw(oQJV24jK}q6j6L5RdTQ&6+4h^>`GA zlBtY$WahPRIAh7PTX*+Y8?J*Fs{$lmTGOR}m&2c2cG+cZt;ND$g+qJK3%5Pu72T@% z)H}{UyFEqj`S*fA>uHg~u1^ zU2D#~@uGRxzVU)H@&}F#);@pB&$s>M7k|9wKOZ~t;B(FPCrYW=&+<(7Hf?2&fEo^7 zT90$`zAWLV3YkQH$Bq|dZ#C#6nfCfgJy(X=c3qnK{?(Vxk8hpnQ5T-kHj+xEQb}f~ z2wwDkj_sT_(&gv&^fw$o80{yNnM{TeXj3am$MfnML|nRUYf%9vW0*0$tPQLx!jw>;r*S?-gT)MY$v#z$s}Z0fDDTeVG$yD z@gsTmbiJ-%d$7We#P{7f-*5!k51CN z-~H}XOH0cl9k>{mO-ZObBs2ZbY}?Q~(aMJ81mh*>AP^%!6+#TIUH9yk zvMcuzGg*Ie=~MmB4VgO*_6?1MM_n8zF?#jt)y9Ga3r?rPePeCwnou-{J8&xR8NcOX zb$W|`#ziYnn-*WHey6+YxJUos;Gmz%N>6JwdJsg1ZbxeH`4!*$hY!@Q`q-Br%oi=N7@#+gtpFbVFvq^Js%1KlPKvFXtt~PZL zg!ti4e|g}IXa3EhLaLb8PHFl{_&Ku~_wcm$z3rm2w(L1PaHw~{9d-0$+O%o-$VWbM zZpt>!srBwq7)MU#|JUA?$HsA;_wUWQ2Y0y#mp3Vrq9mJibeIhlw31@U2kO{OYuauh z3zF-$FksZE{g2zUXbU0gKPej2fQtrcn<}+y7FL{Es1w`rAv2O`i@JD-q{!v9yq3FM z?ln8JbIYd1?#%2~BC&973jOyy@ zGO!FD8!Ek(3?Bl7ScY~2_XPmRUF#o^etPEJvw!?Ri{Yh{c@r_}n81(!@XW_!rfFqL z0{R+pNT8D^Pu942?nz~?-(Q^SbAM&x$yZR6w7Astm&cAAxOn~Ml3`jB5!*Fj9UcI^ z4p6B>hYnFK^;JiTlb=AEgsjEevu8>U&zi$!TZ zna+>KmV~tFEk69j@$G0OYJ#DZZS_Qv*zipEh3ITNmCdCy*(}3*miO=bMk5G|zAZad ztD!GX*h{+}`n_kWHQJL6hQikF-MiTnCr*Son4GB9$)EwL(x++ z+ct25@oHr(r2$20fN0GwgIWCv$N+@aOMPz5R>he0u@>vDYF+t!U_1r4mvMiI3b?Mf z-qX{g9qecyX8cv#wPLQ+t3y!CG;Bv#;75P{%(iHbzHxnIawIw(OQcrPqM|4kMNzuX z=i_$l*x`BV$*%h%jTNDlVV4Zb7DG!kpT3ba6BBcZq7%6O@#|;C?{91U@KEKwZk!z1 z0ha06stEwO`Ic%$aG!kUP`y=qf12}_7yaesK^IHc3B%{K+@=4buqtkbMu>r8qzqFz z{)02u=0>L%GIj>2005%T=hL2h?m2%=P4yllIYeVa+fp?wvUIK?5^=kE4#}$KoHClK z>B^;{3Hj2{M8*!BI~58Fk$S!b(pO%2g+F}wa0gH0WBH*^WOaV9&L)?9DI}%w!PrQa zi_fk|vZ9;1Xi~<0Q&ZF4 zGLP$zwD@Ri^4zP)6q3#BpK+e04;DNl-}~ox3c6uP_H#(Je9PWt7>22>t@S?s*mt)5 z>C;C#QU9B6P=wkoCo|lEg}Ji5181+yUYwYoz1i2-H!X@{mWT!z0HCj{`ZJjf)!fvq z@4l~XpP3vFY@n_XSf(3GD?u|k=Ecbo7oDFC^2Mb}PMC{8@@Ba<)k{mmAJArMvIZ>E zyZO@uX}T*o_g++;>^|2Q*L1@nRAd35pzFHadwpc)&;v(&G> zNLE-vq5><0&?ZA{7$~Mt;35?Sf-__ny{|9toVXtuG zoLQXsER1y}v?Yy#Ervsewdeldh&=f11FeU@b$>`xmH2RUItOdqPSrk%99ER_#1l_I zcX#*BM<4y|$7(7dw{N`Lk`HgfT%jqGI1dGn~DgYpI|_1XEwbWxVmj>$p% z6ns9P^!)SBSG@evpY4A1p$FQ$l;+hI1})I#@-3TUrpA|ZnETd&Z{Ks|&~M$-zN1O& zyEc$2Dk>Q@S{JAY0O;78(V4|%i2y2jYu(-5jjhd%FF|hpadGsMNbcHM zN*MVlWEN8OcgRKpvJ5K7>So8i&1JjWcBsRX3-g(LVHsB0SB?#wJ9_k}`>+4%d%wS} z%-E%ke`F}*=MhLNRd<*8!3?NE8Kfr}E8eYp(U{&(N<~pl5>B9kN2ABD*Qrj?4Y`(x(PP{uRP5k3qpT^^@ajeh^l-q^3Mk1gZ1 z(w3wxWA?=tUu^K^C-&yA{H(!J#j3B^Yk&gFaDy)UK@mcnDS7B%UF_T!HQK_} z>C~xHt&E&{dZp)IS#j)F^+s-~7EIj_|5u4Rws@rE{d6Jjsqt8>J6yN;#n9A@VVVv| z^8ipde*Ab@XIt}QnNNQN`h0&QC_=^EX*2??rdEa(AqY|`9Ej9O|Nj1!8-%?ot#_h2 zwkjGKiy8(-OWSwe%X@g5M~2LTWpeQKc1XcMu?3Y6&5Vlv@gIL2o%zoXE+w*pM1s^& z`y$~a+^W6lxqKs)5UqHyzE$=ID|8l_7P536FlN36z?wkwS%nYBCX_(*tt*M?*M5E> zJ~^LE5%M`QW&l8HYirBw3RB-y=LeeYc0ym@MRWO~6dpK#4xcOG7$iZ6h-A8{^qVmW9nl2U22LuMC52? z83#t*{P5~Htg+gJja2`w&;6ql>hh(3FY*TYxQOJ7il8WLrSd zGG;tUiL00%%zMUv(layllV4trUmlrS)^vjeLCUdBi9j}4CvE|NIUZXSd#;VgCzgu~ ziYv0>i_{5j7q8OTK!7cFwHkA?4Jwcc6jLxcUp&K9MtkE_^!1C=GpFCb67RWsGa(k0 zl@j?@2pN^3p`pUV2RpNV#%!_VeBdjZB&+#vL@Ai_CSq3QO}8EM`Ni^WS_g0bpF|99KQ^M$gTG!RTCq0I3WB>g434ysf5UYFBf8D;Ae4 ziIzooKSxAqm~|&|uDXHOelc))Y$i@RR5`Sf>bGqf&JKV00U%rzF0YOR{Z*|ERn;B4 z>TB<<3shEnAXG*v0mhX5l&QM`n=Zg6L!4$7Aj$-UG)%FoNxK9QdvdWn&R!T@%zklW zx-h$xDhiS;S{9aU^^&(YK1+mqB*F{CB{I70?1moz0vRNczg3`TRsC2ty(lI>$E$cHQbrurDCRMFqZEhpOsQsK^BXOL@zE@tu8p8+?y@ja)mWi4|aKUW838w?|zN03Zt^WCB74 zMzn5GoT4GVSTNZ_QpA}{(M0_1^H--Al9~8AFR>HaK>$GS-np&pZ~o+W_qPVA-{G`u zJ5q&8Ff}h&76X78yZavkKo%g%!W5&L6ffqnccp((o;%YsG<9hxI%}9#oG`sadk+8r zxaXgGsPX9GZ+th1q)tW`tB|4i!O~rTO%||4qqR9wfNc=2F1mZ!|VefI5LC%5l#AZbE2vdbMwrdDCCWJMxmER=+A z$d`z+pXCF95CB8~pu+x4l7=_3*dF38<)V^{ zSPBlk1gJ6rN=G)OL_V^jl3aX8^*RI-7u-(XzEfX(QWlvA=nEzBP3P|s@mVLn!#W-` z!EYc_y3X9yl9xh&+j*lFaZr$@E|mTKBCM6e+=&ofT6CxpYwT#OTQ3H42fGMLa;}&F zf>Z*~Qsz7bx3`NSK}wc?7(`e_AvRuJ$4MYrKzN-o@dlgf+CbLz7LgHtjYiJT z8N;x@<0iBP0~^;vk*6v-Kc(cbQsLLvudn|v*Z%@rXyVb)T!(M~0000. * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include - -namespace sofa::gui::qt::viewer -{ - -class EngineBackend -{ -public: - EngineBackend() = default; - virtual ~EngineBackend() = default; - - virtual void setPickingMethod(sofa::gui::common::PickHandler* pick, sofa::component::setting::ViewerSetting* viewerConf) =0; - virtual void setPrefix(const std::string& prefix) =0; - virtual const std::string screenshotName() =0; - virtual void screenshot(const std::string& filename, int compression_level = -1) =0; - virtual void setBackgroundImage(helper::io::Image* image) =0; - virtual void drawBackgroundImage(const int screenWidth, const int screenHeight)=0; - - virtual bool initRecorder(int width, int height, unsigned int framerate, unsigned int bitrate, const std::string& codecExtension="", const std::string& codecName="") =0; - virtual void endRecorder() =0; - virtual void addFrameRecorder() =0; - - -private: - -}; - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.cpp deleted file mode 100644 index 9c6b852a209..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "GLBackend.h" - -#include -#include -using sofa::helper::system::FileSystem; -#include -using sofa::helper::system::SetDirectory; -#include -using sofa::helper::Utils; - -namespace sofa::gui::qt::viewer -{ - -GLBackend::GLBackend() - : m_texLogo(nullptr) -{ -} - -GLBackend::~GLBackend() -{ -} - -void GLBackend::setPickingMethod(sofa::gui::common::PickHandler* pick, sofa::component::setting::ViewerSetting* viewerConf) -{ - if (viewerConf->d_objectPickingMethod.getValue().getSelectedId() == gui::common::PickHandler::RAY_CASTING) - pick->setPickingMethod( gui::common::PickHandler::RAY_CASTING ); - else - pick->setPickingMethod( gui::common::PickHandler::SELECTION_BUFFER); -} - -void GLBackend::setPrefix(const std::string& prefix) -{ - m_capture.setPrefix(prefix); - m_videoRecorderFFMPEG.setPrefix(prefix); -} - -const std::string GLBackend::screenshotName() -{ - return m_capture.findFilename().c_str(); -} - -void GLBackend::screenshot(const std::string& filename, int compression_level) -{ - m_capture.saveScreen(filename, compression_level); -} - -void GLBackend::setBackgroundImage(helper::io::Image* image) -{ - if(m_texLogo) - { - delete m_texLogo; - m_texLogo = nullptr; - } - - m_texLogo = new gl::Texture( image ); - m_texLogo->init(); -} - -bool GLBackend::initRecorder( int width, int height, unsigned int framerate, unsigned int bitrate, const std::string& codecExtension, const std::string& codecName) -{ - bool res = true; - std::string ffmpeg_exec_path = ""; - const std::string ffmpegIniFilePath = Utils::getSofaPathTo("etc/SofaGuiQt.ini"); - std::map iniFileValues = Utils::readBasicIniFile(ffmpegIniFilePath); - if (iniFileValues.find("FFMPEG_EXEC_PATH") != iniFileValues.end()) - { - // get absolute path of FFMPEG executable - ffmpeg_exec_path = SetDirectory::GetRelativeFromProcess( iniFileValues["FFMPEG_EXEC_PATH"].c_str() ); - } - - const std::string videoFilename = m_videoRecorderFFMPEG.findFilename(framerate, bitrate / 1024, codecExtension); - - res = m_videoRecorderFFMPEG.init(ffmpeg_exec_path, videoFilename, width, height, framerate, bitrate, codecName); - - return res; -} - -void GLBackend::endRecorder() -{ - m_videoRecorderFFMPEG.finishVideo(); -} - -void GLBackend::addFrameRecorder() -{ - m_videoRecorderFFMPEG.addFrame(); -} - -void GLBackend::drawBackgroundImage(const int screenWidth, const int screenHeight) -{ - if(!m_texLogo) - return; - - if(!m_texLogo->getImage()) - return; - - const int w = m_texLogo->getImage()->getWidth(); - const int h = m_texLogo->getImage()->getHeight(); - - glEnable(GL_TEXTURE_2D); - glDisable(GL_DEPTH_TEST); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(-0.5, screenWidth, -0.5, screenHeight, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - m_texLogo->bind(); - - const double coordWidth = int(screenWidth / w) + 1; - const double coordHeight = int(screenHeight / h) + 1; - - glColor3f(1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2d(0.0, 0.0); glVertex3d( -w*coordWidth, -h*coordHeight, 0.0 ); - glTexCoord2d(coordWidth*2.0, 0.0); glVertex3d( w*coordWidth, -h*coordHeight, 0.0 ); - glTexCoord2d(coordWidth*2.0, coordHeight*2.0); glVertex3d( w*coordWidth, h*coordHeight, 0.0 ); - glTexCoord2d(0.0, coordHeight*2.0); glVertex3d( -w*coordWidth, h*coordHeight, 0.0 ); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, 0); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glDisable(GL_TEXTURE_2D); -} - - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.h deleted file mode 100644 index 4cdce326426..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/GLBackend.h +++ /dev/null @@ -1,60 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include -#include - -#include -#include -#include - - -namespace sofa::gui::qt::viewer -{ - -class SOFA_GUI_QT_API GLBackend : public EngineBackend -{ -public: - GLBackend(); - virtual ~GLBackend(); - - void setPickingMethod(sofa::gui::common::PickHandler* pick, sofa::component::setting::ViewerSetting* viewerConf); - void setPrefix(const std::string& prefix); - const std::string screenshotName(); - void screenshot(const std::string& filename, int compression_level = -1); - void setBackgroundImage(helper::io::Image* image); - void drawBackgroundImage(const int screenWidth, const int screenHeight); - - bool initRecorder(int width, int height, unsigned int framerate, unsigned int bitrate,const std::string& codecExtension="", const std::string& codecName=""); - void endRecorder(); - void addFrameRecorder(); - -private: - gl::Capture m_capture; - gl::Texture* m_texLogo; - gl::VideoRecorderFFMPEG m_videoRecorderFFMPEG; -}; - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.cpp deleted file mode 100644 index 6224e508faa..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include -#include - -namespace sofa::gui::qt::viewer -{ - -void OglModelPolicy::load() -{ - drawTool = std::unique_ptr(new sofa::gl::DrawToolGL()); - - // Replace generic visual models with OglModel - sofa::core::ObjectFactory::AddAlias("VisualModel", "OglModel", true, - &classVisualModel); - vparams->drawTool() = drawTool.get(); - vparams->setSupported(sofa::core::visual::API_OpenGL); -} - -void OglModelPolicy::unload() -{ - sofa::core::ObjectFactory::ResetAlias("VisualModel", classVisualModel); - vparams->drawTool() = nullptr; - -} - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.h deleted file mode 100644 index 88d0f2bedd8..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/OglModelPolicy.h +++ /dev/null @@ -1,57 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include - -#include - -namespace sofa::gui::qt::viewer -{ - -class SOFA_GUI_QT_API OglModelPolicy : public VisualModelPolicy -{ -protected: - sofa::core::ObjectFactory::ClassEntry::SPtr classVisualModel; - std::unique_ptr drawTool; -public: - void load() override; - void unload() override; -}; - - -template < typename VisualModelPolicyType > -class SOFA_GUI_QT_API CustomPolicySofaViewer : public VisualModelPolicyType, public sofa::gui::qt::viewer::SofaViewer -{ -public: - using VisualModelPolicyType::load; - using VisualModelPolicyType::unload; - CustomPolicySofaViewer() { load(); } - ~CustomPolicySofaViewer() override { unload(); } -protected: -}; - -typedef CustomPolicySofaViewer< OglModelPolicy > OglModelSofaViewer; - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.cpp deleted file mode 100644 index 10b28313f20..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.cpp +++ /dev/null @@ -1,554 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "SofaViewer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace sofa::gui::common; - -namespace sofa::gui::qt::viewer -{ - -SofaViewer::SofaViewer() - : BaseViewer() - , m_isControlPressed(false) -{ - colourPickingRenderCallBack = ColourPickingRenderCallBack(this); -} - -SofaViewer::~SofaViewer() -{ -} - -void SofaViewer::redraw() -{ - getQWidget()->update(); -} - -void SofaViewer::keyPressEvent(QKeyEvent * e) -{ - - if (currentCamera) - { - sofa::core::objectmodel::KeypressedEvent kpe(e->key()); - currentCamera->manageEvent(&kpe); - } - - switch (e->key()) - { - case Qt::Key_T: - { - if (!currentCamera) break; - - if (currentCamera->getCameraType() == core::visual::VisualParams::ORTHOGRAPHIC_TYPE) - setCameraMode(core::visual::VisualParams::PERSPECTIVE_TYPE); - else - setCameraMode(core::visual::VisualParams::ORTHOGRAPHIC_TYPE); - break; - } - case Qt::Key_Shift: - { - if (!getPickHandler()) break; - const int viewport[4] = {}; - getPickHandler()->activateRay(viewport[2],viewport[3], groot.get()); - break; - } - case Qt::Key_B: - // --- change background - { - _background = (_background + 1) % 4; - if(_background==0) - { - setBackgroundImage("textures/SOFA_logo.bmp"); - } - if (_background==1) - { - setBackgroundImage("textures/SOFA_logo_white.bmp"); - } - break; - } - case Qt::Key_R: - // --- draw axis - { - m_bShowAxis = !m_bShowAxis; - break; - } - case Qt::Key_V: - // --- save video - { - if (m_isVideoButtonPressed == false) - { - if (!_video) - { - switch (SofaVideoRecorderManager::getInstance()->getRecordingType()) - { - case SofaVideoRecorderManager::SCREENSHOTS: - { - //_video = !_video; - break; - } - case SofaVideoRecorderManager::MOVIE: - { - SofaVideoRecorderManager* videoManager = SofaVideoRecorderManager::getInstance(); - const unsigned int bitrate = videoManager->getBitrate(); - const unsigned int framerate = videoManager->getFramerate(); - - const int width = getQWidget()->width(); - const int height = getQWidget()->height(); - m_backend->initRecorder(width, height, framerate, bitrate, videoManager->getCodecExtension(), videoManager->getCodecName()); - - break; - } - default: - break; - } - if (SofaVideoRecorderManager::getInstance()->realtime()) - { - const unsigned int framerate = SofaVideoRecorderManager::getInstance()->getFramerate(); - msg_info("SofaViewer") << "Starting capture timer ( " << framerate << " Hz )"; - const unsigned int interv = (1000 + framerate - 1) / framerate; - captureTimer.start(interv); - } - } - else - { - if (captureTimer.isActive()) - { - msg_info("SofaViewer") << "Stopping capture timer "; - captureTimer.stop(); - } - switch (SofaVideoRecorderManager::getInstance()->getRecordingType()) - { - case SofaVideoRecorderManager::SCREENSHOTS: - break; - case SofaVideoRecorderManager::MOVIE: - { - m_backend->endRecorder(); - break; - } - default: - break; - } - } - - _video = !_video; - } - - m_isVideoButtonPressed = true; - break; - } - case Qt::Key_W: - // --- save current view - { - if (!currentCamera) break; - saveView(); - break; - } - case Qt::Key_F1: - // --- enable stereo mode - { - currentCamera->setStereoEnabled(!currentCamera->getStereoEnabled()); - msg_info("SofaViewer") << "Stereoscopic View " << (currentCamera->getStereoEnabled() ? "Enabled" : "Disabled"); - break; - } - case Qt::Key_F2: - // --- reduce shift distance - { - currentCamera->setStereoShift(currentCamera->getStereoShift()-0.1); - msg_info("SofaViewer") << "Stereo separation = " << currentCamera->getStereoShift(); - break; - } - case Qt::Key_F3: - // --- increase shift distance - { - currentCamera->setStereoShift(currentCamera->getStereoShift()+0.1); - msg_info("SofaViewer") << "Stereo separation = " << currentCamera->getStereoShift(); - break; - } - case Qt::Key_F4: - { - // --- Switch between parallax and toedIn stereovision - switch (currentCamera->getStereoStrategy()) { - case sofa::component::visual::BaseCamera::PARALLEL: - currentCamera->setStereoStrategy(sofa::component::visual::BaseCamera::TOEDIN); - msg_info("SofaViewer") << "Stereo Strategy: TOEDIN"; - break; - case sofa::component::visual::BaseCamera::TOEDIN: - currentCamera->setStereoStrategy(sofa::component::visual::BaseCamera::PARALLEL); - msg_info("SofaViewer") << "Stereo Strategy: Parallel"; - break; - default: - currentCamera->setStereoStrategy(sofa::component::visual::BaseCamera::PARALLEL); - break; - } - break; - } - case Qt::Key_F5: - // --- enable binocular mode - { - //_stereoMode = (StereoMode)(((int)_stereoMode+1)%(int)NB_STEREO_MODES); - currentCamera->setStereoMode((sofa::component::visual::BaseCamera::StereoMode)(((int)currentCamera->getStereoMode()+1)%(int)sofa::component::visual::BaseCamera::NB_STEREO_MODES)); - switch (currentCamera->getStereoMode()) - { - case sofa::component::visual::BaseCamera::STEREO_INTERLACED: - msg_info("SofaViewer") << "Stereo mode: Interlaced"; - break; - case sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE: - msg_info("SofaViewer") << "Stereo mode: Side by Side"; break; - case sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE_HALF: - msg_info("SofaViewer") << "Stereo mode: Side by Side Half"; break; - case sofa::component::visual::BaseCamera::STEREO_FRAME_PACKING: - msg_info("SofaViewer") << "Stereo mode: Frame Packing"; break; - case sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM: - msg_info("SofaViewer") << "Stereo mode: Top Bottom"; break; - case sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM_HALF: - msg_info("SofaViewer") << "Stereo mode: Top Bottom Half"; break; - case sofa::component::visual::BaseCamera::STEREO_AUTO: - msg_info("SofaViewer") << "Stereo mode: Automatic"; break; - case sofa::component::visual::BaseCamera::STEREO_NONE: - msg_info("SofaViewer") << "Stereo mode: None"; break; - default: - msg_info("SofaViewer") << "Stereo mode: INVALID"; break; - } - break; - } - case Qt::Key_Control: - { - m_isControlPressed = true; - dmsg_info("SofaViewer")<<"QtViewer::keyPressEvent, CONTROL pressed"; - break; - } - default: - { - e->ignore(); - } - } -} - -void SofaViewer::keyReleaseEvent(QKeyEvent * e) -{ - sofa::core::objectmodel::KeyreleasedEvent kre(e->key()); - if (isControlPressed()) - { - sofa::core::objectmodel::KeyreleasedEvent keyEvent(e->key()); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), &keyEvent); - } - - currentCamera->manageEvent(&kre); - switch (e->key()) - { - case Qt::Key_V: - { - m_isVideoButtonPressed = false; - break; - } - case Qt::Key_Shift: - { - if (getPickHandler()) - getPickHandler()->deactivateRay(); - break; - } - - case Qt::Key_Control: - { - m_isControlPressed = false; - - // Send Control Release Info to a potential ArticulatedRigid Instrument - sofa::core::objectmodel::MouseEvent mouseEvent( - sofa::core::objectmodel::MouseEvent::Reset); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), &mouseEvent); - [[fallthrough]]; - } - default: - { - e->ignore(); - } - } - - - -} - -bool SofaViewer::isControlPressed() const -{ - return m_isControlPressed; -} - -// ---------------------- Here are the Mouse controls ---------------------- -void SofaViewer::wheelEvent(QWheelEvent *e) -{ - if (!currentCamera) return; - // -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - sofa::core::objectmodel::MouseEvent me(sofa::core::objectmodel::MouseEvent::Wheel,e->delta()); -#else - sofa::core::objectmodel::MouseEvent me(sofa::core::objectmodel::MouseEvent::Wheel,e->angleDelta().y()); -#endif - currentCamera->manageEvent(&me); - - getQWidget()->update(); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), &me); -} - -void SofaViewer::mouseMoveEvent ( QMouseEvent *e ) -{ - if (!currentCamera) return; - // - sofa::core::objectmodel::MouseEvent me(sofa::core::objectmodel::MouseEvent::Move,e->x(), e->y()); - currentCamera->manageEvent(&me); - - getQWidget()->update(); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), &me); -} - -void SofaViewer::mousePressEvent ( QMouseEvent * e) -{ - if (!currentCamera) return; - // - sofa::core::objectmodel::MouseEvent* mEvent = nullptr; - if (e->button() == Qt::LeftButton) { - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::LeftPressed, e->x(), e->y()); - } else if (e->button() == Qt::RightButton) { - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::RightPressed, e->x(), e->y()); -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - } else if (e->button() == Qt::MidButton) { -#else - } else if (e->button() == Qt::MiddleButton) { -#endif - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::MiddlePressed, e->x(), e->y()); - } else { - // A fallback event to rules them all... - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::AnyExtraButtonPressed, e->x(), e->y()); - } - currentCamera->manageEvent(mEvent); - - getQWidget()->update(); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), mEvent); -} - -void SofaViewer::mouseReleaseEvent ( QMouseEvent * e) -{ - if (!currentCamera) return; - // - sofa::core::objectmodel::MouseEvent* mEvent = nullptr; - if (e->button() == Qt::LeftButton) { - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::LeftReleased, e->x(), e->y()); - } else if (e->button() == Qt::RightButton) { - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::RightReleased, e->x(), e->y()); -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - } else if (e->button() == Qt::MidButton) { -#else - } else if (e->button() == Qt::MiddleButton) { -#endif - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::MiddleReleased, e->x(), e->y()); - } else { - // A fallback event to rules them all... - mEvent = new sofa::core::objectmodel::MouseEvent(sofa::core::objectmodel::MouseEvent::AnyExtraButtonReleased, e->x(), e->y()); - } - - currentCamera->manageEvent(mEvent); - - getQWidget()->update(); - if (groot) - groot->propagateEvent(core::execparams::defaultInstance(), mEvent); -} - -bool SofaViewer::mouseEvent(QMouseEvent *e) -{ - if (!currentCamera) return true; - - const int w = this->getWidth(); - const int h = this->getHeight(); - - MousePosition mousepos; - mousepos.screenWidth = w; - mousepos.screenHeight = h; - mousepos.x = e->x(); - mousepos.y = e->y(); - - if (e->modifiers() & Qt::ShiftModifier) - { - - getPickHandler()->activateRay(w,h, groot.get()); - getPickHandler()->updateMouse2D( mousepos ); - - //_sceneTransform.ApplyInverse(); - switch (e->type()) - { - case QEvent::MouseButtonPress: - - if (e->button() == Qt::LeftButton) - { - getPickHandler()->handleMouseEvent(PRESSED, LEFT); - } - else if (e->button() == Qt::RightButton) // Shift+Rightclick to remove triangles - { - getPickHandler()->handleMouseEvent(PRESSED, RIGHT); - } -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - else if (e->button() == Qt::MidButton) // Shift+Midclick (by 2 steps defining 2 input points) to cut from one point to another -#else - else if (e->button() == Qt::MiddleButton) // Shift+Midclick (by 2 steps defining 2 input points) to cut from one point to another -#endif - { - getPickHandler()->handleMouseEvent(PRESSED, MIDDLE); - } - break; - case QEvent::MouseButtonRelease: - //if (e->button() == Qt::LeftButton) - { - - if (e->button() == Qt::LeftButton) - { - getPickHandler()->handleMouseEvent(RELEASED, LEFT); - } - else if (e->button() == Qt::RightButton) - { - getPickHandler()->handleMouseEvent(RELEASED, RIGHT); - } -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - else if (e->button() == Qt::MidButton) -#else - else if (e->button() == Qt::MiddleButton) -#endif - { - getPickHandler()->handleMouseEvent(RELEASED, MIDDLE); - } - } - break; - default: - break; - } - moveRayPickInteractor(e->x(), e->y()); - } - else - { - getPickHandler()->activateRay(w,h, groot.get()); - } - return true; -} - -void SofaViewer::captureEvent() -{ - if (_video) - { - bool skip = false; - const unsigned int frameskip = SofaVideoRecorderManager::getInstance()->getFrameskip(); - if (frameskip) - { - static unsigned int skipcounter = 0; - if (skipcounter < frameskip) - { - skip = true; - ++skipcounter; - } - else - { - skip = false; - skipcounter = 0; - } - } - if (!skip) - { - switch (SofaVideoRecorderManager::getInstance()->getRecordingType()) - { - case SofaVideoRecorderManager::SCREENSHOTS : - screenshot(screenshotName(), 1); - break; - case SofaVideoRecorderManager::MOVIE : - m_backend->addFrameRecorder(); - - break; - default : - break; - } - } - } -} - - -void SofaViewer::configure(sofa::component::setting::ViewerSetting* viewerConf) -{ - BaseViewer::configure(viewerConf); - - m_backend->setPickingMethod(pick.get(), viewerConf); - -} - -//Functions needed to take a screenshot -const std::string SofaViewer::screenshotName() -{ - return m_backend->screenshotName(); - -} - -void SofaViewer::setPrefix(const std::string& prefix, bool prependDirectory) -{ - const std::string fullPrefix = (prependDirectory) - ? helper::system::FileSystem::append(sofa::gui::common::BaseGUI::getScreenshotDirectoryPath(), prefix) - : prefix; - - m_backend->setPrefix(fullPrefix); -} - -void SofaViewer::screenshot(const std::string& filename, int compression_level) -{ - m_backend->screenshot(filename, compression_level); -} - -void SofaViewer::setBackgroundImage(std::string imageFileName) -{ - if( sofa::helper::system::DataRepository.findFile(imageFileName) ) - { - backgroundImageFile = sofa::helper::system::DataRepository.getFile(imageFileName); - - std::string extension = sofa::helper::system::SetDirectory::GetExtension(imageFileName.c_str()); - std::transform(extension.begin(),extension.end(),extension.begin(),::tolower ); - - helper::io::Image* image = helper::io::Image::FactoryImage::getInstance()->createObject(extension,backgroundImageFile); - if( !image ) - { - type::vector validExtensions; - helper::io::Image::FactoryImage::getInstance()->uniqueKeys(std::back_inserter(validExtensions)); - msg_warning("SofaViewer") << "Could not create file '" << imageFileName <<"'" << msgendl - << " Valid extensions: " << validExtensions; - } - else - { - m_backend->setBackgroundImage(image); - } - } -} - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.h deleted file mode 100644 index 56c08cd1323..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/SofaViewer.h +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt::viewer -{ - -enum -{ - BTLEFT_MODE = 101, BTRIGHT_MODE = 102, BTMIDDLE_MODE = 103, -}; - -class SOFA_GUI_QT_API SofaViewer : public sofa::gui::common::BaseViewer -{ - -public: - SofaViewer(); - ~SofaViewer() override; - - /// Optional QTabWidget GUI for a concreate viewer. - virtual void removeViewerTab(QTabWidget *) {} - /// Optional QTabWidget GUI for a concreate viewer. - virtual void configureViewerTab(QTabWidget *) {} - - virtual QWidget* getQWidget()=0; - virtual QString helpString() const =0; - - //************************************************************* - // QT - //************************************************************* - //SLOTS - void captureEvent() override; - - // ---------------------- Here are the Keyboard controls ---------------------- - virtual void keyPressEvent(QKeyEvent * e); - virtual void keyReleaseEvent(QKeyEvent * e); - bool isControlPressed() const; - // ---------------------- Here are the Mouse controls ---------------------- - virtual void wheelEvent(QWheelEvent *e); - virtual void mouseMoveEvent ( QMouseEvent *e ); - virtual void mousePressEvent ( QMouseEvent * e); - virtual void mouseReleaseEvent ( QMouseEvent * e); - virtual bool mouseEvent(QMouseEvent *e); - - // Overridden from BaseViewer - virtual void configure(sofa::component::setting::ViewerSetting* viewerConf) override; - const std::string screenshotName() override; - void setPrefix(const std::string& prefix, bool prependDirectory = true) override; - virtual void screenshot(const std::string& filename, int compression_level =-1) override; - virtual void setBackgroundImage(std::string imageFileName = std::string("textures/SOFA_logo.bmp")) override; - -protected: - std::unique_ptr m_backend; - - void redraw() override; - - QTimer captureTimer; - - bool m_isControlPressed; - - ColourPickingRenderCallBack colourPickingRenderCallBack; - -signals: - virtual void redrawn() = 0; - virtual void resizeW(int) = 0; - virtual void resizeH(int) = 0; -}; - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.cpp deleted file mode 100644 index ae857b1d2b5..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include - -namespace sofa::gui::qt::viewer -{ - -VisualModelPolicy::VisualModelPolicy(core::visual::VisualParams* vparams) - :vparams(vparams) -{ -} - -VisualModelPolicy::~VisualModelPolicy() -{ - -} - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.h deleted file mode 100644 index 65474917fa0..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/VisualModelPolicy.h +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -namespace sofa::gui::qt::viewer -{ - -class SOFA_GUI_QT_API VisualModelPolicy -{ -public: - VisualModelPolicy(core::visual::VisualParams* vparams = core::visual::visualparams::defaultInstance()); - virtual ~VisualModelPolicy(); - virtual void load() = 0; - virtual void unload() = 0; -protected: - sofa::core::visual::VisualParams* vparams; - -}; - -} // namespace sofa::gui::qt::viewer diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.cpp deleted file mode 100644 index d82f3e63e35..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.cpp +++ /dev/null @@ -1,1122 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QtGLViewer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -namespace sofa::gui::qt::viewer::qgl -{ - -using std::endl; -using namespace sofa::type; -using namespace sofa::defaulttype; -using namespace sofa::gl; -using sofa::simulation::getSimulation; -using namespace sofa::simulation; -using namespace sofa::gui::common; - -helper::SofaViewerCreator QtGLViewer_class("qglviewer",false); -// --------------------------------------------------------- -// --- Constructor -// --------------------------------------------------------- - -QtGLViewer::QtGLViewer(QWidget* parent, const char* name) - : QGLViewer(parent, Qt::WindowType::Widget) -{ - this->setObjectName(name); - - m_backend = std::make_unique(); - pick = std::make_unique(); - - groot = nullptr; - initTexturesDone = false; - - backgroundColour[0]=1.0f; - backgroundColour[1]=1.0f; - backgroundColour[2]=1.0f; - - // setup OpenGL mode for the window - timerAnimate = new QTimer(this); - connect( timerAnimate, SIGNAL(timeout()), this, SLOT(animate()) ); - - _video = false; - m_bShowAxis = false; - _background = 0; - _numOBJmodels = 0; - _materialMode = 0; - _facetNormal = GL_FALSE; - _renderingMode = GL_RENDER; - - _waitForRender=false; - - ////////////////////// - - _mouseInteractorMoving = false; - _mouseInteractorSavedPosX = 0; - _mouseInteractorSavedPosY = 0; - m_isControlPressed = false; - - setManipulatedFrame( new qglviewer::ManipulatedFrame() ); - //near and far plane are better placed - camera()->setZNearCoefficient(0.005); - camera()->setZClippingCoefficient(2); - - vparams->zNear() = camera()->zNear(); - vparams->zFar() = camera()->zFar(); - - connect( &captureTimer, SIGNAL(timeout()), this, SLOT(captureEvent()) ); - - //change shortcut (now M key) for camera mode to avoid double effects of shortcut - setShortcut(CAMERA_MODE, Qt::Key_M); -} - - -// --------------------------------------------------------- -// --- Destructor -// --------------------------------------------------------- -QtGLViewer::~QtGLViewer() -{ -} - -// ----------------------------------------------------------------- -// --- OpenGL initialization method - includes light definitions, -// --- color tracking, etc. -// ----------------------------------------------------------------- -void QtGLViewer::init(void) -{ - restoreStateFromFile(); - - - static GLfloat specref[4]; - static GLfloat ambientLight[4]; - static GLfloat diffuseLight[4]; - static GLfloat specular[4]; - static GLfloat lmodel_ambient[] = {0.0f, 0.0f, 0.0f, 0.0f}; - static GLfloat lmodel_twoside[] = {GL_FALSE}; - static GLfloat lmodel_local[] = {GL_FALSE}; - bool initialized = false; - - if (!initialized) - { - _lightPosition[0] = -0.7f; - _lightPosition[1] = 0.3f; - _lightPosition[2] = 0.0f; - _lightPosition[3] = 1.0f; - - ambientLight[0] = 0.5f; - ambientLight[1] = 0.5f; - ambientLight[2] = 0.5f; - ambientLight[3] = 1.0f; - - diffuseLight[0] = 0.9f; - diffuseLight[1] = 0.9f; - diffuseLight[2] = 0.9f; - diffuseLight[3] = 1.0f; - - specular[0] = 1.0f; - specular[1] = 1.0f; - specular[2] = 1.0f; - specular[3] = 1.0f; - - specref[0] = 1.0f; - specref[1] = 1.0f; - specref[2] = 1.0f; - specref[3] = 1.0f; - - // Here we initialize our multi-texturing functions - glewInit(); - - _clearBuffer = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; - _lightModelTwoSides = false; - - glDepthFunc(GL_LEQUAL); - glClearDepth(1.0); - glEnable(GL_NORMALIZE); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - // Set light model - glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local); - glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); - - // Setup 'light 0' - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specular); - glLightfv(GL_LIGHT0, GL_POSITION, _lightPosition); - - // Enable color tracking - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - - // All materials hereafter have full specular reflectivity with a high shine - glMaterialfv(GL_FRONT, GL_SPECULAR, specref); - glMateriali(GL_FRONT, GL_SHININESS, 128); - - glShadeModel(GL_SMOOTH); - - // Define background color - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - //glBlendFunc(GL_SRC_ALPHA, GL_ONE); - //Load texture for logo - setBackgroundImage(); - - - glEnableClientState(GL_VERTEX_ARRAY); - //glEnableClientState(GL_NORMAL_ARRAY); - - // Turn on our light and enable color along with the light - //glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - //glEnable(GL_COLOR_MATERIAL); - - //init Quadrics - _arrow = gluNewQuadric(); - gluQuadricDrawStyle(_arrow, GLU_FILL); - gluQuadricOrientation(_arrow, GLU_OUTSIDE); - gluQuadricNormals(_arrow, GLU_SMOOTH); - - _tube = gluNewQuadric(); - gluQuadricDrawStyle(_tube, GLU_FILL); - gluQuadricOrientation(_tube, GLU_OUTSIDE); - gluQuadricNormals(_tube, GLU_SMOOTH); - - _sphere = gluNewQuadric(); - gluQuadricDrawStyle(_sphere, GLU_FILL); - gluQuadricOrientation(_sphere, GLU_OUTSIDE); - gluQuadricNormals(_sphere, GLU_SMOOTH); - - _disk = gluNewQuadric(); - gluQuadricDrawStyle(_disk, GLU_FILL); - gluQuadricOrientation(_disk, GLU_OUTSIDE); - gluQuadricNormals(_disk, GLU_SMOOTH); - - // change status so we only do this stuff once - initialized = true; - - _beginTime = helper::system::thread::CTime::getTime(); - - printf("\n"); - - - // GL_LIGHT1 follows the camera - // glMatrixMode(GL_MODELVIEW); - // glPushMatrix(); - // glLoadIdentity(); - // glLightfv(GL_LIGHT0, GL_POSITION, _lightPosition); - // glPopMatrix(); - - - - // camera()->setType( qglviewer::Camera::ORTHOGRAPHIC ); - // camera()->setType( qglviewer::Camera::PERSPECTIVE ); - - } - - // switch to preset view - - resetView(); - - // Redefine keyboard events - // The default SAVE_SCREENSHOT shortcut is Ctrl+S and this shortcut is used to - // save x3d file in the MainController. So we need to change it: - setShortcut(QGLViewer::SAVE_SCREENSHOT, Qt::Key_S); - setShortcut(QGLViewer::HELP, Qt::Key_H); - // Disable ESC shortcut - setShortcut(QGLViewer::EXIT_VIEWER, 0); - - - // some useful libQGLViewer's mouse bindings are using Shift and Ctrl keys - // that causes trouble with SOFA bindings - // so let's redefined them - - // change pivot center: right click + double left click - setMouseBinding(Qt::NoModifier, Qt::LeftButton, RAP_FROM_PIXEL, true, Qt::RightButton); - - // Zoom: right click + double middle click - setMouseBinding(Qt::NoModifier, Qt::MiddleButton, ZOOM_ON_PIXEL, true, Qt::RightButton); -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtGLViewer::PrintString(void* /*font*/, char* string) -{ - gl::GlText::draw(string); - -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtGLViewer::Display3DText(float x, float y, float z, char* string) -{ - glPushMatrix(); - glTranslatef(x, y, z); - gl::GlText::draw(string); - glPopMatrix(); -} - -// --------------------------------------------------- -// --- -// --- -// --------------------------------------------------- -void QtGLViewer::DrawAxis(double xpos, double ypos, double zpos, - double arrowSize) -{ - glPushMatrix(); - glTranslatef(xpos, ypos,zpos); - QGLViewer::drawAxis(arrowSize); - glPopMatrix(); -} - -// --------------------------------------------------- -// --- -// --- -// --------------------------------------------------- -void QtGLViewer::DrawBox(SReal* minBBox, SReal* maxBBox, SReal r) -{ - if (r==0.0) - r = (Vec3(maxBBox) - Vec3(minBBox)).norm() / 500; -#if 0 - { - Enable depth; - Disable lighting; - glColor3f(0.0, 1.0, 1.0); - glBegin(GL_LINES); - for (int corner=0; corner<4; ++corner) - { - glVertex3d( minBBox[0] , - (corner&1)?minBBox[1]:maxBBox[1], - (corner&2)?minBBox[2]:maxBBox[2]); - glVertex3d( maxBBox[0] , - (corner&1)?minBBox[1]:maxBBox[1], - (corner&2)?minBBox[2]:maxBBox[2]); - } - for (int corner=0; corner<4; ++corner) - { - glVertex3d((corner&1)?minBBox[0]:maxBBox[0], - minBBox[1] , - (corner&2)?minBBox[2]:maxBBox[2]); - glVertex3d((corner&1)?minBBox[0]:maxBBox[0], - maxBBox[1] , - (corner&2)?minBBox[2]:maxBBox[2]); - } - - // --- Draw the Z edges - for (int corner=0; corner<4; ++corner) - { - glVertex3d((corner&1)?minBBox[0]:maxBBox[0], - (corner&2)?minBBox[1]:maxBBox[1], - minBBox[2] ); - glVertex3d((corner&1)?minBBox[0]:maxBBox[0], - (corner&2)?minBBox[1]:maxBBox[1], - maxBBox[2] ); - } - glEnd(); - return; - } -#endif - Enable depth; - Enable lighting; - Enable colorMat; - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glShadeModel(GL_SMOOTH); - - // --- Draw the corners - glColor3f(0.0, 1.0, 1.0); - for (int corner=0; corner<8; ++corner) - { - glPushMatrix(); - glTranslated((corner&1)?minBBox[0]:maxBBox[0], - (corner&2)?minBBox[1]:maxBBox[1], - (corner&4)?minBBox[2]:maxBBox[2]); - gluSphere(_sphere,2*r,20,10); - glPopMatrix(); - } - - glColor3f(1.0, 1.0, 0.0); - // --- Draw the X edges - for (int corner=0; corner<4; ++corner) - { - glPushMatrix(); - glTranslated( minBBox[0] , - (corner&1)?minBBox[1]:maxBBox[1], - (corner&2)?minBBox[2]:maxBBox[2]); - glRotatef(90,0,1,0); - gluCylinder(_tube, r, r, maxBBox[0] - minBBox[0], 10, 10); - glPopMatrix(); - } - - // --- Draw the Y edges - for (int corner=0; corner<4; ++corner) - { - glPushMatrix(); - glTranslated((corner&1)?minBBox[0]:maxBBox[0], - minBBox[1] , - (corner&2)?minBBox[2]:maxBBox[2]); - glRotatef(-90,1,0,0); - gluCylinder(_tube, r, r, maxBBox[1] - minBBox[1], 10, 10); - glPopMatrix(); - } - - // --- Draw the Z edges - for (int corner=0; corner<4; ++corner) - { - glPushMatrix(); - glTranslated((corner&1)?minBBox[0]:maxBBox[0], - (corner&2)?minBBox[1]:maxBBox[1], - minBBox[2] ); - gluCylinder(_tube, r, r, maxBBox[2] - minBBox[2], 10, 10); - glPopMatrix(); - } -} - - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtGLViewer::DrawXYPlane(double zo, double xmin, double xmax, double ymin, - double ymax, double step) -{ - /*register*/ double x, y; - - Enable depth; - - glBegin(GL_LINES); - for (x = xmin; x <= xmax; x += step) - { - glVertex3d(x, ymin, zo); - glVertex3d(x, ymax, zo); - } - glEnd(); - - glBegin(GL_LINES); - for (y = ymin; y <= ymax; y += step) - { - glVertex3d(xmin, y, zo); - glVertex3d(xmax, y, zo); - } - glEnd(); -} - - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtGLViewer::DrawYZPlane(double xo, double ymin, double ymax, double zmin, - double zmax, double step) -{ - /*register*/ double y, z; - Enable depth; - - glBegin(GL_LINES); - for (y = ymin; y <= ymax; y += step) - { - glVertex3d(xo, y, zmin); - glVertex3d(xo, y, zmax); - } - glEnd(); - - glBegin(GL_LINES); - for (z = zmin; z <= zmax; z += step) - { - glVertex3d(xo, ymin, z); - glVertex3d(xo, ymax, z); - } - glEnd(); - -} - - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtGLViewer::DrawXZPlane(double yo, double xmin, double xmax, double zmin, - double zmax, double step) -{ - /*register*/ double x, z; - Enable depth; - - glBegin(GL_LINES); - for (x = xmin; x <= xmax; x += step) - { - glVertex3d(x, yo, zmin); - glVertex3d(x, yo, zmax); - } - glEnd(); - - glBegin(GL_LINES); - for (z = zmin; z <= zmax; z += step) - { - glVertex3d(xmin, yo, z); - glVertex3d(xmax, yo, z); - } - glEnd(); -} - -void QtGLViewer::drawColourPicking(ColourPickingVisitor::ColourCode code) -{ - - // Define background color - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // GL_PROJECTION matrix - camera()->loadProjectionMatrix(); - // GL_MODELVIEW matrix - camera()->loadModelViewMatrix(); - - - - ColourPickingVisitor cpv(sofa::core::visual::visualparams::defaultInstance(), code); - cpv.execute(groot.get()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtGLViewer::DrawLogo() -{ - m_backend->drawBackgroundImage(_W, _H); -} - -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtGLViewer::DisplayOBJs() -{ - - - if (_background == 0 || _background == 1) - DrawLogo(); - - if (!groot) return; - - // // Initialize lighting - glPushMatrix(); - glLoadIdentity(); - glLightfv(GL_LIGHT0, GL_POSITION, _lightPosition); - glPopMatrix(); - Enable light0; - // - glColor3f(0.5f, 0.5f, 0.6f); - // DrawXZPlane(-4.0, -20.0, 20.0, -20.0, 20.0, 1.0); - // DrawAxis(0.0, 0.0, 0.0, 10.0); - - - if (!groot->f_bbox.getValue().isValid()) viewAll(); - - - sofa::type::BoundingBox& bbox = vparams->sceneBBox(); - bbox = groot->f_bbox.getValue(); - - Enable light; - Enable depth; - - glShadeModel(GL_SMOOTH); - //glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glColor4f(1,1,1,1); - glDisable(GL_COLOR_MATERIAL); - - if (!initTexturesDone) - { - // std::cout << "-----------------------------------> initTexturesDone\n"; - //--------------------------------------------------- - sofa::simulation::node::initTextures(groot.get()); - //--------------------------------------------------- - initTexturesDone = true; - } - - - { - this->setSceneBoundingBox(qglviewer::Vec(vparams->sceneBBox().minBBoxPtr()), - qglviewer::Vec(vparams->sceneBBox().maxBBoxPtr())); - - //Draw Debug information of the components - sofa::simulation::node::draw(vparams, groot.get()); - if (m_bShowAxis) - { - //DrawAxis(0.0, 0.0, 0.0, 10.0); - DrawAxis(0.0, 0.0, 0.0, this->sceneRadius()); - - if (vparams->sceneBBox().isValid()) - DrawBox(vparams->sceneBBox().minBBoxPtr(), vparams->sceneBBox().maxBBoxPtr()); - - // 2D Axis: project current world orientation in the lower left part of the screen - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0,vparams->viewport()[2],0,vparams->viewport()[3],-30,30); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - const sofa::type::Quat sofaQuat( this->camera()->orientation()[0] - , this->camera()->orientation()[1] - , this->camera()->orientation()[2] - , this->camera()->orientation()[3]); - gl::Axis::draw(sofa::type::Vec3(30.0_sreal,30.0_sreal,0.0_sreal),sofaQuat.inverse(), 25.0, sofa::type::RGBAColor::red(), sofa::type::RGBAColor::green(), sofa::type::RGBAColor::blue()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - } - } - - // glDisable(GL_COLOR_MATERIAL); -} - -// ------------------------------------------------------- -// --- -// ------------------------------------------------------- -void QtGLViewer::DisplayMenu(void) -{ - Disable light; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(-0.5, _W, -0.5, _H, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glColor3f(0.3f, 0.7f, 0.95f); - glRasterPos2i(_W / 2 - 5, _H - 15); - //sprintf(buffer,"FPS: %.1f\n", _frameRate.GetFPS()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void QtGLViewer::MakeStencilMask() -{ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D(0,_W, 0, _H ); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glClear(GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_ALWAYS, 0x1, 0x1); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - glColor4f(0,0,0,0); - glBegin(GL_LINES); - for (float f=0 ; f< _H ; f+=2.0) - { - glVertex2f(0.0, f); - glVertex2f(_W, f); - } - glEnd(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtGLViewer::drawScene(void) -{ - - camera()->getProjectionMatrix( lastProjectionMatrix ); - sofa::core::visual::VisualParams::Viewport& viewport = vparams->viewport(); - viewport[0] = 0; - viewport[1] = 0; - viewport[2] = camera()->screenWidth(); - viewport[3] = camera()->screenHeight(); - - vparams->zFar() = camera()->zFar(); - vparams->zNear() = camera()->zNear(); - - camera()->getModelViewMatrix( lastModelviewMatrix ); - vparams->setModelViewMatrix( lastModelviewMatrix ); - - vparams->setProjectionMatrix( lastProjectionMatrix ); - - //update info to SofaCamera - //TODO - - if (_renderingMode == GL_RENDER) - { - DisplayOBJs(); - DisplayMenu(); // always needs to be the last object being drawn - } - -} - -void QtGLViewer::viewAll() -{ - if (!groot) return; - sofa::type::BoundingBox& bbox = vparams->sceneBBox(); - bbox = groot->f_bbox.getValue(); - - - if (bbox.minBBox().x() == bbox.maxBBox().x() || !bbox.isValid()) - { - bbox.minBBox().x() = -1; - bbox.maxBBox().x() = 1; - } - if (bbox.minBBox().y() == bbox.maxBBox().y() || !bbox.isValid()) - { - bbox.minBBox().y() = -1; - bbox.maxBBox().y() = 1; - } - if (bbox.minBBox().z() == bbox.maxBBox().z() || !bbox.isValid()) - { - bbox.minBBox().z() = -1; - bbox.maxBBox().z() = 1; - } - - QGLViewer::setSceneBoundingBox( qglviewer::Vec(bbox.minBBoxPtr()),qglviewer::Vec(bbox.maxBBoxPtr())) ; - - qglviewer::Vec pos; - pos[0] = 0.0; - pos[1] = 0.0; - pos[2] = 75.0; - camera()->setPosition(pos); - camera()->showEntireScene(); -} - - - -// --------------------------------------------------------- -// --- Reshape of the window, reset the projection -// --------------------------------------------------------- -void QtGLViewer::resizeGL(int width, int height) -{ - _W = width; - _H = height; - - - QGLViewer::resizeGL( width, height); - - // TODO: find a better fix -#if not defined(__APPLE__) - this->resize(width, height); -#endif - - emit( resizeW( _W ) ); - emit( resizeH( _H ) ); -} - - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtGLViewer::draw() -{ - /// clear buffers (color and depth) - if (_background==0) - glClearColor(0.0f,0.0f,0.0f,1.0f); - else if (_background==1) - glClearColor(0.0f,0.0f,0.0f,1.0f); - else if (_background==2) - glClearColor(0.0f,0.0f,0.0f,0.0f); - else if (_background==3) - glClearColor(backgroundColour[0],backgroundColour[1],backgroundColour[2], 1.0f); - glClearDepth(1.0); - glClear(_clearBuffer); - - /// draw the scene - drawScene(); - - if(!captureTimer.isActive()) - SofaViewer::captureEvent(); - - if (_waitForRender) - { - _waitForRender = false; - } - - emit( redrawn() ); -} - -void QtGLViewer::setCameraMode(core::visual::VisualParams::CameraType mode) -{ - SofaViewer::setCameraMode(mode); - - switch (mode) - { - case core::visual::VisualParams::ORTHOGRAPHIC_TYPE: - camera()->setType( qglviewer::Camera::ORTHOGRAPHIC ); - break; - case core::visual::VisualParams::PERSPECTIVE_TYPE: - camera()->setType( qglviewer::Camera::PERSPECTIVE ); - break; - } -} - - -// ---------------------------------------- -// --- Handle events (mouse, keyboard, ...) -// ---------------------------------------- - - -void QtGLViewer::keyPressEvent ( QKeyEvent * e ) -{ - if (isControlPressed()) - { - if (groot ) - { - sofa::core::objectmodel::KeypressedEvent keyEvent(e->key()); - groot->propagateEvent(core::execparams::defaultInstance(), &keyEvent); - } - } - - switch(e->key()) - { - case Qt::Key_A: // axis - case Qt::Key_H: // help page - case Qt::Key_G: // show grid - { - // these shortcuts are handled by qglviewer - QGLViewer::keyPressEvent(e); - break; - } - case Qt::Key_C: - { - viewAll(); - break; - } - default: - { - SofaViewer::keyPressEvent(e); - } - } - update(); -} - - -void QtGLViewer::screenshot(const std::string& filename, int compression_level) -{ - SOFA_UNUSED(compression_level); - QGLViewer::saveSnapshot(QString::fromStdString(filename), false); -} - - -void QtGLViewer::keyReleaseEvent ( QKeyEvent * e ) -{ - - QGLViewer::keyReleaseEvent(e); - SofaViewer::keyReleaseEvent(e); -} - - -void QtGLViewer::mousePressEvent ( QMouseEvent * e ) -{ - if( ! mouseEvent(e) ) - { - if ( isControlPressed() ) - SofaViewer::mousePressEvent(e); - else - QGLViewer::mousePressEvent(e); - } -} - - -void QtGLViewer::mouseReleaseEvent ( QMouseEvent * e ) -{ - if( ! mouseEvent(e) ) - { - if (isControlPressed()) - SofaViewer::mouseReleaseEvent(e); - else - QGLViewer::mouseReleaseEvent(e); - } -} - - -void QtGLViewer::mouseMoveEvent ( QMouseEvent * e ) -{ - if( ! mouseEvent(e) ) - { - if ( isControlPressed() ) - SofaViewer::mouseMoveEvent(e); - else - QGLViewer::mouseMoveEvent(e); - } -} - - -bool QtGLViewer::mouseEvent(QMouseEvent * e) -{ - if(e->modifiers()&Qt::ShiftModifier) - { - SofaViewer::mouseEvent(e); - return true; - } - - return false; -} - -void QtGLViewer::wheelEvent(QWheelEvent* e) -{ - QGLViewer::wheelEvent(e); - if(isControlPressed()) // pass event to the scene elements - { - if (groot) - { -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - sofa::core::objectmodel::MouseEvent me(sofa::core::objectmodel::MouseEvent::Wheel, e->delta()); -#else - sofa::core::objectmodel::MouseEvent me(sofa::core::objectmodel::MouseEvent::Wheel, e->angleDelta().y()); -#endif - groot->propagateEvent(core::execparams::defaultInstance(), &me); - } - } - else - QGLViewer::wheelEvent(e); -} - -void QtGLViewer::moveRayPickInteractor(int eventX, int eventY) -{ - const sofa::core::visual::VisualParams::Viewport& viewport = vparams->viewport(); - Vec3d p0, px, py, pz, px1, py1; - gluUnProject(eventX, viewport[3]-1-(eventY), 0, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(p0[0]), &(p0[1]), &(p0[2])); - gluUnProject(eventX+1, viewport[3]-1-(eventY), 0, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(px[0]), &(px[1]), &(px[2])); - gluUnProject(eventX, viewport[3]-1-(eventY+1), 0, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(py[0]), &(py[1]), &(py[2])); - gluUnProject(eventX, viewport[3]-1-(eventY), 0.1, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(pz[0]), &(pz[1]), &(pz[2])); - gluUnProject(eventX+1, viewport[3]-1-(eventY), 0.1, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(px1[0]), &(px1[1]), &(px1[2])); - gluUnProject(eventX, viewport[3]-1-(eventY+1), 0, lastModelviewMatrix, lastProjectionMatrix, viewport.data(), &(py1[0]), &(py1[1]), &(py1[2])); - px1 -= pz; - py1 -= pz; - px -= p0; - py -= p0; - pz -= p0; - const double r0 = sqrt(px.norm2() + py.norm2()); - double r1 = sqrt(px1.norm2() + py1.norm2()); - r1 = r0 + (r1-r0) / pz.norm(); - px.normalize(); - py.normalize(); - pz.normalize(); - Mat4x4d transform; - transform.identity(); - transform[0][0] = px[0]; - transform[1][0] = px[1]; - transform[2][0] = px[2]; - transform[0][1] = py[0]; - transform[1][1] = py[1]; - transform[2][1] = py[2]; - transform[0][2] = pz[0]; - transform[1][2] = pz[1]; - transform[2][2] = pz[2]; - transform[0][3] = p0[0]; - transform[1][3] = p0[1]; - transform[2][3] = p0[2]; - Mat3x3d mat; mat = transform; - Quat q; q.fromMatrix(mat); - - - Vec3d position, direction; - position = transform*Vec4d(0,0,0,1); - direction = transform*Vec4d(0,0,1,0); - direction.normalize(); - pick->updateRay(position, direction); - -} - -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtGLViewer::resetView() -{ - viewAll(); - - if (!sceneFileName.empty()) - { - //Test if we have a specific view point for the QGLViewer - //That case, the camera will be well placed - std::string viewFileName = sceneFileName+"."+BaseGUI::GetGUIName()+".view"; - std::ifstream in(viewFileName.c_str()); - if (!in.fail()) - { - qglviewer::Vec pos; - in >> pos[0]; - in >> pos[1]; - in >> pos[2]; - - qglviewer::Quaternion q; - in >> q[0]; - in >> q[1]; - in >> q[2]; - in >> q[3]; - q.normalize(); - - camera()->setOrientation(q); - camera()->setPosition(pos); - - in.close(); - update(); - - return; - } - else - { - //If we have the default QtViewer view file, we have to use, showEntireScene - //as the FOV of the QtViewer is not constant, so the parameters are not good - std::string viewFileName = sceneFileName+".view"; - std::ifstream in(viewFileName.c_str()); - if (!in.fail()) - { - qglviewer::Vec pos; - in >> pos[0]; - in >> pos[1]; - in >> pos[2]; - - qglviewer::Quaternion q; - in >> q[0]; - in >> q[1]; - in >> q[2]; - in >> q[3]; - q.normalize(); - - camera()->setOrientation(q); - camera()->setPosition(pos); - camera()->showEntireScene(); - - in.close(); - update(); - - return; - } - } - } - update(); -} - -void QtGLViewer::saveView() -{ - if (!sceneFileName.empty()) - { - const std::string viewFileName = sceneFileName+"."+BaseGUI::GetGUIName()+".view"; - std::ofstream out(viewFileName.c_str()); - if (!out.fail()) - { - out << camera()->position()[0] << " " << camera()->position()[1] << " " << camera()->position()[2] << "\n"; - out << camera()->orientation()[0] << " " << camera()->orientation()[1] << " " << camera()->orientation()[2] << " " << camera()->orientation()[3] << "\n"; - out.close(); - } - std::cout << "View parameters saved in "<& ori) const -{ - qglviewer::Vec position = camera()->position(); - for(int i = 0; i < 3; ++i) pos[i] = position[i]; - qglviewer::Quaternion orientation = camera()->orientation(); - for(int i = 0; i < 4; ++i) ori[i] = orientation[i]; -} - -void QtGLViewer::setView(const Vec3& pos, const Quat &ori) -{ - camera()->setPosition(qglviewer::Vec(pos[0],pos[1],pos[2])); - camera()->setOrientation(qglviewer::Quaternion(ori[0],ori[1],ori[2],ori[3])); -} - -void QtGLViewer::setSizeW( int size ) -{ - resizeGL( size, _H ); - update(); -} - -void QtGLViewer::setSizeH( int size ) -{ - resizeGL( _W, size ); - update(); - -} - -QString QtGLViewer::helpString() const -{ - - static QString text( - (QString)"

    QtGLViewer


    \ -
      \ -
    • Mouse: TO NAVIGATE
    • \ -
    • Shift & Left Button: TO PICK OBJECTS
    • \ -
    • A: TO DRAW AXIS
    • \ -
    • B: TO CHANGE THE BACKGROUND
    • \ -
    • C: TO CENTER THE VIEW
    • \ -
    • H: TO OPEN HELP of QGLViewer
    • \ -
    • O: TO EXPORT TO .OBJ
      \ - The generated files scene-time.obj and scene-time.mtl are saved in the running project directory
    • \ -
    • P: TO SAVE A SEQUENCE OF OBJ
      \ - Each time the frame is updated an obj is exported
    • \ -
    • R: TO DRAW THE SCENE AXIS
    • \ -
    • T: TO CHANGE BETWEEN A PERSPECTIVE OR AN ORTHOGRAPHIC CAMERA
    • \ - The captured images are saved in the running project directory under the name format capturexxxx.bmp
      \ -
    • S: TO SAVE A SCREENSHOT
      \ -
    • V: TO SAVE A VIDEO
      \ - Each time the frame is updated a screenshot is saved
    • \ -
    • Esc: TO QUIT ::sofa::
    " - ); - - return text; -} - -} // namespace sofa::gui::qt::viewer::qgl diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.h deleted file mode 100644 index 4ebce78d423..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qgl/QtGLViewer.h +++ /dev/null @@ -1,232 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#include -#include - -#define TRACKING_MOUSE - -namespace sofa::gui::qt::viewer::qgl -{ - -class SOFA_GUI_QT_API QtGLViewer :public QGLViewer, public sofa::gui::qt::viewer::OglModelSofaViewer -{ - typedef type::Vec3::value_type Real; - Q_OBJECT -private: - -#ifdef TRACKING_MOUSE - bool m_grabActived; -#endif - - QTimer* timerAnimate; - int _W, _H; - int _clearBuffer; - bool _lightModelTwoSides; - float _lightPosition[4]; - - - double lastProjectionMatrix[16]; - double lastModelviewMatrix[16]; - - GLUquadricObj* _arrow; - GLUquadricObj* _tube; - GLUquadricObj* _sphere; - GLUquadricObj* _disk; - GLuint _numOBJmodels; - GLuint _materialMode; - GLboolean _facetNormal; - - int _renderingMode; - - helper::system::thread::ctime_t _beginTime; - - - bool _waitForRender; - - -public: - - static QtGLViewer* create(QtGLViewer*, sofa::gui::common::BaseViewerArgument& arg) - { - common::BaseViewerArgument* pArg = &arg; - const common::ViewerQtArgument* viewerArg = dynamic_cast(pArg); - return viewerArg ? - new QtGLViewer(viewerArg->getParentWidget(), viewerArg->getName().c_str() ) : - new QtGLViewer(nullptr, pArg->getName().c_str() ) - ; - } - - static const char* viewerName() { return "QGLViewer (QtGLViewer)"; } - - static const char* acceleratedName() { return "&QGLViewer (QtGLViewer)"; } - - virtual void drawColourPicking (common::ColourPickingVisitor::ColourCode code) override; - - QtGLViewer( QWidget* parent, const char* name=""); - ~QtGLViewer() override; - - QWidget* getQWidget() override { return this; } - -protected: - - // void calcProjection(); - void init() override; - /// Overloaded from QGLViewer to render the scene - void draw() override; - /// Overloaded from SofaViewer - virtual void viewAll() override; - void resizeGL( int w, int h ) override; - -public: - - //void reshape(int width, int height); - int getWidth() override - { - return _W; - } - int getHeight() override - { - return _H; - } - bool ready() override {return !_waitForRender;} - void wait() override {_waitForRender = true;} - - void UpdateOBJ(void); - - void moveRayPickInteractor(int eventX, int eventY) override; - - void setCameraMode(core::visual::VisualParams::CameraType mode) override; - - void screenshot(const std::string& filename, int compression_level = -1) override; - - QString helpString() const override; - - -private: - - void InitGFX(void); - void PrintString(void* font, char* string); - void Display3DText(float x, float y, float z, char* string); - void DrawAxis(double xpos, double ypos, double zpos, double arrowSize); - void DrawBox(SReal* minBBox, SReal* maxBBox, SReal r=0.0); - void DrawXYPlane(double zo, double xmin, double xmax, double ymin, double ymax, double step); - void DrawYZPlane(double xo, double ymin, double ymax, double zmin, double zmax, double step); - void DrawXZPlane(double yo, double xmin, double xmax, double zmin, double zmax, double step); - void CreateOBJmodelDisplayList(int material_mode); - //int loadBMP(char *filename, TextureImage *texture); - //void LoadGLTexture(char *Filename); - void DisplayOBJs(); - void DisplayMenu(void); - void MakeStencilMask(); - - //int handle(int event); // required by FLTK - -protected: - //virtual bool event ( QEvent * e ); - - virtual void drawScene() override; - virtual void DrawLogo(void); - - - void keyPressEvent ( QKeyEvent * e ) override; - void keyReleaseEvent ( QKeyEvent * e ) override; - void mousePressEvent ( QMouseEvent * e ) override; - void mouseReleaseEvent ( QMouseEvent * e ) override; - void mouseMoveEvent ( QMouseEvent * e ) override; - void wheelEvent(QWheelEvent* e) override; - bool mouseEvent( QMouseEvent * e ) override; - - - -public slots: - void resetView() override; - void saveView() override; - void setSizeW(int) override; - void setSizeH(int) override; - - virtual void getView(type::Vec3& pos, type::Quat& ori) const override; - virtual void setView(const type::Vec3& pos, const type::Quat &ori) override; - virtual void captureEvent() override { SofaViewer::captureEvent(); } - void fitObjectBBox(sofa::core::objectmodel::BaseObject* object) override - { - if( object->f_bbox.getValue().isValid() && !object->f_bbox.getValue().isFlat() ) - this->camera()->fitBoundingBox( - ::qglviewer::Vec(object->f_bbox.getValue().minBBox()), - ::qglviewer::Vec(object->f_bbox.getValue().maxBBox()) - ); - else - { - if(object->getContext()->f_bbox.getValue().isValid() && !object->getContext()->f_bbox.getValue().isFlat() ) - { - this->camera()->fitBoundingBox( - ::qglviewer::Vec(object->getContext()->f_bbox.getValue().minBBox()), - ::qglviewer::Vec(object->getContext()->f_bbox.getValue().maxBBox()) - ); - } - } - this->update(); - } - - void fitNodeBBox(sofa::core::objectmodel::BaseNode* node) override - { - if( node->f_bbox.getValue().isValid() && !node->f_bbox.getValue().isFlat() ) - this->camera()->fitBoundingBox( - ::qglviewer::Vec(node->f_bbox.getValue().minBBox()), - ::qglviewer::Vec(node->f_bbox.getValue().maxBBox()) - ); - - this->update(); - - } - -signals: - void redrawn() override; - void resizeW( int ) override; - void resizeH( int ) override; - void quit(); -}; - -} // namespace sofa::gui::qt::viewer::qgl diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.cpp deleted file mode 100644 index fd469cbda79..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.cpp +++ /dev/null @@ -1,1558 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef __APPLE__ -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include - -#include - -namespace sofa::gui::qt::viewer::qt -{ -using std::cout; -using std::endl; -using namespace sofa::type; -using namespace sofa::defaulttype; -using namespace sofa::gui::common; - -using sofa::simulation::getSimulation; - -helper::SofaViewerCreator< QtViewer> QtViewer_class("qt",false); -//Q:Why would the QtViewer write its .view file with the qglviewer (a GPL library) extension? -//A:The new QtViewer has the same parameters as QGLViewer. -// Consequently, the old .view file is now totally incorrect. - -///TODO: standardize .view file parameters -//const std::string QtViewer::VIEW_FILE_EXTENSION = "qglviewer.view"; -const std::string QtViewer::VIEW_FILE_EXTENSION = "view"; -// Mouse Interactor -bool QtViewer::_mouseTrans = false; -bool QtViewer::_mouseRotate = false; -Quat QtViewer::_mouseInteractorNewQuat; - -// --------------------------------------------------------- -// --- Constructor -// --------------------------------------------------------- -QtViewer::QtViewer(QWidget* parent, const char* name) - : QOpenGLWidget(parent) -{ - m_backend.reset(new GLBackend()); - pick = std::make_unique(); - - this->setObjectName(name); - - groot = nullptr; - initTexturesDone = false; - backgroundColour[0] = 1.0f; - backgroundColour[1] = 1.0f; - backgroundColour[2] = 1.0f; - - _video = false; - m_bShowAxis = false; - _background = 0; - _numOBJmodels = 0; - _materialMode = 0; - _facetNormal = GL_FALSE; - _renderingMode = GL_RENDER; - _waitForRender = false; - - //////////////// - // Interactor // - //////////////// - m_isControlPressed = false; - _mouseInteractorMoving = false; - _mouseInteractorTranslationMode = false; - _mouseInteractorRotationMode = false; - _mouseInteractorSavedPosX = 0; - _mouseInteractorSavedPosY = 0; - _mouseInteractorTrackball.ComputeQuaternion(0.0, 0.0, 0.0, 0.0); - _mouseInteractorNewQuat = _mouseInteractorTrackball.GetQuaternion(); - - connect( &captureTimer, &QTimer::timeout, this, &QtViewer::captureEvent ); -} - -// --------------------------------------------------------- -// --- Destructor -// --------------------------------------------------------- -QtViewer::~QtViewer() -{ -} - -// ----------------------------------------------------------------- -// --- OpenGL initialization method - includes light definitions, -// --- color tracking, etc. -// ----------------------------------------------------------------- -void QtViewer::initializeGL(void) -{ - msg_info("QtViewer") << "OpenGL version: " << glGetString(GL_VERSION) << " (" << glGetString(GL_VENDOR) << ")"; - if (std::string((const char*)glGetString(GL_VENDOR)).find("Intel") != std::string::npos) - { - const char* mesaEnv = ::getenv("MESA_GL_VERSION_OVERRIDE"); - if ( !mesaEnv || std::string(mesaEnv) != "3.0") - msg_warning("QtViewer") << "QtViewer might not be compatible with Intel drivers on " - "Linux. If you run into rendering issues, try changing " - "the gui to qglviewer (runSofa -g qglviewer) or set the " - "environment variable \"MESA_GL_VERSION_OVERRIDE\" " - "to the value \"3.0\""; - } - - static GLfloat specref[4]; - static GLfloat ambientLight[4]; - static GLfloat diffuseLight[4]; - static GLfloat specular[4]; - static GLfloat lmodel_ambient[] = - { 0.0f, 0.0f, 0.0f, 0.0f }; - static GLfloat lmodel_twoside[] = - { GL_FALSE }; - static GLfloat lmodel_local[] = - { GL_FALSE }; - bool initialized = false; - - if (!initialized) - { - //std::cout << "progname=" << sofa::gui::qt::progname << std::endl; - //sofa::helper::system::SetDirectory cwd(sofa::helper::system::SetDirectory::GetProcessFullPath(sofa::gui::qt::progname)); - - // Define light parameters - //_lightPosition[0] = 0.0f; - //_lightPosition[1] = 10.0f; - //_lightPosition[2] = 0.0f; - //_lightPosition[3] = 1.0f; - - _lightPosition[0] = -0.7f; - _lightPosition[1] = 0.3f; - _lightPosition[2] = 0.0f; - _lightPosition[3] = 1.0f; - - ambientLight[0] = 0.5f; - ambientLight[1] = 0.5f; - ambientLight[2] = 0.5f; - ambientLight[3] = 1.0f; - - diffuseLight[0] = 0.9f; - diffuseLight[1] = 0.9f; - diffuseLight[2] = 0.9f; - diffuseLight[3] = 1.0f; - - specular[0] = 1.0f; - specular[1] = 1.0f; - specular[2] = 1.0f; - specular[3] = 1.0f; - - specref[0] = 1.0f; - specref[1] = 1.0f; - specref[2] = 1.0f; - specref[3] = 1.0f; - - // Here we initialize our multi-texturing functions - glewInit(); - if (!GL_ARB_multitexture) - msg_error("QtViewer") << "GL_ARB_multitexture not supported."; - - _clearBuffer = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; - _lightModelTwoSides = false; - - glDepthFunc(GL_LEQUAL); - glClearDepth(1.0); - glEnable(GL_NORMALIZE); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - // Set light model - glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local); - glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); - - // Setup 'light 0' - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specular); - glLightfv(GL_LIGHT0, GL_POSITION, _lightPosition); - - // Enable color tracking - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - - // All materials hereafter have full specular reflectivity with a high shine - glMaterialfv(GL_FRONT, GL_SPECULAR, specref); - glMateriali(GL_FRONT, GL_SHININESS, 128); - - glShadeModel(GL_SMOOTH); - - // Define background color - // glClearColor(0.0f, 0.0f, 1.0f, 1.0f); - - //glBlendFunc(GL_SRC_ALPHA, GL_ONE); - //Load texture for logo - setBackgroundImage(); - - glEnableClientState(GL_VERTEX_ARRAY); - //glEnableClientState(GL_NORMAL_ARRAY); - - // Turn on our light and enable color along with the light - //glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - //glEnable(GL_COLOR_MATERIAL); - - //init Quadrics - _arrow = gluNewQuadric(); - gluQuadricDrawStyle(_arrow, GLU_FILL); - gluQuadricOrientation(_arrow, GLU_OUTSIDE); - gluQuadricNormals(_arrow, GLU_SMOOTH); - - _tube = gluNewQuadric(); - gluQuadricDrawStyle(_tube, GLU_FILL); - gluQuadricOrientation(_tube, GLU_OUTSIDE); - gluQuadricNormals(_tube, GLU_SMOOTH); - - _sphere = gluNewQuadric(); - gluQuadricDrawStyle(_sphere, GLU_FILL); - gluQuadricOrientation(_sphere, GLU_OUTSIDE); - gluQuadricNormals(_sphere, GLU_SMOOTH); - - _disk = gluNewQuadric(); - gluQuadricDrawStyle(_disk, GLU_FILL); - gluQuadricOrientation(_disk, GLU_OUTSIDE); - gluQuadricNormals(_disk, GLU_SMOOTH); - - // change status so we only do this stuff once - initialized = true; - - _beginTime = CTime::getTime(); - - //printf("GL initialized\n"); - } - - // switch to preset view - resetView(); -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::PrintString(void* /*font*/, char* string) -{ - gl::GlText::draw(string); -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::Display3DText(float x, float y, float z, char* string) -{ - glPushMatrix(); - glTranslatef(x, y, z); - gl::GlText::draw(string); - glPopMatrix(); -} - -// --------------------------------------------------- -// --- -// --- -// --------------------------------------------------- -void QtViewer::DrawAxis(double xpos, double ypos, double zpos, double arrowSize) -{ - const float fontScale = (float) (arrowSize * 0.25); - - Enable depth; - Enable lighting; - Enable colorMat; - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glShadeModel(GL_SMOOTH); - - // --- Draw the "X" axis in red - glPushMatrix(); - glColor3f(1.0, 0.0, 0.0); - glTranslated(xpos, ypos, zpos); - glRotatef(90.0f, 0.0, 1.0, 0.0); - gluCylinder(_tube, arrowSize / 50.0, arrowSize / 50.0, arrowSize, 10, 10); - glTranslated(0.0, 0.0, arrowSize); - gluCylinder(_arrow, arrowSize / 15.0, 0.0, arrowSize / 5.0, 10, 10); - // ---- Display a "X" near the tip of the arrow - glTranslated(-0.5 * fontScale, arrowSize / 15.0, arrowSize / 5.0); - - gl::GlText::draw('X', sofa::type::Vec3(0.0_sreal, 0.0_sreal, 0.0_sreal), fontScale); - - // --- Undo transforms - glTranslated(-xpos, -ypos, -zpos); - glPopMatrix(); - - // --- Draw the "Y" axis in green - glPushMatrix(); - glColor3f(0.0, 1.0, 0.0); - glTranslated(xpos, ypos, zpos); - glRotatef(-90.0f, 1.0, 0.0, 0.0); - gluCylinder(_tube, arrowSize / 50.0, arrowSize / 50.0, arrowSize, 10, 10); - glTranslated(0.0, 0.0, arrowSize); - gluCylinder(_arrow, arrowSize / 15.0, 0.0, arrowSize / 5.0, 10, 10); - // ---- Display a "Y" near the tip of the arrow - glTranslated(-0.5 * fontScale, arrowSize / 15.0, arrowSize / 5.0); - gl::GlText::draw('Y', sofa::type::Vec3(0.0, 0.0, 0.0), fontScale); - // --- Undo transforms - glTranslated(-xpos, -ypos, -zpos); - glPopMatrix(); - - // --- Draw the "Z" axis in blue - glPushMatrix(); - glColor3f(0.0, 0.0, 1.0); - glTranslated(xpos, ypos, zpos); - glRotatef(0.0f, 1.0, 0.0, 0.0); - gluCylinder(_tube, arrowSize / 50.0, arrowSize / 50.0, arrowSize, 10, 10); - glTranslated(0.0, 0.0, arrowSize); - gluCylinder(_arrow, arrowSize / 15.0, 0.0, arrowSize / 5.0, 10, 10); - // ---- Display a "Z" near the tip of the arrow - glTranslated(-0.5 * fontScale, arrowSize / 15.0, arrowSize / 5.0); - gl::GlText::draw('Z', sofa::type::Vec3(0.0, 0.0, 0.0), fontScale); - // --- Undo transforms - glTranslated(-xpos, -ypos, -zpos); - glPopMatrix(); -} - -// --------------------------------------------------- -// --- -// --- -// --------------------------------------------------- -void QtViewer::DrawBox(SReal* minBBox, SReal* maxBBox, SReal r) -{ - //std::cout << "box = < " << minBBox[0] << ' ' << minBBox[1] << ' ' << minBBox[2] << " >-< " << maxBBox[0] << ' ' << maxBBox[1] << ' ' << maxBBox[2] << " >"<< std::endl; - if (r == 0.0) - r = (Vec3(maxBBox) - Vec3(minBBox)).norm() / 500; - - Enable depth; - Enable lighting; - Enable colorMat; - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glShadeModel(GL_SMOOTH); - - // --- Draw the corners - glColor3f(0.0, 1.0, 1.0); - for (int corner = 0; corner < 8; ++corner) - { - glPushMatrix(); - glTranslated((corner & 1) ? minBBox[0] : maxBBox[0], - (corner & 2) ? minBBox[1] : maxBBox[1], - (corner & 4) ? minBBox[2] : maxBBox[2]); - gluSphere(_sphere, 2 * r, 20, 10); - glPopMatrix(); - } - - glColor3f(1.0, 1.0, 0.0); - // --- Draw the X edges - for (int corner = 0; corner < 4; ++corner) - { - glPushMatrix(); - glTranslated(minBBox[0], (corner & 1) ? minBBox[1] : maxBBox[1], - (corner & 2) ? minBBox[2] : maxBBox[2]); - glRotatef(90, 0, 1, 0); - gluCylinder(_tube, r, r, maxBBox[0] - minBBox[0], 10, 10); - glPopMatrix(); - } - - // --- Draw the Y edges - for (int corner = 0; corner < 4; ++corner) - { - glPushMatrix(); - glTranslated((corner & 1) ? minBBox[0] : maxBBox[0], minBBox[1], - (corner & 2) ? minBBox[2] : maxBBox[2]); - glRotatef(-90, 1, 0, 0); - gluCylinder(_tube, r, r, maxBBox[1] - minBBox[1], 10, 10); - glPopMatrix(); - } - - // --- Draw the Z edges - for (int corner = 0; corner < 4; ++corner) - { - glPushMatrix(); - glTranslated((corner & 1) ? minBBox[0] : maxBBox[0], - (corner & 2) ? minBBox[1] : maxBBox[1], minBBox[2]); - gluCylinder(_tube, r, r, maxBBox[2] - minBBox[2], 10, 10); - glPopMatrix(); - } -} - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtViewer::DrawXYPlane(double zo, double xmin, double xmax, double ymin, - double ymax, double step) -{ - double x, y; - - Enable depth; - - glBegin(GL_LINES); - for (x = xmin; x <= xmax; x += step) - { - glVertex3d(x, ymin, zo); - glVertex3d(x, ymax, zo); - } - glEnd(); - - glBegin(GL_LINES); - for (y = ymin; y <= ymax; y += step) - { - glVertex3d(xmin, y, zo); - glVertex3d(xmax, y, zo); - } - glEnd(); -} - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtViewer::DrawYZPlane(double xo, double ymin, double ymax, double zmin, - double zmax, double step) -{ - double y, z; - Enable depth; - - glBegin(GL_LINES); - for (y = ymin; y <= ymax; y += step) - { - glVertex3d(xo, y, zmin); - glVertex3d(xo, y, zmax); - } - glEnd(); - - glBegin(GL_LINES); - for (z = zmin; z <= zmax; z += step) - { - glVertex3d(xo, ymin, z); - glVertex3d(xo, ymax, z); - } - glEnd(); - -} - -// ---------------------------------------------------------------------------------- -// --- Draw a "plane" in wireframe. The "plane" is parallel to the XY axis -// --- of the main coordinate system -// ---------------------------------------------------------------------------------- -void QtViewer::DrawXZPlane(double yo, double xmin, double xmax, double zmin, - double zmax, double step) -{ - double x, z; - Enable depth; - - glBegin(GL_LINES); - for (x = xmin; x <= xmax; x += step) - { - glVertex3d(x, yo, zmin); - glVertex3d(x, yo, zmax); - } - glEnd(); - - glBegin(GL_LINES); - for (z = zmin; z <= zmax; z += step) - { - glVertex3d(xmin, yo, z); - glVertex3d(xmax, yo, z); - } - glEnd(); -} - -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtViewer::DrawLogo() -{ - m_backend->drawBackgroundImage(_W, _H); -} - - - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::drawColourPicking(ColourPickingVisitor::ColourCode code) -{ - // Define background color - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMultMatrixd(lastProjectionMatrix); - glMatrixMode(GL_MODELVIEW); - - - ColourPickingVisitor cpv(sofa::core::visual::visualparams::defaultInstance(), code); - cpv.execute( groot.get() ); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - -} -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtViewer::DisplayOBJs() -{ - - if (_background == 0 || _background == 1) - DrawLogo(); - - if (!groot) - return; - Enable light; - Enable depth; - - - vparams->sceneBBox() = groot->f_bbox.getValue(); - - - glShadeModel(GL_SMOOTH); - //glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glColor4f(1, 1, 1, 1); - glDisable(GL_COLOR_MATERIAL); - - if (!initTexturesDone) - { - // std::cout << "-----------------------------------> initTexturesDone\n"; - //--------------------------------------------------- - sofa::simulation::node::initTextures(groot.get()); - //--------------------------------------------------- - initTexturesDone = true; - } - - { - - sofa::simulation::node::draw(vparams, groot.get()); - - if (m_bShowAxis) - { - const SReal* minBBox = vparams->sceneBBox().minBBoxPtr(); - const SReal* maxBBox = vparams->sceneBBox().maxBBoxPtr(); - SReal maxDistance = std::numeric_limits::min(); - - maxDistance = maxBBox[0] - minBBox[0]; - for (int i=1;i<3;i++) - { - if(maxDistance < (maxBBox[i] - minBBox[i])) - maxDistance = (maxBBox[i] - minBBox[i]); - } - - if(maxDistance == 0 ) - maxDistance = 1.0; - - // World Axis: Arrows of axis are defined as 10% of maxBBox - DrawAxis(0.0, 0.0, 0.0,(maxDistance*0.1)); - - if (vparams->sceneBBox().minBBox().x() < vparams->sceneBBox().maxBBox().x()) - DrawBox(vparams->sceneBBox().minBBoxPtr(), vparams->sceneBBox().maxBBoxPtr()); - - // 2D Axis: project current world orientation in the lower left part of the screen - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0,vparams->viewport()[2],0,vparams->viewport()[3],-30,30); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - gl::Axis::draw(sofa::type::Vec3(30.0,30.0,0.0),currentCamera->getOrientation().inverse(), 25.0, sofa::type::RGBAColor::red(), sofa::type::RGBAColor::green(), sofa::type::RGBAColor::blue()); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - } - } - - // glDisable(GL_COLOR_MATERIAL); -} - -// ------------------------------------------------------- -// --- -// ------------------------------------------------------- -void QtViewer::DisplayMenu(void) -{ - Disable light; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(-0.5, _W, -0.5, _H, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glColor3f(0.3f, 0.7f, 0.95f); - glRasterPos2i(_W / 2 - 5, _H - 15); - //sprintf(buffer,"FPS: %.1f\n", _frameRate.GetFPS()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); -} - -void QtViewer::MakeStencilMask() -{ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D(0,_W, 0, _H ); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glClear(GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_ALWAYS, 0x1, 0x1); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - glColor4f(0,0,0,0); - glBegin(GL_LINES); - for (float f=0 ; f< _H ; f+=2.0) - { - glVertex2f(0.0, f); - glVertex2f(_W, f); - } - glEnd(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::drawScene(void) -{ - if (!groot) return; - - if(!currentCamera) - { - msg_error("QtViewer") << "No camera defined."; - return; - } - - int width = _W; - int height = _H; - const bool stereo = currentCamera->getStereoEnabled(); - bool twopass = stereo; - sofa::component::visual::BaseCamera::StereoMode smode = currentCamera->getStereoMode(); - const sofa::component::visual::BaseCamera::StereoStrategy sStrat = currentCamera->getStereoStrategy(); - const double sShift = currentCamera->getStereoShift(); - bool stencil = false; - bool viewport = false; - const bool supportStereo = currentCamera->isStereo(); - sofa::core::visual::VisualParams::Viewport vpleft, vpright; - if(supportStereo) - { - if(stereo) - { - if (smode == sofa::component::visual::BaseCamera::STEREO_AUTO) - { - // auto-detect stereo mode - static int prevsmode = sofa::component::visual::BaseCamera::STEREO_AUTO; - if ((_W <= 1280 && _H == 1470) || (_W <= 1920 && _H == 2205)) - { - // standard HDMI 1.4 stereo frame packing format - smode = sofa::component::visual::BaseCamera::STEREO_FRAME_PACKING; - if (smode != prevsmode) std::cout << "AUTO Stereo mode: Frame Packing" << std::endl; - } - else if (_W >= 2 * _H) - { - smode = sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE; - if (smode != prevsmode) std::cout << "AUTO Stereo mode: Side by Side" << std::endl; - } - else if (_H > _W) - { - smode = sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM; - if (smode != prevsmode) std::cout << "AUTO Stereo mode: Top Bottom" << std::endl; - } - else - { - smode = sofa::component::visual::BaseCamera::STEREO_INTERLACED; - if (smode != prevsmode) std::cout << "AUTO Stereo mode: Interlaced" << std::endl; - //smode = STEREO_SYDE_BY_SIDE_HALF; - //if (smode != prevsmode) std::cout << "AUTO Stereo mode: Side by Side Half" << std::endl; - } - prevsmode = smode; - } - switch (smode) - { - case sofa::component::visual::BaseCamera::STEREO_INTERLACED: - { - stencil = true; - glEnable(GL_STENCIL_TEST); - MakeStencilMask(); - break; - } - case sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE: - case sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE_HALF: - { - width /= 2; - viewport = true; - vpleft = sofa::type::make_array(0,0,width,height); - vpright = sofa::type::make_array(_W-width,0,width,height); - if (smode == sofa::component::visual::BaseCamera::STEREO_SIDE_BY_SIDE_HALF) - width = _W; // keep the original ratio for camera - break; - } - case sofa::component::visual::BaseCamera::STEREO_FRAME_PACKING: - case sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM: - case sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM_HALF: - { - if (smode == sofa::component::visual::BaseCamera::STEREO_FRAME_PACKING && _H == 1470) // 720p format - height = 720; - else if (smode == sofa::component::visual::BaseCamera::STEREO_FRAME_PACKING && _H == 2205) // 1080p format - height = 1080; - else // other resolutions - height /= 2; - viewport = true; - vpleft = sofa::type::make_array(0,0,width,height); - vpright = sofa::type::make_array(0,_H-height,width,height); - if (smode == sofa::component::visual::BaseCamera::STEREO_TOP_BOTTOM_HALF) - height = _H; // keep the original ratio for camera - break; - } - case sofa::component::visual::BaseCamera::STEREO_AUTO: - case sofa::component::visual::BaseCamera::STEREO_NONE: - default: - twopass = false; - break; - } - } - }else - { - twopass = false; - } - calcProjection(width, height); - - glLoadIdentity(); - - GLdouble mat[16]; - - //std::cout << "Default" << this->defaultFramebufferObject() << std::endl; - currentCamera->getOpenGLModelViewMatrix(mat); - glMultMatrixd(mat); - - glGetDoublev(GL_MODELVIEW_MATRIX, lastModelviewMatrix); - vparams->setModelViewMatrix(lastModelviewMatrix); - - if(supportStereo) - { - if (stereo) - { - //1st pass - if (viewport) - { - sofa::core::visual::VisualParams::Viewport vp = vpleft; - vparams->viewport() = vp; - glViewport(vp[0], vp[1], vp[2], vp[3]); - glScissor(vp[0], vp[1], vp[2], vp[3]); - glEnable(GL_SCISSOR_TEST); - } - if (stencil) - { - glStencilFunc(GL_EQUAL, 0x1, 0x1); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - } - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - if(sStrat == sofa::component::visual::BaseCamera::PARALLEL) - { - glTranslated(sShift/2,0,0); - } - else if(sStrat == sofa::component::visual::BaseCamera::TOEDIN) - { - const double distance = currentCamera ? currentCamera->getDistance() : 10*sShift; - const double angle = atan2(sShift,distance)*180.0/M_PI; - glTranslated(0,0,-distance); - glRotated(-angle,0,1,0); - glTranslated(0,0,distance); - } - - - glMultMatrixd(mat); - } - } - - if (_renderingMode == GL_RENDER) - { - currentCamera->setCurrentSide(sofa::component::visual::BaseCamera::LEFT); - DisplayOBJs(); - } - if(supportStereo) - { - if (stereo) - { - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - } - //2nd pass - if (twopass) - { - if (viewport) - { - sofa::core::visual::VisualParams::Viewport vp = vpright; - vparams->viewport() = vp; - glViewport(vp[0], vp[1], vp[2], vp[3]); - glScissor(vp[0], vp[1], vp[2], vp[3]); - glEnable(GL_SCISSOR_TEST); - } - if (stencil) - { - glStencilFunc(GL_NOTEQUAL, 0x1, 0x1); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - } - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - if(sStrat == sofa::component::visual::BaseCamera::PARALLEL) {glTranslated(-sShift/2,0,0);} - - glMultMatrixd(mat); - if (_renderingMode == GL_RENDER) - { - currentCamera->setCurrentSide(sofa::component::visual::BaseCamera::RIGHT); - DisplayOBJs(); - } - if (stereo) - { - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - if (viewport) - { - vparams->viewport() = sofa::type::make_array(0,0,_W,_H); - glViewport(0, 0, _W, _H); - glScissor(0, 0, _W, _H); - glDisable(GL_SCISSOR_TEST); - } - if (stencil) - { - glDisable(GL_STENCIL_TEST); - } - } - DisplayMenu(); // always needs to be the last object being drawn - -} - - -// --------------------------------------------------------- -// --- Reshape of the window, reset the projection -// --------------------------------------------------------- -void QtViewer::resizeGL(int width, int height) -{ - - _W = width; - _H = height; - - if(currentCamera) - currentCamera->setViewport(width, height); - - // std::cout << "GL window: " <f_bbox.getValue().isValid() || m_bShowAxis)) - { - vparams->sceneBBox() = groot->f_bbox.getValue(); - currentCamera->setBoundingBox(vparams->sceneBBox().minBBox(), vparams->sceneBBox().maxBBox()); - } - currentCamera->computeZ(); - currentCamera->d_widthViewport.setValue(sofa::Size(width)); - currentCamera->d_heightViewport.setValue(sofa::Size(height)); - - GLdouble projectionMatrix[16]; - currentCamera->getOpenGLProjectionMatrix(projectionMatrix); - - glViewport(0, 0, width * this->devicePixelRatio(), height * this->devicePixelRatio()); // to handle retina displays - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMultMatrixd(projectionMatrix); - - glMatrixMode(GL_MODELVIEW); - glGetDoublev(GL_PROJECTION_MATRIX, lastProjectionMatrix); - - //Update vparams - vparams->zNear() = currentCamera->getZNear(); - vparams->zFar() = currentCamera->getZFar(); - vparams->viewport() = sofa::type::make_array(0, 0, width, height); - vparams->setProjectionMatrix(projectionMatrix); -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::paintGL() -{ - // clear buffers (color and depth) - if (_background == 0) - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - else if (_background == 1) - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - else if (_background == 2) - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - else if (_background == 3) - glClearColor(backgroundColour[0], backgroundColour[1], backgroundColour[2], 1.0f); - - glClearDepth(1.0); - glClear( _clearBuffer); - - // draw the scene - drawScene(); - - if(!captureTimer.isActive()) - { - SofaViewer::captureEvent(); - } - - if (_waitForRender) - { - _waitForRender = false; - } - - emit redrawn(); -} - -void QtViewer::paintEvent(QPaintEvent* qpe) -{ - QOpenGLWidget::paintEvent(qpe ); - /* - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - painter.setRenderHint(QPainter::HighQualityAntialiasing, true); - painter.setRenderHint(QPainter::TextAntialiasing, false); -*/ -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::ApplySceneTransformation(int /* x */, int /* y */) -{ - update(); -} - -// --------------------------------------------------------- -// --- -// --------------------------------------------------------- -void QtViewer::ApplyMouseInteractorTransformation(int x, int y) -{ - // Mouse Interaction - double coeffDeplacement = 0.025; - const sofa::type::BoundingBox sceneBBox = vparams->sceneBBox(); - if (sceneBBox.isValid() && ! sceneBBox.isFlat()) - coeffDeplacement *= 0.001 * (sceneBBox.maxBBox() - - sceneBBox.minBBox()).norm(); - Quat conjQuat, resQuat, _newQuatBckUp; - - float x1, x2, y1, y2; - - if (_mouseInteractorMoving) - { - if (_mouseInteractorRotationMode) - { - if ((_mouseInteractorSavedPosX != x) || (_mouseInteractorSavedPosY - != y)) - { - x1 = 0; - y1 = 0; - x2 = (2.0f * (x + (-_mouseInteractorSavedPosX + _W / 2.0f)) - - _W) / _W; - y2 = (_H - 2.0f - * (y + (-_mouseInteractorSavedPosY + _H / 2.0f))) / _H; - - _mouseInteractorTrackball.ComputeQuaternion(x1, y1, x2, y2); - _mouseInteractorCurrentQuat - = _mouseInteractorTrackball.GetQuaternion(); - _mouseInteractorSavedPosX = x; - _mouseInteractorSavedPosY = y; - - _mouseInteractorNewQuat = _mouseInteractorCurrentQuat - + _mouseInteractorNewQuat; - _mouseRotate = true; - } - else - { - _mouseRotate = false; - } - - update(); - } - else if (_mouseInteractorTranslationMode) - { - _mouseInteractorAbsolutePosition = Vec3(0, 0, 0); - - if (_translationMode == XY_TRANSLATION) - { - _mouseInteractorAbsolutePosition[0] = coeffDeplacement * (x - - _mouseInteractorSavedPosX); - _mouseInteractorAbsolutePosition[1] = -coeffDeplacement * (y - - _mouseInteractorSavedPosY); - - _mouseInteractorSavedPosX = x; - _mouseInteractorSavedPosY = y; - } - else if (_translationMode == Z_TRANSLATION) - { - _mouseInteractorAbsolutePosition[2] = coeffDeplacement * (y - - _mouseInteractorSavedPosY); - - _mouseInteractorSavedPosX = x; - _mouseInteractorSavedPosY = y; - } - - _mouseTrans = true; - update(); - } - } -} - -// ---------------------------------------- -// --- Handle events (mouse, keyboard, ...) -// ---------------------------------------- - - -void QtViewer::keyPressEvent(QKeyEvent * e) -{ - if (isControlPressed()) - { - if (groot) - { - sofa::core::objectmodel::KeypressedEvent keyEvent(e->key()); - groot->propagateEvent(core::execparams::defaultInstance(), &keyEvent); - } - } - - // control the GUI - switch (e->key()) - { - - case Qt::Key_C: - // --- switch interaction mode - if (!_mouseInteractorTranslationMode) - { - std::cout << "Interaction Mode ON\n"; - _mouseInteractorTranslationMode = true; - _mouseInteractorRotationMode = false; - } - else - { - std::cout << "Interaction Mode OFF\n"; - _mouseInteractorTranslationMode = false; - _mouseInteractorRotationMode = false; - } - break; - default: - SofaViewer::keyPressEvent(e); - } - update(); -} - -void QtViewer::keyReleaseEvent(QKeyEvent * e) -{ - SofaViewer::keyReleaseEvent(e); -} - -void QtViewer::wheelEvent(QWheelEvent* e) -{ - SofaViewer::wheelEvent(e); -} - -void QtViewer::mousePressEvent(QMouseEvent * e) -{ - mouseEvent(e); - - SofaViewer::mousePressEvent(e); -} - -void QtViewer::mouseReleaseEvent(QMouseEvent * e) -{ - mouseEvent(e); - - SofaViewer::mouseReleaseEvent(e); - -} - -void QtViewer::mouseMoveEvent(QMouseEvent * e) -{ - //if the mouse move is not "interactive", give the event to the camera - if(!mouseEvent(e)) - SofaViewer::mouseMoveEvent(e); -} - -// ---------------------- Here are the mouse controls for the scene ---------------------- -bool QtViewer::mouseEvent(QMouseEvent * e) -{ - bool isInteractive = false; - const int eventX = e->x(); - const int eventY = e->y(); - if (_mouseInteractorRotationMode) - { - switch (e->type()) - { - case QEvent::MouseButtonPress: - // Mouse left button is pushed - if (e->button() == Qt::LeftButton) - { - _mouseInteractorMoving = true; - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - break; - - case QEvent::MouseMove: - // - break; - - case QEvent::MouseButtonRelease: - // Mouse left button is released - if (e->button() == Qt::LeftButton) - { - if (_mouseInteractorMoving) - { - _mouseInteractorMoving = false; - } - } - break; - - default: - break; - } - ApplyMouseInteractorTransformation(eventX, eventY); - } - else if (_mouseInteractorTranslationMode) - { - switch (e->type()) - { - case QEvent::MouseButtonPress: - // Mouse left button is pushed - if (e->button() == Qt::LeftButton) - { - _translationMode = XY_TRANSLATION; - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - _mouseInteractorMoving = true; - } - // Mouse right button is pushed - else if (e->button() == Qt::RightButton) - { - _translationMode = Z_TRANSLATION; - _mouseInteractorSavedPosY = eventY; - _mouseInteractorMoving = true; - } - - break; - - case QEvent::MouseButtonRelease: - // Mouse left button is released - if ((e->button() == Qt::LeftButton) && (_translationMode - == XY_TRANSLATION)) - { - _mouseInteractorMoving = false; - } - // Mouse right button is released - else if ((e->button() == Qt::RightButton) && (_translationMode - == Z_TRANSLATION)) - { - _mouseInteractorMoving = false; - } - break; - - default: - break; - } - - ApplyMouseInteractorTransformation(eventX, eventY); - } - else if (e->modifiers() & Qt::ShiftModifier) - { - isInteractive = true; - SofaViewer::mouseEvent(e); - } - else if (e->modifiers() & Qt::ControlModifier) - { - isInteractive = true; - } - else if (e->modifiers() & Qt::AltModifier) - { - isInteractive = true; - switch (e->type()) - { - case QEvent::MouseButtonPress: - // Mouse left button is pushed - if (e->button() == Qt::LeftButton) - { - _navigationMode = BTLEFT_MODE; - _mouseInteractorMoving = true; - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - // Mouse right button is pushed - else if (e->button() == Qt::RightButton) - { - _navigationMode = BTRIGHT_MODE; - _mouseInteractorMoving = true; - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - // Mouse middle button is pushed -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - else if (e->button() == Qt::MidButton) -#else - else if (e->button() == Qt::MiddleButton) -#endif - { - _navigationMode = BTMIDDLE_MODE; - _mouseInteractorMoving = true; - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - break; - - case QEvent::MouseMove: - // - break; - - case QEvent::MouseButtonRelease: - // Mouse left button is released - if (e->button() == Qt::LeftButton) - { - if (_mouseInteractorMoving) - { - _mouseInteractorMoving = false; - } - } - // Mouse right button is released - else if (e->button() == Qt::RightButton) - { - if (_mouseInteractorMoving) - { - _mouseInteractorMoving = false; - } - } - // Mouse middle button is released -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - else if (e->button() == Qt::MidButton) -#else - else if (e->button() == Qt::MiddleButton) -#endif - { - if (_mouseInteractorMoving) - { - _mouseInteractorMoving = false; - } - } - break; - - default: - break; - } - if (_mouseInteractorMoving && _navigationMode == BTLEFT_MODE) - { - const int dx = eventX - _mouseInteractorSavedPosX; - const int dy = eventY - _mouseInteractorSavedPosY; - if (dx || dy) - { - _lightPosition[0] -= dx * 0.1; - _lightPosition[1] += dy * 0.1; - std::cout << "Light = " << _lightPosition[0] << " " - << _lightPosition[1] << " " << _lightPosition[2] - << std::endl; - update(); - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - } - else if (_mouseInteractorMoving && _navigationMode == BTRIGHT_MODE) - { - const int dx = eventX - _mouseInteractorSavedPosX; - const int dy = eventY - _mouseInteractorSavedPosY; - if (dx || dy) - { - //g_DepthBias[0] += dx*0.01; - //g_DepthBias[1] += dy * 0.01; - //std::cout << "Depth bias = " << g_DepthBias[0] << " " - // << g_DepthBias[1] << std::endl; - update(); - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - } - else if (_mouseInteractorMoving && _navigationMode == BTMIDDLE_MODE) - { - const int dx = eventX - _mouseInteractorSavedPosX; - const int dy = eventY - _mouseInteractorSavedPosY; - if (dx || dy) - { - //g_DepthOffset[0] += dx * 0.01; - //g_DepthOffset[1] += dy * 0.01; - //std::cout << "Depth offset = " << g_DepthOffset[0] << " " - // << g_DepthOffset[1] << std::endl; - update(); - _mouseInteractorSavedPosX = eventX; - _mouseInteractorSavedPosY = eventY; - } - } - } - - return isInteractive; -} - -void QtViewer::moveRayPickInteractor(int eventX, int eventY) -{ - - const sofa::core::visual::VisualParams::Viewport& viewport = vparams->viewport(); - - Vec3d p0, px, py, pz, px1, py1; - gluUnProject(eventX, viewport[3] - 1 - (eventY), 0, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(p0[0]), &(p0[1]), &(p0[2])); - gluUnProject(eventX + 1, viewport[3] - 1 - (eventY), 0, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(px[0]), &(px[1]), &(px[2])); - gluUnProject(eventX, viewport[3] - 1 - (eventY + 1), 0, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(py[0]), &(py[1]), &(py[2])); - gluUnProject(eventX, viewport[3] - 1 - (eventY), 0.1, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(pz[0]), &(pz[1]), &(pz[2])); - gluUnProject(eventX + 1, viewport[3] - 1 - (eventY), 0.1, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(px1[0]), &(px1[1]), &(px1[2])); - gluUnProject(eventX, viewport[3] - 1 - (eventY + 1), 0, - lastModelviewMatrix, lastProjectionMatrix, - viewport.data(), &(py1[0]), &(py1[1]), &(py1[2])); - px1 -= pz; - py1 -= pz; - px -= p0; - py -= p0; - pz -= p0; - const double r0 = sqrt(px.norm2() + py.norm2()); - double r1 = sqrt(px1.norm2() + py1.norm2()); - r1 = r0 + (r1 - r0) / pz.norm(); - px.normalize(); - py.normalize(); - pz.normalize(); - Mat4x4d transform; - transform.identity(); - transform[0][0] = px[0]; - transform[1][0] = px[1]; - transform[2][0] = px[2]; - transform[0][1] = py[0]; - transform[1][1] = py[1]; - transform[2][1] = py[2]; - transform[0][2] = pz[0]; - transform[1][2] = pz[1]; - transform[2][2] = pz[2]; - transform[0][3] = p0[0]; - transform[1][3] = p0[1]; - transform[2][3] = p0[2]; - Mat3x3d mat; - mat = transform; - Quat q; - q.fromMatrix(mat); - - Vec3d position, direction; - position = transform * Vec4d(0, 0, 0, 1); - direction = transform * Vec4d(0, 0, 1, 0); - direction.normalize(); - getPickHandler()->updateRay(position, direction); -} - -// ------------------------------------------------------------------- -// --- -// ------------------------------------------------------------------- -void QtViewer::resetView() -{ - - Quat orientation; - bool fileRead = false; - - if (!sceneFileName.empty()) - { - const std::string viewFileName = sceneFileName + "." + VIEW_FILE_EXTENSION; - fileRead = currentCamera->importParametersFromFile(viewFileName); - } - - //if there is no .view file , look at the center of the scene bounding box - // and with a Up vector in the same axis as the gravity - if (!fileRead) - { - newView(); - } - - update(); - //updateGL(); - - //SofaViewer::resetView(); - //ResetScene(); -} - -void QtViewer::newView() -{ - SofaViewer::newView(); -} - -void QtViewer::getView(Vec3& pos, Quat& ori) const -{ - SofaViewer::getView(pos, ori); -} - -void QtViewer::setView(const Vec3& pos, const Quat &ori) -{ - SofaViewer::setView(pos, ori); -} - -void QtViewer::moveView(const Vec3& pos, const Quat &ori) -{ - SofaViewer::moveView(pos, ori); -} - -void QtViewer::saveView() -{ - if (!sceneFileName.empty()) - { - const std::string viewFileName = sceneFileName + "." + VIEW_FILE_EXTENSION; - if(currentCamera->exportParametersInFile(viewFileName)) - std::cout << "View parameters saved in " << viewFileName << std::endl; - else - std::cout << "Error while saving view parameters in " << viewFileName << std::endl; - } -} - -void QtViewer::setSizeW(int size) -{ - resizeGL(size, _H); - update(); -} - -void QtViewer::setSizeH(int size) -{ - resizeGL(_W, size); - update(); -} - -//void QtViewer::setCameraMode(core::visual::VisualParams::CameraType mode) -//{ -// SofaViewer::setCameraMode(mode); - -// switch (mode) -// { -// case core::visual::VisualParams::ORTHOGRAPHIC_TYPE: -// camera()->setType( qglviewer::Camera::ORTHOGRAPHIC ); -// break; -// case core::visual::VisualParams::PERSPECTIVE_TYPE: -// camera()->setType( qglviewer::Camera::PERSPECTIVE ); -// break; -// } -//} - -QString QtViewer::helpString() const -{ - static QString - text( - "

    QtViewer


    \ -
      \ -
    • Mouse: TO NAVIGATE
    • \ -
    • Shift & Left Button: TO PICK OBJECTS
    • \ -
    • B: TO CHANGE THE BACKGROUND
    • \ -
    • C: TO SWITCH INTERACTION MODE: press the KEY C.
      \ - Allow or not the navigation with the mouse.
    • \ -
    • O: TO EXPORT TO .OBJ
      \ - The generated files scene-time.obj and scene-time.mtl are saved in the running project directory
    • \ -
    • P: TO SAVE A SEQUENCE OF OBJ
      \ - Each time the frame is updated an obj is exported
    • \ -
    • R: TO DRAW THE SCENE AXIS
    • \ -
    • S: TO SAVE A SCREENSHOT
      \ - The captured images are saved in the running project directory under the name format capturexxxx.bmp
    • \ -
    • T: TO CHANGE BETWEEN A PERSPECTIVE OR AN ORTHOGRAPHIC CAMERA
    • \ -
    • V: TO SAVE A VIDEO
      \ - Each time the frame is updated a screenshot is saved
    • \ -
    • Esc: TO QUIT ::sofa::
    "); - return text; -} - - -void QtViewer::screenshot(const std::string& filename, int compression_level) -{ - QImage screenshot; - - screenshot = this->grabFramebuffer(); - const bool res = screenshot.save(filename.c_str(), nullptr, (compression_level == -1) ? -1 : compression_level*100); // compression_level is either -1 or [0,100] - if(res) - { - msg_info("QtViewer") << "Saved " << screenshot.width() << "x" << screenshot.height() << " screen image to " << filename; - } - else - { - msg_error("QtViewer") << "Unknown error while saving screen image to " << filename; - } -} - -} // namespace sofa::gui::qt::viewer::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.h b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.h deleted file mode 100644 index 9e33cce8cc5..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/QtViewer.h +++ /dev/null @@ -1,267 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(QT_VERSION) && QT_VERSION >= 0x050400 -#include -#include -#include -#endif // defined(QT_VERSION) && QT_VERSION >= 0x050400 - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -namespace sofa::gui::qt::viewer::qt -{ - -using sofa::type::Vec3; -using sofa::type::Quat; -using namespace sofa::gl; -using namespace sofa::helper::visual; -using namespace sofa::helper::system::thread; -using namespace sofa::component::collision; - -#if defined(QT_VERSION) && QT_VERSION >= 0x050400 -typedef QOpenGLWidget QOpenGLWidget; -#else -typedef QGLWidget QOpenGLWidget; -#endif // defined(QT_VERSION) && QT_VERSION >= 0x050400 - -class SOFA_GUI_QT_API QtViewer - : public QOpenGLWidget - , public sofa::gui::qt::viewer::OglModelSofaViewer -{ - Q_OBJECT - -private: - // Interaction - enum - { - XY_TRANSLATION = 1, - Z_TRANSLATION = 2, - }; - - enum { MINMOVE = 10 }; - - - QTimer* timerAnimate; - int _W, _H; - int _clearBuffer; - bool _lightModelTwoSides; - float _lightPosition[4]; - - int _mouseX, _mouseY; - int _savedMouseX, _savedMouseY; - - GLUquadricObj* _arrow; - GLUquadricObj* _tube; - GLUquadricObj* _sphere; - GLUquadricObj* _disk; - GLuint _numOBJmodels; - GLuint _materialMode; - GLboolean _facetNormal; - float _zoom; - int _renderingMode; - - bool _waitForRender; - - //GLuint _logoTexture; - - ctime_t _beginTime; - - double lastProjectionMatrix[16]; - double lastModelviewMatrix[16]; - -public: - - static const std::string VIEW_FILE_EXTENSION; - - - static QtViewer* create(QtViewer*, common::BaseViewerArgument& arg) - { - common::BaseViewerArgument* pArg = &arg; - const common::ViewerQtArgument* viewerArg = dynamic_cast(pArg); - return viewerArg ? - new QtViewer(viewerArg->getParentWidget(), viewerArg->getName().c_str() ) : - new QtViewer(nullptr, pArg->getName().c_str() ) - ; - } - - static const char* viewerName() - { - return "OpenGL (QtViewer)"; - } - - static const char* acceleratedName() - { - return "Open&GL (QtViewer)"; - } - - /// Activate this class of viewer. - /// This method is called before the viewer is actually created - /// and can be used to register classes associated with in the ObjectFactory. - static int EnableViewer(); - - /// Disable this class of viewer. - /// This method is called after the viewer is destroyed - /// and can be used to unregister classes associated with in the ObjectFactory. - static int DisableViewer(); - - QtViewer( QWidget* parent, const char* name=""); - ~QtViewer() override; - - QWidget* getQWidget() override { return this; } - - bool ready() override {return !_waitForRender;} - void wait() override {_waitForRender = true;} - -public slots: - void resetView() override; - virtual void saveView() override; - virtual void setSizeW(int) override; - virtual void setSizeH(int) override; - - virtual void getView(type::Vec3& pos, type::Quat& ori) const override; - virtual void setView(const type::Vec3& pos, const type::Quat &ori) override ; - virtual void newView() override ; - virtual void moveView(const type::Vec3& pos, const type::Quat &ori) override ; - virtual void captureEvent() override { SofaViewer::captureEvent(); } - virtual void drawColourPicking (common::ColourPickingVisitor::ColourCode code) override ; - virtual void fitNodeBBox(sofa::core::objectmodel::BaseNode * node ) override { SofaViewer::fitNodeBBox(node); } - virtual void fitObjectBBox(sofa::core::objectmodel::BaseObject * obj) override { SofaViewer::fitObjectBBox(obj); } - -signals: - void redrawn() override ; - void resizeW( int ) override ; - void resizeH( int ) override ; - void quit(); - - -protected: - - void calcProjection( int width = 0, int height = 0 ); - void initializeGL() override; - void paintGL() override; - void paintEvent(QPaintEvent* qpe) override; - void resizeGL( int w, int h ) override; - /// Overloaded from SofaViewer - virtual void viewAll() override {} - -public: - - sofa::simulation::Node* getScene() override - { - return groot.get(); - } - - //void reshape(int width, int height); - int getWidth() override - { - return _W; - } - int getHeight() override - { - return _H; - } - - void UpdateOBJ(void); - void moveRayPickInteractor(int eventX, int eventY) override ; - ///////////////// - // Interaction // - ///////////////// - - bool _mouseInteractorTranslationMode; - bool _mouseInteractorRotationMode; - int _translationMode; - Quat _mouseInteractorCurrentQuat; - Vec3 _mouseInteractorAbsolutePosition; - Trackball _mouseInteractorTrackball; - void ApplyMouseInteractorTransformation(int x, int y); - - static Quat _mouseInteractorNewQuat; - static bool _mouseTrans; - static bool _mouseRotate; - - - QString helpString() const override ; -// void setCameraMode(core::visual::VisualParams::CameraType mode); - void screenshot(const std::string& filename, int compression_level = -1) override; - -private: - - void InitGFX(void); - void PrintString(void* font, char* string); - void Display3DText(float x, float y, float z, char* string); - void DrawAxis(double xpos, double ypos, double zpos, double arrowSize); - void DrawBox(SReal* minBBox, SReal* maxBBox, SReal r=0.0); - void DrawXYPlane(double zo, double xmin, double xmax, double ymin, - double ymax, double step); - void DrawYZPlane(double xo, double ymin, double ymax, double zmin, - double zmax, double step); - void DrawXZPlane(double yo, double xmin, double xmax, double zmin, - double zmax, double step); - void CreateOBJmodelDisplayList(int material_mode); - //int loadBMP(char *filename, TextureImage *texture); - //void LoadGLTexture(char *Filename); - void DrawLogo(void); - void DisplayOBJs(); - void DisplayMenu(void); - virtual void drawScene() override ; - void MakeStencilMask(); - - void ApplySceneTransformation(int x, int y); - //int handle(int event); // required by FLTK - - //virtual bool event ( QEvent * e ); - - void keyPressEvent ( QKeyEvent * e ) override; - void keyReleaseEvent ( QKeyEvent * e ) override; - void mousePressEvent ( QMouseEvent * e ) override; - void mouseReleaseEvent ( QMouseEvent * e ) override; - void mouseMoveEvent ( QMouseEvent * e ) override; - void wheelEvent ( QWheelEvent* e) override; - virtual bool mouseEvent ( QMouseEvent * e ) override; -}; - -} // namespace sofa::gui::qt::viewer::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/graphicon.ico b/Sofa/GUI/Qt/src/sofa/gui/qt/viewer/qt/graphicon.ico deleted file mode 100644 index adf0a2071a539814323c2b09f3e68c2d70895ce2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1406 zcmeH^&ra%45XQe&ThVI8TB~TSC{?lktG2>yNMJ`uNLUdbfCX%L6kdP@1V|ukcm=j> z*s&ul;0+)okPx`X+=x3jcX|CLGs*8eIcG9+0FH&%3sybI34jJ5$dXy`v;6db6321i zc^-lwKomttk_1_np(qMeRfVQ$&~+V#VZby^Se6Cbw&6GqT-QY;5y| zdcFQ>^xw1J4gA*|phv}X;3p>kfk%0ycj+i_!9Nf^@E3t2>HT)gAv!rDIy)h9wr;P4 z5Rp$K(tJcA;mQ^+pH1PK=vpwJF9n #include #include -#include namespace sofa::gui { @@ -37,8 +36,7 @@ void init() sofa::gui::component::init(); sofa::gui::common::init(); sofa::gui::batch::init(); - sofa::gui::qt::init(); - + first = false; } } diff --git a/Sofa/framework/Config/CMakeLists.txt b/Sofa/framework/Config/CMakeLists.txt index e1374daf83c..5a418a64568 100644 --- a/Sofa/framework/Config/CMakeLists.txt +++ b/Sofa/framework/Config/CMakeLists.txt @@ -240,7 +240,7 @@ endif() ## Tracy option(SOFA_TRACY "Compile SOFA with the Tracy profiler client" OFF) if (SOFA_TRACY) - set(SOFA_TRACY_VERSION v0.9.1) + set(SOFA_TRACY_VERSION v0.11.1) include(FetchContent) option(TRACY_STATIC "Whether to build Tracy as a static library" OFF) FetchContent_Declare ( diff --git a/Sofa/framework/Config/cmake/SofaMacrosConfigure.cmake b/Sofa/framework/Config/cmake/SofaMacrosConfigure.cmake index 47574524727..0fa3ac323ae 100644 --- a/Sofa/framework/Config/cmake/SofaMacrosConfigure.cmake +++ b/Sofa/framework/Config/cmake/SofaMacrosConfigure.cmake @@ -294,7 +294,13 @@ macro(sofa_add_subdirectory type directory name) endif() set(default_value OFF) - if(${ARGV3}) + if(ARG_EXTERNAL) + set(input_value ${ARGV6}) + else() + set(input_value ${ARGV3}) + endif () + + if(${input_value}) set(default_value ON) endif() diff --git a/Sofa/framework/Config/cmake/SofaMacrosInstall.cmake b/Sofa/framework/Config/cmake/SofaMacrosInstall.cmake index 096546f9d10..f4f348099fe 100644 --- a/Sofa/framework/Config/cmake/SofaMacrosInstall.cmake +++ b/Sofa/framework/Config/cmake/SofaMacrosInstall.cmake @@ -31,7 +31,7 @@ include(CMakeParseLibraryList) macro(sofa_create_package_with_targets) set(oneValueArgs PACKAGE_NAME PACKAGE_VERSION INCLUDE_ROOT_DIR INCLUDE_INSTALL_DIR INCLUDE_SOURCE_DIR EXAMPLE_INSTALL_DIR RELOCATABLE) set(multiValueArgs TARGETS) - set(optionalArgs AUTO_SET_TARGET_PROPERTIES) + set(optionalArgs AUTO_SET_TARGET_PROPERTIES NO_AUTO_RESOURCES_INSTALL) cmake_parse_arguments("ARG" "${optionalArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Required arguments foreach(arg ARG_PACKAGE_NAME ARG_PACKAGE_VERSION ARG_TARGETS) @@ -226,7 +226,7 @@ endmacro() macro(sofa_add_targets_to_package) set(oneValueArgs PACKAGE_NAME PACKAGE_VERSION INCLUDE_ROOT_DIR INCLUDE_INSTALL_DIR INCLUDE_SOURCE_DIR EXAMPLE_INSTALL_DIR RELOCATABLE OPTIMIZE_BUILD_DIR) set(multiValueArgs TARGETS) - set(optionalArgs AUTO_SET_TARGET_PROPERTIES) + set(optionalArgs AUTO_SET_TARGET_PROPERTIES NO_AUTO_RESOURCES_INSTALL) cmake_parse_arguments("ARG" "${optionalArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Required arguments foreach(arg ARG_PACKAGE_NAME ARG_TARGETS) @@ -600,7 +600,7 @@ endmacro() macro(sofa_install_targets_in_package) set(oneValueArgs PACKAGE_NAME PACKAGE_VERSION INCLUDE_ROOT_DIR INCLUDE_INSTALL_DIR INCLUDE_SOURCE_DIR EXAMPLE_INSTALL_DIR RELOCATABLE OPTIMIZE_BUILD_DIR) set(multiValueArgs TARGETS) - set(optionalArgs AUTO_SET_TARGET_PROPERTIES) + set(optionalArgs AUTO_SET_TARGET_PROPERTIES NO_AUTO_RESOURCES_INSTALL) cmake_parse_arguments("ARG" "${optionalArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Required arguments foreach(arg ARG_PACKAGE_NAME ARG_TARGETS ARG_INCLUDE_INSTALL_DIR) @@ -700,16 +700,18 @@ macro(sofa_install_targets_in_package) endforeach() endforeach() - # Install examples and scenes - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples") - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples/" - DESTINATION "${example_install_dir}" - COMPONENT resources) - endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/scenes") - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/scenes/" - DESTINATION "${example_install_dir}" - COMPONENT resources) + if(NOT ARG_NO_AUTO_RESOURCES_INSTALL) + # Install examples and scenes + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples/" + DESTINATION "${example_install_dir}" + COMPONENT resources) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/scenes") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/scenes/" + DESTINATION "${example_install_dir}" + COMPONENT resources) + endif() endif() # Install info files (README, license, etc.) diff --git a/Sofa/framework/Core/src/sofa/core/Multi2Mapping.h b/Sofa/framework/Core/src/sofa/core/Multi2Mapping.h index 6616b222fa2..c0ead569710 100644 --- a/Sofa/framework/Core/src/sofa/core/Multi2Mapping.h +++ b/Sofa/framework/Core/src/sofa/core/Multi2Mapping.h @@ -229,23 +229,6 @@ class Multi2Mapping : public BaseMapping return !error && BaseMapping::canCreate(obj, context, arg); } - /// Construction method called by ObjectFactory. - /// - /// This implementation read the input and output attributes to - /// find the input and output models of this mapping. - template - static typename T::SPtr create(T*, core::objectmodel::BaseContext* context, core::objectmodel::BaseObjectDescription* arg) - { - typename T::SPtr obj = sofa::core::objectmodel::New(); - - if (context) - context->addObject(obj); - - if (arg) - obj->parse(arg); - - return obj; - } protected: void getVecIn1Coord (const MultiVecCoordId id, type::vector< DataVecCoord_t*> &v) const diff --git a/Sofa/framework/Core/src/sofa/core/MultiMapping.h b/Sofa/framework/Core/src/sofa/core/MultiMapping.h index c6ecfe48c78..bc65f24d32f 100644 --- a/Sofa/framework/Core/src/sofa/core/MultiMapping.h +++ b/Sofa/framework/Core/src/sofa/core/MultiMapping.h @@ -231,26 +231,6 @@ class MultiMapping : public BaseMapping return BaseMapping::canCreate(obj, context, arg); } - /// Construction method called by ObjectFactory. - /// - /// This implementation read the input and output attributes to - /// find the input and output models of this mapping. - template - static typename T::SPtr create(T*, core::objectmodel::BaseContext* context, core::objectmodel::BaseObjectDescription* arg) - { - typename T::SPtr obj = sofa::core::objectmodel::New(); - - if (context) - context->addObject(obj); - - if (arg) - { - obj->parse(arg); - } - - return obj; - } - protected: void getVecInCoord (const MultiVecCoordId id, type::vector< InDataVecCoord* > &v) const diff --git a/Sofa/framework/Core/src/sofa/core/behavior/MixedInteractionConstraint.h b/Sofa/framework/Core/src/sofa/core/behavior/MixedInteractionConstraint.h index d2c82954415..51b2322c62e 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/MixedInteractionConstraint.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/MixedInteractionConstraint.h @@ -113,21 +113,6 @@ class MixedInteractionConstraint : public BaseInteractionConstraint, public Pair /// This is the method that should be implemented by the component virtual void buildConstraintMatrix(const ConstraintParams* cParams, DataMatrixDeriv1 &c1, DataMatrixDeriv2 &c2, unsigned int &cIndex , const DataVecCoord1 &x1, const DataVecCoord2 &x2) = 0; - - - /// Construction method called by ObjectFactory. - template - static typename T::SPtr create(T* p0, core::objectmodel::BaseContext* context, core::objectmodel::BaseObjectDescription* arg) - { - typename T::SPtr obj = core::behavior::BaseInteractionConstraint::create(p0, context, arg); - - if (arg) - { - obj->parse(arg); - } - - return obj; - } }; #if !defined(SOFA_CORE_BEHAVIOR_MIXEDINTERACTIONCONSTRAINT_CPP) diff --git a/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp b/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp index 29d9abf57d8..dbfc314e00d 100644 --- a/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/ComponentChange.cpp @@ -127,8 +127,6 @@ const std::map > movedComponents = { // SofaBaseUtils was deprecated in #2605 { "AddResourceRepository", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, - { "MakeAliasComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, - { "MakeDataAliasComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, { "MessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, { "FileMessageHandlerComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, { "InfoComponent", Moved("v22.06", "SofaBaseUtils", Sofa.Component.SceneUtility) }, @@ -629,6 +627,12 @@ const std::map > movedComponents = { const std::map > uncreatableComponents = { + /***********************/ + // REMOVED SINCE v25.06 + + { "MakeAliasComponent", Removed("v24.12", "v25.06")}, + { "MakeDataAliasComponent", Removed("v24.12", "v25.06")}, + /***********************/ // REMOVED SINCE v23.06 diff --git a/Sofa/framework/Helper/src/sofa/helper/Utils.cpp b/Sofa/framework/Helper/src/sofa/helper/Utils.cpp index 9bb99fc101c..df91f2af9f5 100644 --- a/Sofa/framework/Helper/src/sofa/helper/Utils.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/Utils.cpp @@ -315,8 +315,8 @@ const std::string& Utils::getSofaUserLocalDirectory() { constexpr std::string_view sofaLocalDirSuffix = "SOFA"; - static std::string sofaLocalDirectory = FileSystem::cleanPath(FileSystem::findOrCreateAValidPath( - FileSystem::append(getUserLocalDirectory(), sofaLocalDirSuffix))); + static const auto sofaLocalDirectory = FileSystem::cleanPath(FileSystem::append(getUserLocalDirectory(), sofaLocalDirSuffix)); + FileSystem::ensureFolderExists(sofaLocalDirectory); return sofaLocalDirectory; } diff --git a/Sofa/framework/Helper/src/sofa/helper/config.h.in b/Sofa/framework/Helper/src/sofa/helper/config.h.in index 2fb09087b39..0d38bd68fa3 100644 --- a/Sofa/framework/Helper/src/sofa/helper/config.h.in +++ b/Sofa/framework/Helper/src/sofa/helper/config.h.in @@ -91,3 +91,11 @@ SOFA_ATTRIBUTE_DISABLED( \ SOFA_ATTRIBUTE_DEPRECATED( \ "v24.12", "v25.06", "This function is now in StringUtils.h") #endif // SOFA_BUILD_SOFA_HELPER + +#ifdef SOFA_BUILD_SOFA_HELPER +#define SOFA_HELPER_FILESYSTEM_FINDORCREATEAVALIDPATH_DEPRECATED() +#else +#define SOFA_HELPER_FILESYSTEM_FINDORCREATEAVALIDPATH_DEPRECATED() \ +SOFA_ATTRIBUTE_DEPRECATED( \ +"v25.06", "v25.12", "It is not clear that this function works on folders or files. Use ensureFolderExists or ensureFolderForFileExists instead.") +#endif // SOFA_BUILD_SOFA_HELPER diff --git a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp index 7e8675e5f27..dc776e08c3c 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp @@ -388,7 +388,28 @@ std::string FileSystem::findOrCreateAValidPath(const std::string path) return path ; } +void FileSystem::ensureFolderExists(const std::string& pathToFolder) +{ + if (!FileSystem::exists(pathToFolder)) + { + const std::string parentPath = FileSystem::getParentDirectory(pathToFolder); + FileSystem::ensureFolderExists(parentPath); + if (FileSystem::exists(parentPath)) + { + FileSystem::createDirectory(pathToFolder); + } + } +} + +void FileSystem::ensureFolderForFileExists(const std::string& pathToFile) +{ + if (!FileSystem::exists(pathToFile)) + { + const std::string parentPath = FileSystem::getParentDirectory(pathToFile); + FileSystem::ensureFolderExists(parentPath); + } +} std::string FileSystem::cleanPath(const std::string& path, separator s) { diff --git a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h index e55c028eaf5..cb0646ee67d 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h +++ b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h @@ -93,12 +93,31 @@ static bool removeDirectory(const std::string& path); /// @return true on error static bool removeAll(const std::string& path) ; +/// @brief The file or empty directory identified by the path is deleted +/// +/// @return true if the file was deleted, false if it did not exist. static bool removeFile(const std::string& path); /// @brief check that all element in the path exists or create them. (This function accepts relative paths) /// /// @return the valid path. -static std::string findOrCreateAValidPath(const std::string path) ; +SOFA_HELPER_FILESYSTEM_FINDORCREATEAVALIDPATH_DEPRECATED() +static std::string findOrCreateAValidPath(const std::string path); + +/// @brief Ensures that a folder exists at the specified path. If the folder does not exist, it will be created. +/// +/// @param pathToFolder The path of the folder to ensure exists. +/// +/// @note The function assumes that a path to a folder is given. +static void ensureFolderExists(const std::string& pathToFolder); + +/// @brief Ensures that the folder containing the specified file path exists. If the folder does not +/// exist, it will be created. If the file does not exist, it will not be created. +/// +/// @param pathToFile The path to the file. The function ensures that the directory containing this file exists. +/// +/// @note The function assumes that a path to a file is given. +static void ensureFolderForFileExists(const std::string& pathToFile); /// @brief Return true if and only if the given file exists. static bool exists(const std::string& path); diff --git a/Sofa/framework/Helper/src/sofa/helper/visual/DrawTool.h b/Sofa/framework/Helper/src/sofa/helper/visual/DrawTool.h index cb0647f038e..c26c675ed01 100644 --- a/Sofa/framework/Helper/src/sofa/helper/visual/DrawTool.h +++ b/Sofa/framework/Helper/src/sofa/helper/visual/DrawTool.h @@ -61,7 +61,8 @@ class SOFA_HELPER_API DrawTool virtual void drawPoints(const std::vector &points, float size, const std::vector& color) = 0; virtual void drawLine(const Vec3 &p1, const Vec3 &p2, const RGBAColor& color) = 0; - virtual void drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const RGBAColor& color) = 0; + virtual void drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const RGBAColor& color, const bool& vanishing=false) = 0; + virtual void drawInfiniteLine(const Vec3 &point, const Vec3 &direction, const float& size, const RGBAColor& color, const bool& vanishing=false) = 0; virtual void drawLines(const std::vector &points, float size, const RGBAColor& color) = 0 ; virtual void drawLines(const std::vector &points, float size, const std::vector& colors) = 0 ; virtual void drawLines(const std::vector &points, const std::vector< Vec2i > &index , float size, const RGBAColor& color) = 0 ; diff --git a/Sofa/framework/Helper/test/system/FileSystem_test.cpp b/Sofa/framework/Helper/test/system/FileSystem_test.cpp index 68c211c8c5b..63881207d00 100644 --- a/Sofa/framework/Helper/test/system/FileSystem_test.cpp +++ b/Sofa/framework/Helper/test/system/FileSystem_test.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -359,3 +360,69 @@ TEST(FileSystemTest, append) EXPECT_EQ(FileSystem::append("a/b/c/d/", "e", "/f", "/g"), "a/b/c/d/e/f/g"); EXPECT_EQ(FileSystem::append("a/b/c/d/", "/e", "/f", "/g"), "a/b/c/d/e/f/g"); } + +TEST(FileSystemTest, ensureFolderExists) +{ + ASSERT_TRUE(FileSystem::isDirectory(sofa::helper::Utils::getSofaPathPrefix())); + + const auto parentDir = FileSystem::append(sofa::helper::Utils::getSofaPathPrefix(), "test_folder"); + const auto dir = FileSystem::append(parentDir, "another_layer"); + + //the folders don't exist yet + EXPECT_FALSE(FileSystem::isDirectory(parentDir)); + EXPECT_FALSE(FileSystem::isDirectory(dir)); + + FileSystem::ensureFolderExists(dir); + + EXPECT_TRUE(FileSystem::isDirectory(parentDir)); + EXPECT_TRUE(FileSystem::isDirectory(dir)); + + //cleanup + EXPECT_FALSE(FileSystem::removeDirectory(dir)); + EXPECT_FALSE(FileSystem::removeDirectory(parentDir)); +} + +TEST(FileSystemTest, ensureFolderForFileExists_fileAndFolderDontExist) +{ + ASSERT_TRUE(FileSystem::isDirectory(sofa::helper::Utils::getSofaPathPrefix())); + + const auto parentDir = FileSystem::append(sofa::helper::Utils::getSofaPathPrefix(), "test_folder"); + const auto dir = FileSystem::append(parentDir, "another_layer"); + + //the folder does not exist yet + EXPECT_FALSE(FileSystem::isDirectory(dir)); + + const auto file = FileSystem::append(dir, "file.txt"); + FileSystem::ensureFolderForFileExists(file); + + EXPECT_TRUE(FileSystem::isDirectory(dir)); + EXPECT_FALSE(FileSystem::isDirectory(file)); + + EXPECT_FALSE(FileSystem::exists(file)); + + //cleanup + EXPECT_FALSE(FileSystem::removeDirectory(dir)); + EXPECT_FALSE(FileSystem::removeDirectory(parentDir)); +} + +TEST(FileSystemTest, ensureFolderForFileExists_fileExist) +{ + ASSERT_TRUE(FileSystem::isDirectory(sofa::helper::Utils::getSofaPathPrefix())); + + const auto file = FileSystem::append(sofa::helper::Utils::getSofaPathPrefix(), "file.txt"); + EXPECT_FALSE(FileSystem::exists(file)); + + std::ofstream fileStream; + fileStream.open(file); + fileStream << "Hello"; + fileStream.close(); + + EXPECT_TRUE(FileSystem::exists(file)); + + FileSystem::ensureFolderForFileExists(file); + + EXPECT_TRUE(FileSystem::exists(file)); + + //cleanup + EXPECT_TRUE(FileSystem::removeFile(file)); +} \ No newline at end of file diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp index f4f2ce91e80..99e6484986b 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/Node.cpp @@ -1024,8 +1024,26 @@ void Node::setSleeping(bool val) } } +template +void checkAlreadyContains(Node& self, LinkType& link, Component* obj) +{ + if constexpr (!LinkType::IsMultiLink) + { + if (link != obj && link != nullptr) + { + static const auto componentClassName = Component::GetClass()->className; + msg_warning(&self) << "Trying to add a " << componentClassName << " ('" + << obj->getName() << "' [" << obj->getClassName() << "] " << obj << ")" + << " into the Node '" << self.getPathName() + << "', whereas it already contains one ('" << link->getName() << "' [" << link->getClassName() << "] " << link.get() << ")." + << " Only one " << componentClassName << " is permitted in a Node. The previous " + << componentClassName << " is replaced and the behavior is undefined."; + } + } +} + #define NODE_DEFINE_SEQUENCE_ACCESSOR( CLASSNAME, FUNCTIONNAME, SEQUENCENAME ) \ - void Node::add##FUNCTIONNAME( CLASSNAME* obj ) { SEQUENCENAME.add(obj); } \ + void Node::add##FUNCTIONNAME( CLASSNAME* obj ) { checkAlreadyContains(*this, SEQUENCENAME, obj); SEQUENCENAME.add(obj); } \ void Node::remove##FUNCTIONNAME( CLASSNAME* obj ) { SEQUENCENAME.remove(obj); } NODE_DEFINE_SEQUENCE_ACCESSOR( sofa::core::behavior::BaseAnimationLoop, AnimationLoop, animationManager ) diff --git a/Sofa/framework/Simulation/Graph/test/Node_test.cpp b/Sofa/framework/Simulation/Graph/test/Node_test.cpp index bb07c4221c1..edb453be83e 100644 --- a/Sofa/framework/Simulation/Graph/test/Node_test.cpp +++ b/Sofa/framework/Simulation/Graph/test/Node_test.cpp @@ -19,6 +19,8 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ +#include +#include #include using sofa::testing::BaseSimulationTest ; @@ -33,6 +35,9 @@ namespace sofa TEST( Node_test, getPathName) { + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + /* create trivial DAG : * * A @@ -90,6 +95,9 @@ TEST(Node_test, addObjectAtFront) TEST(Node_test, addObjectPreventingSharedContext) { + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + const sofa::core::sptr root = sofa::simpleapi::createNode("root"); const BaseObject::SPtr A = core::objectmodel::New("A"); @@ -177,6 +185,53 @@ TEST(Node_test, getObjectsStdUnorderedSet) EXPECT_NE(objects.find(B.get()), objects.end()); } +class CounterVisitor : public simulation::MechanicalVisitor +{ +public: + using MechanicalVisitor::MechanicalVisitor; + + Result fwdMechanicalState(simulation::Node* node, sofa::core::behavior::BaseMechanicalState* state) override + { + SOFA_UNUSED(node); + SOFA_UNUSED(state); + m_counter++; + return Result::RESULT_CONTINUE; + } + + Result fwdMappedMechanicalState(simulation::Node* node, sofa::core::behavior::BaseMechanicalState* state) override + { + SOFA_UNUSED(node); + SOFA_UNUSED(state); + ++m_counter; + return Result::RESULT_CONTINUE; + } + + std::size_t m_counter = 0; +}; + +TEST(Node_test, twoMechanicalStatesInTheSameNode) +{ + // required to be able to use EXPECT_MSG_NOEMIT and EXPECT_MSG_EMIT + sofa::helper::logging::MessageDispatcher::addHandler(sofa::testing::MainGtestMessageHandler::getInstance() ) ; + + const sofa::core::sptr root = sofa::simpleapi::createNode("root"); + + const auto plugins = testing::makeScopedPlugin({Sofa.Component.StateContainer}); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"template", "Vec3"}, {"name", "A"}}); + + EXPECT_MSG_EMIT(Warning); + sofa::simpleapi::createObject(root, "MechanicalObject", {{"template", "Vec3"}, {"name", "B"}}); + + //the last added state is the one in Node + EXPECT_EQ(root->mechanicalState->getName(), "B"); + + CounterVisitor visitor(core::MechanicalParams::defaultInstance()); + root->executeVisitor(&visitor); + + //only one of the two added states is visited + EXPECT_EQ(visitor.m_counter, 1); +} + }// namespace sofa diff --git a/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp b/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp index 53507e22024..8fad0b75081 100644 --- a/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp +++ b/Sofa/framework/Simulation/Graph/test/Simulation_test.cpp @@ -223,10 +223,9 @@ struct Scene_test: public NumericTest root = simulation::getSimulation()->createNewGraph("root"); root->addObject(core::objectmodel::New >()); - typename UniformMass3::SPtr uniformMass = core::objectmodel::New(); + typename UniformMass3::SPtr uniformMass = core::objectmodel::New>(); uniformMass->d_totalMass.setValue(1.0); root->addObject(uniformMass); - root->addObject(core::objectmodel::New >()); const simulation::Node::SPtr child = simulation::getSimulation()->createNewNode("child"); root->addChild(child); diff --git a/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.h b/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.h index 18b2d8e9eb8..ecffebb8269 100644 --- a/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.h +++ b/applications/plugins/MultiThreading/src/MultiThreading/component/animationloop/AnimationLoopParallelScheduler.h @@ -76,17 +76,6 @@ class SOFA_MULTITHREADING_PLUGIN_API AnimationLoopParallelScheduler : void step(const sofa::core::ExecParams* params, SReal dt) override; - /// Construction method called by ObjectFactory. - template - static typename T::SPtr create(T*, sofa::core::objectmodel::BaseContext* context, sofa::core::objectmodel::BaseObjectDescription* arg) - { - sofa::simulation::Node* gnode = dynamic_cast(context); - typename T::SPtr obj = sofa::core::objectmodel::New(gnode); - if (context) context->addObject(obj); - if (arg) obj->parse(arg); - return obj; - } - private : sofa::simulation::Node* gnode; diff --git a/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu b/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu index 0617c7ee550..8c55d4fdb56 100644 --- a/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu +++ b/applications/plugins/SofaCUDA/sofa/gpu/cuda/mycuda.cu @@ -32,6 +32,11 @@ cudaDeviceProp mycudaDeviceProp; #if defined(__cplusplus) + +#define STRINGIFY(x) #x +#define _STR(x) STRINGIFY(x) +SOFA_PRAGMA_MESSAGE("__cplusplus value: " _STR(__cplusplus)) + namespace sofa { namespace gpu @@ -57,9 +62,28 @@ bool cudaCheck(cudaError_t err, const char* src="?") bool cudaInitCalled = false; int deviceCount = 0; +#ifdef SOFA_WITH_DEVTOOLS +__global__ void print_cuda_standard() +{ + /** + * 199711L = C++98 + * 201103L = C++11 + * 201402L = C++14 + * 201703L = C++17 + * 202002L = C++20 + */ + printf("CUDA Standard: %ld\n", __cplusplus); +} +#endif + int mycudaInit(int device) { if (cudaInitCalled) return 1; + +#if defined(__cplusplus) + mycudaPrintf("C++ standard = %ld", __cplusplus); +#endif + cudaInitCalled = true; const cudaError_t getDeviceCountError = cudaGetDeviceCount(&deviceCount); if (getDeviceCountError != cudaSuccess) @@ -121,6 +145,12 @@ int mycudaInit(int device) #if defined(SOFA_GPU_CUBLAS) && !defined(SOFA_GPU_CUBLAS_V2) cublasInit(); #endif + +#ifdef SOFA_WITH_DEVTOOLS + print_cuda_standard<<<1, 1>>>(); + cudaCheck(cudaDeviceSynchronize()); +#endif + return 1; } diff --git a/applications/projects/CMakeLists.txt b/applications/projects/CMakeLists.txt index 0c85f91879a..01009d74d45 100644 --- a/applications/projects/CMakeLists.txt +++ b/applications/projects/CMakeLists.txt @@ -10,10 +10,11 @@ sofa_add_subdirectory(application GenerateRigid GenerateRigid) sofa_add_subdirectory(application SofaPhysicsAPI SofaPhysicsAPI) sofa_add_subdirectory(application SofaGuiGlut SofaGuiGlut OFF) +sofa_add_subdirectory(directory SofaGLFW SofaGLFW EXTERNAL GIT_REF master ON) +sofa_add_subdirectory(plugin Sofa.Qt Sofa.Qt EXTERNAL GIT_REF master OFF) sofa_add_subdirectory(application runSofa runSofa ON) sofa_add_subdirectory(application sofaOPENCL sofaOPENCL OFF) sofa_add_subdirectory(directory Regression Regression EXTERNAL GIT_REF master) -sofa_add_subdirectory(directory SofaGLFW SofaGLFW EXTERNAL GIT_REF master) sofa_add_subdirectory(application sofaProjectExample sofaProjectExample) sofa_add_subdirectory(application sofaInfo sofaInfo) diff --git a/applications/projects/SceneChecking/CMakeLists.txt b/applications/projects/SceneChecking/CMakeLists.txt index a4c688e7f27..3ed18e84519 100644 --- a/applications/projects/SceneChecking/CMakeLists.txt +++ b/applications/projects/SceneChecking/CMakeLists.txt @@ -16,6 +16,7 @@ set(HEADER_FILES ${SCENECHECK_SRC_DIR}/SceneCheckCollisionResponse.h ${SCENECHECK_SRC_DIR}/SceneCheckDeprecatedComponents.h ${SCENECHECK_SRC_DIR}/SceneCheckDuplicatedName.h + ${SCENECHECK_SRC_DIR}/SceneCheckEmptyNodeName.h ${SCENECHECK_SRC_DIR}/SceneCheckMissingRequiredPlugin.h ${SCENECHECK_SRC_DIR}/SceneCheckUsingAlias.h ${SCENECHECK_SRC_DIR}/SceneCheckerListener.h @@ -28,6 +29,7 @@ set(SOURCE_FILES ${SCENECHECK_SRC_DIR}/SceneCheckCollisionResponse.cpp ${SCENECHECK_SRC_DIR}/SceneCheckDeprecatedComponents.cpp ${SCENECHECK_SRC_DIR}/SceneCheckDuplicatedName.cpp + ${SCENECHECK_SRC_DIR}/SceneCheckEmptyNodeName.cpp ${SCENECHECK_SRC_DIR}/SceneCheckMissingRequiredPlugin.cpp ${SCENECHECK_SRC_DIR}/SceneCheckUsingAlias.cpp ${SCENECHECK_SRC_DIR}/SceneCheckerListener.cpp diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.cpp b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.cpp similarity index 59% rename from Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.cpp rename to applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.cpp index 853c5fcc15d..96eaa647c59 100644 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.cpp +++ b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.cpp @@ -19,32 +19,39 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include -#include -#include +#include -void sofa::gui::qt::redirectQtMessages(QtMsgType type, - const QMessageLogContext& context, - const QString& msg) +#include +#include + +namespace sofa::scenechecking { - SOFA_UNUSED(context); - const QByteArray localMsg = msg.toLocal8Bit(); - switch (type) + +const bool SceneCheckEmptyNodeNameRegistered = sofa::simulation::SceneCheckMainRegistry::addToRegistry(SceneCheckEmptyNodeName::newSPtr()); + +SceneCheckEmptyNodeName::~SceneCheckEmptyNodeName() {} +const std::string SceneCheckEmptyNodeName::getName() { return "SceneCheckEmptyNodeName"; } +const std::string SceneCheckEmptyNodeName::getDesc() { return "Check if a Node has an empty name."; } + +void SceneCheckEmptyNodeName::doInit(sofa::simulation::Node* node) +{ + m_nbNodesWithEmptyName = 0; +} + +void SceneCheckEmptyNodeName::doCheckOn(sofa::simulation::Node* node) +{ + const auto& nodeName = node->getName(); + + if (nodeName.empty()) { - case QtDebugMsg: - msg_info("Qt") << localMsg.constData(); - break; - case QtInfoMsg: - msg_info("Qt") << localMsg.constData(); - break; - case QtWarningMsg: - msg_warning("Qt") << localMsg.constData(); - break; - case QtCriticalMsg: - msg_error("Qt") << localMsg.constData(); - break; - case QtFatalMsg: - msg_fatal("Qt") << localMsg.constData(); - break; + ++m_nbNodesWithEmptyName; } } + +void SceneCheckEmptyNodeName::doPrintSummary() +{ + msg_warning_when(m_nbNodesWithEmptyName > 0, getName()) << "Nodes with empty name are found in" + " the scene. This can lead to undefined behaviors. It is recommended to give a name to all Nodes."; +} + +} // namespace sofa::scenechecking \ No newline at end of file diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.h b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.h similarity index 71% rename from Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.h rename to applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.h index b763e6d7cdf..f002974e191 100644 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QtMessageRedirection.h +++ b/applications/projects/SceneChecking/src/SceneChecking/SceneCheckEmptyNodeName.h @@ -21,9 +21,26 @@ ******************************************************************************/ #pragma once -#include +#include +#include -namespace sofa::gui::qt +namespace sofa::scenechecking { -void redirectQtMessages(QtMsgType type, const QMessageLogContext& context, const QString& msg); + +class SOFA_SCENECHECKING_API SceneCheckEmptyNodeName : public sofa::simulation::SceneCheck +{ +public: + ~SceneCheckEmptyNodeName() override; + typedef std::shared_ptr SPtr; + static SPtr newSPtr() { return std::make_shared(); } + const std::string getName() override; + const std::string getDesc() override; + void doInit(sofa::simulation::Node* node) override; + void doCheckOn(sofa::simulation::Node* node) override; + void doPrintSummary() override; + +private: + unsigned int m_nbNodesWithEmptyName = 0; +}; + } diff --git a/applications/projects/Sofa.Qt/ExternalProjectConfig.cmake.in b/applications/projects/Sofa.Qt/ExternalProjectConfig.cmake.in new file mode 100644 index 00000000000..a142386d33f --- /dev/null +++ b/applications/projects/Sofa.Qt/ExternalProjectConfig.cmake.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.2) + +include(ExternalProject) +ExternalProject_Add(Regression + GIT_REPOSITORY https://github.com/sofa-framework/Sofa.Qt + GIT_TAG origin/@ARG_GIT_REF@ + SOURCE_DIR "${CMAKE_SOURCE_DIR}/applications/projects/Sofa.Qt" + BINARY_DIR "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + GIT_CONFIG "remote.origin.fetch=+refs/pull/*:refs/remotes/origin/pr/*" +) + \ No newline at end of file diff --git a/applications/projects/runSofa/Main.cpp b/applications/projects/runSofa/Main.cpp index 8cea20e57d1..92f2683ee39 100644 --- a/applications/projects/runSofa/Main.cpp +++ b/applications/projects/runSofa/Main.cpp @@ -78,9 +78,8 @@ using sofa::helper::logging::RichConsoleStyleMessageFormatter ; using sofa::helper::logging::MainPerComponentLoggingMessageHandler ; #include +#include -#include -using sofa::gui::common::GuiDataRepository ; using sofa::helper::system::DataRepository; using sofa::helper::system::PluginRepository; @@ -115,18 +114,17 @@ static std::string appName { "runSofa" }; // --------------------------------------------------------------------- int main(int argc, char** argv) { - // Add resources dir to GuiDataRepository - const std::string runSofaIniFilePath = Utils::getSofaPathTo("/etc/runSofa.ini"); - std::map iniFileValues = Utils::readBasicIniFile(runSofaIniFilePath); - if (iniFileValues.contains("RESOURCES_DIR")) - { - std::string dir = iniFileValues["RESOURCES_DIR"]; - dir = SetDirectory::GetRelativeFromProcess(dir.c_str()); - if(FileSystem::isDirectory(dir)) - { - sofa::gui::common::GuiDataRepository.addFirstPath(dir); - } - } + + sofa::helper::system::FileRepository runSofaDataRepository( + "RUNSOFA_DATA_PATH", + { + Utils::getSofaPathTo("share/sofa/gui/runSofa") + }, + { + { Utils::getSofaPathTo("etc/runSofa.ini").c_str(), {"RESOURCES_DIR"} } + } + ); + sofa::helper::BackTrace::autodump(); @@ -371,7 +369,7 @@ int main(int argc, char** argv) // Output FileRepositories msg_info(appName) << "PluginRepository paths = " << PluginRepository.getPathsJoined(); msg_info(appName) << "DataRepository paths = " << DataRepository.getPathsJoined(); - msg_info(appName) << "GuiDataRepository paths = " << GuiDataRepository.getPathsJoined(); + msg_info(appName) << "runSofaDataRepository paths = " << runSofaDataRepository.getPathsJoined(); // Initialise paths BaseGUI::setConfigDirectoryPath(Utils::getSofaPathPrefix() + "/config", true); diff --git a/examples/Component/ODESolver/Backward/EulerImplicitSolver.scn b/examples/Component/ODESolver/Backward/EulerImplicitSolver.scn index bb30a06a950..44eb6604a32 100644 --- a/examples/Component/ODESolver/Backward/EulerImplicitSolver.scn +++ b/examples/Component/ODESolver/Backward/EulerImplicitSolver.scn @@ -13,7 +13,7 @@ - + diff --git a/examples/Component/SceneUtility/MakeAlias.scn b/examples/Component/SceneUtility/MakeAlias.scn deleted file mode 100644 index 6c0519524f4..00000000000 --- a/examples/Component/SceneUtility/MakeAlias.scn +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/examples/Component/SceneUtility/MakeDataAlias.scn b/examples/Component/SceneUtility/MakeDataAlias.scn deleted file mode 100644 index d6e7f09d15c..00000000000 --- a/examples/Component/SceneUtility/MakeDataAlias.scn +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/tools/postinstall-fixup/CMakeLists.txt b/tools/postinstall-fixup/CMakeLists.txt index 702c896b108..5c90cd7509a 100644 --- a/tools/postinstall-fixup/CMakeLists.txt +++ b/tools/postinstall-fixup/CMakeLists.txt @@ -3,19 +3,21 @@ if(NOT SOFA_BUILD_RELEASE_PACKAGE) return() endif() -find_package(Qt5 COMPONENTS Gui REQUIRED) -get_target_property(qt5gui_loc Qt5::Gui LOCATION_RELEASE) -get_filename_component(QT_LIB_DIR "${qt5gui_loc}" DIRECTORY) -if(QT_LIB_DIR MATCHES "\.framework$") - get_filename_component(QT_LIB_DIR "${QT_LIB_DIR}" DIRECTORY) -endif() -get_target_property(qjpeg_loc Qt5::QJpegPlugin LOCATION_RELEASE) -get_filename_component(imageformats_dir "${qjpeg_loc}" DIRECTORY) -get_filename_component(plugins_dir "${imageformats_dir}" DIRECTORY) -get_filename_component(QT_DATA_DIR "${plugins_dir}" DIRECTORY) +if(TARGET Sofa.GUI.Qt) + find_package(Qt5 COMPONENTS Gui REQUIRED) + get_target_property(qt5gui_loc Qt5::Gui LOCATION_RELEASE) + get_filename_component(QT_LIB_DIR "${qt5gui_loc}" DIRECTORY) + if(QT_LIB_DIR MATCHES "\.framework$") + get_filename_component(QT_LIB_DIR "${QT_LIB_DIR}" DIRECTORY) + endif() + get_target_property(qjpeg_loc Qt5::QJpegPlugin LOCATION_RELEASE) + get_filename_component(imageformats_dir "${qjpeg_loc}" DIRECTORY) + get_filename_component(plugins_dir "${imageformats_dir}" DIRECTORY) + get_filename_component(QT_DATA_DIR "${plugins_dir}" DIRECTORY) -message("QT_LIB_DIR = ${QT_LIB_DIR}") -message("QT_DATA_DIR = ${QT_DATA_DIR}") + message("QT_LIB_DIR = ${QT_LIB_DIR}") + message("QT_DATA_DIR = ${QT_DATA_DIR}") +endif() if(CMAKE_SYSTEM_NAME STREQUAL Linux) install(CODE "file(WRITE @@ -34,7 +36,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux) COMPONENT resources) elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) if(SOFA_BUILD_APP_BUNDLE) - include(macdeployqt) # set MACDEPLOYQT_EXECUTABLE + if(TARGET Sofa.GUI.Qt) + include(macdeployqt) # set MACDEPLOYQT_EXECUTABLE + endif() install(CODE "execute_process(COMMAND /bin/bash \"${CMAKE_CURRENT_LIST_DIR}/macos-postinstall-fixup.sh\" \"${CMAKE_CURRENT_LIST_DIR}\" diff --git a/tools/postinstall-fixup/linux-postinstall-fixup.sh b/tools/postinstall-fixup/linux-postinstall-fixup.sh index f90ce9cb9fc..f9bfa7c5fec 100644 --- a/tools/postinstall-fixup/linux-postinstall-fixup.sh +++ b/tools/postinstall-fixup/linux-postinstall-fixup.sh @@ -4,12 +4,17 @@ usage() { echo "Usage: linux-postinstall-fixup.sh [qt-lib-dir] [qt-data-dir]" } -if [ "$#" -ge 2 ]; then +if [ "$#" -ge 3 ]; then SCRIPT_DIR="$(cd $1 && pwd)" BUILD_DIR="$(cd $2 && pwd)" INSTALL_DIR="$(cd $3 && pwd)" - QT_LIB_DIR="$4" - QT_DATA_DIR="$5" + if [ "$#" -ge 4 ]; then + QT_LIB_DIR="$4" + QT_DATA_DIR="$5" + SHIP_QT=1 + else + SHIP_QT=0 + fi else usage; exit 1 fi @@ -39,35 +44,38 @@ rm -rf "$INSTALL_DIR/plugins/platforms" rm -rf "$INSTALL_DIR/plugins/styles" rm -rf "$INSTALL_DIR/plugins/xcbglintegrations" -QT_PLUGINS_DIR="$QT_DATA_DIR/plugins" -QT_LIBEXEC_DIR="$QT_DATA_DIR/libexec" -if [[ "$QT_LIB_DIR" == "/usr/lib"* ]]; then - QT_WEBENGINE_DATA_DIR="/usr/share/qt5/resources" -else - QT_WEBENGINE_DATA_DIR="$QT_DATA_DIR" +if [ "$SHIP_QT" = "1" ]; then + QT_PLUGINS_DIR="$QT_DATA_DIR/plugins" + QT_LIBEXEC_DIR="$QT_DATA_DIR/libexec" + if [[ "$QT_LIB_DIR" == "/usr/lib"* ]]; then + QT_WEBENGINE_DATA_DIR="/usr/share/qt5/resources" + else + QT_WEBENGINE_DATA_DIR="$QT_DATA_DIR" + fi + + echo "QT_LIB_DIR = $QT_LIB_DIR" + echo "QT_DATA_DIR = $QT_DATA_DIR" + echo "QT_PLUGINS_DIR = $QT_PLUGINS_DIR" + echo "QT_LIBEXEC_DIR = $QT_LIBEXEC_DIR" + echo "QT_WEBENGINE_DATA_DIR = $QT_WEBENGINE_DATA_DIR" + + if [ -d "$QT_PLUGINS_DIR/iconengines" ]; then + cp -R "$QT_PLUGINS_DIR/iconengines" "$INSTALL_DIR/bin" + fi + if [ -d "$QT_PLUGINS_DIR/imageformats" ]; then + cp -R "$QT_PLUGINS_DIR/imageformats" "$INSTALL_DIR/bin" + fi + if [ -d "$QT_PLUGINS_DIR/platforms" ]; then + cp -R "$QT_PLUGINS_DIR/platforms" "$INSTALL_DIR/bin" + fi + if [ -d "$QT_PLUGINS_DIR/styles" ]; then + cp -R "$QT_PLUGINS_DIR/styles" "$INSTALL_DIR/bin" + fi + if [ -d "$QT_PLUGINS_DIR/xcbglintegrations" ]; then + cp -R "$QT_PLUGINS_DIR/xcbglintegrations" "$INSTALL_DIR/bin" + fi fi -echo "QT_LIB_DIR = $QT_LIB_DIR" -echo "QT_DATA_DIR = $QT_DATA_DIR" -echo "QT_PLUGINS_DIR = $QT_PLUGINS_DIR" -echo "QT_LIBEXEC_DIR = $QT_LIBEXEC_DIR" -echo "QT_WEBENGINE_DATA_DIR = $QT_WEBENGINE_DATA_DIR" - -if [ -d "$QT_PLUGINS_DIR/iconengines" ]; then - cp -R "$QT_PLUGINS_DIR/iconengines" "$INSTALL_DIR/bin" -fi -if [ -d "$QT_PLUGINS_DIR/imageformats" ]; then - cp -R "$QT_PLUGINS_DIR/imageformats" "$INSTALL_DIR/bin" -fi -if [ -d "$QT_PLUGINS_DIR/platforms" ]; then - cp -R "$QT_PLUGINS_DIR/platforms" "$INSTALL_DIR/bin" -fi -if [ -d "$QT_PLUGINS_DIR/styles" ]; then - cp -R "$QT_PLUGINS_DIR/styles" "$INSTALL_DIR/bin" -fi -if [ -d "$QT_PLUGINS_DIR/xcbglintegrations" ]; then - cp -R "$QT_PLUGINS_DIR/xcbglintegrations" "$INSTALL_DIR/bin" -fi echo_debug() { if [ -n "$DEBUG" ] && [ "$DEBUG" -gt 0 ]; then @@ -169,7 +177,7 @@ for deps_file in postinstall_deps_SOFA.tmp postinstall_deps_plugin_*.tmp; do continue fi # take first path found for the dep lib (paths are sorted so "/a/b/c" comes before "not found") - if [[ "$group" == "libQt" ]] && [ -e "$QT_LIB_DIR/$lib_name" ]; then + if [[ "$group" == "libQt" ]] && [ "$SHIP_QT" = "1" ] && [ -e "$QT_LIB_DIR/$lib_name" ]; then lib_path="$QT_LIB_DIR/$lib_name" else lib_path="$(cat $deps_file | grep "${lib_name} =>" | sed -e 's/.* => //g' | sort | uniq | head -n 1)" @@ -196,7 +204,7 @@ done move_metis "$INSTALL_DIR" # Add QtWebEngine dependencies -if [ -e "$INSTALL_DIR/lib/libQt5WebEngineCore.so.5" ] && [ -d "$QT_LIBEXEC_DIR" ] && [ -d "$QT_WEBENGINE_DATA_DIR" ]; then +if [ "$SHIP_QT" = "1" ] && [ -e "$INSTALL_DIR/lib/libQt5WebEngineCore.so.5" ] && [ -d "$QT_LIBEXEC_DIR" ] && [ -d "$QT_WEBENGINE_DATA_DIR" ]; then cp "$QT_LIBEXEC_DIR/QtWebEngineProcess" "$INSTALL_DIR/bin" # not in INSTALL_DIR/libexec ; see our custom bin/qt.conf mkdir "$INSTALL_DIR/translations" cp -R "$QT_WEBENGINE_DATA_DIR/translations/qtwebengine_locales" "$INSTALL_DIR/translations" diff --git a/tools/postinstall-fixup/macos-postinstall-fixup.sh b/tools/postinstall-fixup/macos-postinstall-fixup.sh index 329be2877c7..e7eac7c0bd5 100644 --- a/tools/postinstall-fixup/macos-postinstall-fixup.sh +++ b/tools/postinstall-fixup/macos-postinstall-fixup.sh @@ -8,9 +8,15 @@ usage() { if [ "$#" -ge 1 ]; then SCRIPT_DIR="$(cd $1 && pwd)" INSTALL_DIR="$(cd $2 && pwd)" - QT_LIB_DIR="$3" - QT_DATA_DIR="$4" - MACDEPLOYQT_EXE="$5" + + if [ "$#" -ge 3 ]; then + QT_LIB_DIR="$3" + QT_DATA_DIR="$4" + MACDEPLOYQT_EXE="$5" + SHIP_QT=1 + else + SHIP_QT=0 + fi else usage; exit 1 fi @@ -39,18 +45,20 @@ if [ -e "$INSTALL_DIR/runSofa" ]; then mv -f $INSTALL_DIR/runSofa* $INSTALL_DIR/bin/ fi -if [ -d "$BUNDLE_DIR" ] && [ -e "$MACDEPLOYQT_EXE" ]; then - echo "Fixing up libs with MacDeployQt ..." - $MACDEPLOYQT_EXE $BUNDLE_DIR -always-overwrite +if [ "$SHIP_QT" = "1" ]; then + if [ -d "$BUNDLE_DIR" ] && [ -e "$MACDEPLOYQT_EXE" ]; then + echo "Fixing up libs with MacDeployQt ..." + $MACDEPLOYQT_EXE $BUNDLE_DIR -always-overwrite - cp -R $BUNDLE_DIR/Contents/PlugIns/* $BUNDLE_DIR/Contents/MacOS/bin && rm -rf $BUNDLE_DIR/Contents/PlugIns + cp -R $BUNDLE_DIR/Contents/PlugIns/* $BUNDLE_DIR/Contents/MacOS/bin && rm -rf $BUNDLE_DIR/Contents/PlugIns - printf "[Paths] \n Plugins = MacOS/bin \n" > $BUNDLE_DIR/Contents/Resources/qt.conf -elif [ -d "$QT_DATA_DIR" ]; then - cp -Rf $QT_DATA_DIR/plugins/iconengines $INSTALL_DIR/bin - cp -Rf $QT_DATA_DIR/plugins/imageformats $INSTALL_DIR/bin - cp -Rf $QT_DATA_DIR/plugins/platforms $INSTALL_DIR/bin - cp -Rf $QT_DATA_DIR/plugins/styles $INSTALL_DIR/bin + printf "[Paths] \n Plugins = MacOS/bin \n" > $BUNDLE_DIR/Contents/Resources/qt.conf + elif [ -d "$QT_DATA_DIR" ]; then + cp -Rf $QT_DATA_DIR/plugins/iconengines $INSTALL_DIR/bin + cp -Rf $QT_DATA_DIR/plugins/imageformats $INSTALL_DIR/bin + cp -Rf $QT_DATA_DIR/plugins/platforms $INSTALL_DIR/bin + cp -Rf $QT_DATA_DIR/plugins/styles $INSTALL_DIR/bin + fi fi move_metis "$INSTALL_DIR" From bb78caf28cfefa649f2ea9c7b503ce62e3c5cbdf Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Fri, 28 Feb 2025 16:56:50 +0100 Subject: [PATCH 16/21] Fix compilaiton --- .../solidmechanics/spring/RestShapeSpringsForceField.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h index a073c3f1671..e59ae0b6584 100644 --- a/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h +++ b/Sofa/Component/SolidMechanics/Spring/src/sofa/component/solidmechanics/spring/RestShapeSpringsForceField.h @@ -89,7 +89,7 @@ protected : virtual const DataVecCoord* getExtPosition() const override; virtual const VecIndex& getExtIndices() const override; - virtual const type::fixed_array& getActiveDirections() const override; + virtual const type::fixed_array& getActiveDirections() const override; virtual bool checkOutOfBoundsIndices(); From ab240255a393edcc45cd14c9df22d472f7218c79 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 4 Mar 2025 17:35:10 +0100 Subject: [PATCH 17/21] Use FixedWeakConstraint when possible --- .../examples/ArticulatedArm/robot.py | 2 +- applications/plugins/Haption/examples/haption1.scn | 2 +- applications/plugins/Haption/examples/temp1.scn | 2 +- applications/plugins/LeapMotion/examples/buffoon.scn | 4 ++-- .../PersistentContact/examples/instrument.xml | 4 ++-- .../PersistentContact/examples/instrument2.xml | 4 ++-- .../plugins/Sensable/examples/Old Examples/omni1.scn | 2 +- .../plugins/Sensable/examples/Old Examples/omni2.scn | 2 +- .../plugins/Sensable/examples/SimpleBox-Method2.scn | 2 +- applications/plugins/SofaHAPI/examples/SofaHAPI1.scn | 2 +- applications/plugins/Xitact/examples/1xitact.scn | 2 +- applications/plugins/Xitact/examples/2xitact2.scn | 2 +- .../plugins/Xitact/examples/XitactGrasping.scn | 4 ++-- .../examples/XitactGraspingWithForceFeedBack.scn | 4 ++-- .../Xitact/examples/XitactGrasping_coupledModel.scn | 8 ++++---- .../examples/XitactGrasping_coupledModel_withITP.scn | 12 ++++++------ applications/plugins/Xitact/examples/xitactTest.scn | 4 ++-- .../LinearSystem/PendulumSpringsDistanceMapping.scn | 4 ++-- examples/Component/Mapping/NonLinear/AreaMapping.scn | 2 +- .../Mapping/NonLinear/DistanceFromTargetMapping.scn | 4 ++-- .../Component/Mapping/NonLinear/DistanceMapping.scn | 2 +- .../Mapping/NonLinear/DistanceMultiMapping.scn | 6 +++--- .../Mapping/NonLinear/SquareDistanceMapping.scn | 2 +- .../Component/Mapping/NonLinear/SquareMapping.scn | 4 ++-- .../Component/Mapping/NonLinear/VolumeMapping.scn | 2 +- .../Spring/RestShapeSpringsForceField.scn | 8 ++++---- 26 files changed, 48 insertions(+), 48 deletions(-) diff --git a/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py b/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py index 8b72a19be18..58bba66308e 100644 --- a/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py +++ b/applications/plugins/ArticulatedSystemPlugin/examples/ArticulatedArm/robot.py @@ -88,7 +88,7 @@ def addRobot(self, name='Robot', translation=[0,0,0]): articulations.addObject('MechanicalObject', name='dofs', template='Vec1', rest_position=robot.getData('angles').getLinkPath(), position=initAngles) articulations.addObject('ArticulatedHierarchyContainer') articulations.addObject('UniformMass', totalMass=1) - articulations.addObject('RestShapeSpringsForceField', stiffness=1e10, indices=list(range(6))) + articulations.addObject('FixedWeakConstraint', stiffness=1e10, indices=list(range(6))) # Rigid rigid = articulations.addChild('Rigid') diff --git a/applications/plugins/Haption/examples/haption1.scn b/applications/plugins/Haption/examples/haption1.scn index 528622522c0..cd168bced0b 100644 --- a/applications/plugins/Haption/examples/haption1.scn +++ b/applications/plugins/Haption/examples/haption1.scn @@ -19,7 +19,7 @@ - + diff --git a/applications/plugins/Haption/examples/temp1.scn b/applications/plugins/Haption/examples/temp1.scn index 359a4a7df86..283c546062d 100644 --- a/applications/plugins/Haption/examples/temp1.scn +++ b/applications/plugins/Haption/examples/temp1.scn @@ -19,7 +19,7 @@ - + diff --git a/applications/plugins/LeapMotion/examples/buffoon.scn b/applications/plugins/LeapMotion/examples/buffoon.scn index 5e9cbdc251e..b9d50754101 100644 --- a/applications/plugins/LeapMotion/examples/buffoon.scn +++ b/applications/plugins/LeapMotion/examples/buffoon.scn @@ -36,7 +36,7 @@ - + @@ -47,7 +47,7 @@ - + diff --git a/applications/plugins/PersistentContact/examples/instrument.xml b/applications/plugins/PersistentContact/examples/instrument.xml index 551bf782cde..726c970e297 100644 --- a/applications/plugins/PersistentContact/examples/instrument.xml +++ b/applications/plugins/PersistentContact/examples/instrument.xml @@ -5,12 +5,12 @@ - + - + diff --git a/applications/plugins/PersistentContact/examples/instrument2.xml b/applications/plugins/PersistentContact/examples/instrument2.xml index f6a6e04273c..11899fa0f82 100644 --- a/applications/plugins/PersistentContact/examples/instrument2.xml +++ b/applications/plugins/PersistentContact/examples/instrument2.xml @@ -5,12 +5,12 @@ - + - + diff --git a/applications/plugins/Sensable/examples/Old Examples/omni1.scn b/applications/plugins/Sensable/examples/Old Examples/omni1.scn index b635978b532..49f057225ac 100644 --- a/applications/plugins/Sensable/examples/Old Examples/omni1.scn +++ b/applications/plugins/Sensable/examples/Old Examples/omni1.scn @@ -20,7 +20,7 @@ - + diff --git a/applications/plugins/Sensable/examples/Old Examples/omni2.scn b/applications/plugins/Sensable/examples/Old Examples/omni2.scn index 4e19ad2b2a7..68f6cc7c630 100644 --- a/applications/plugins/Sensable/examples/Old Examples/omni2.scn +++ b/applications/plugins/Sensable/examples/Old Examples/omni2.scn @@ -15,7 +15,7 @@ - + diff --git a/applications/plugins/Sensable/examples/SimpleBox-Method2.scn b/applications/plugins/Sensable/examples/SimpleBox-Method2.scn index f9d5c362f91..d346e314a41 100644 --- a/applications/plugins/Sensable/examples/SimpleBox-Method2.scn +++ b/applications/plugins/Sensable/examples/SimpleBox-Method2.scn @@ -51,7 +51,7 @@ - + diff --git a/applications/plugins/SofaHAPI/examples/SofaHAPI1.scn b/applications/plugins/SofaHAPI/examples/SofaHAPI1.scn index ef2c5275e58..7cc6c7c1e0b 100644 --- a/applications/plugins/SofaHAPI/examples/SofaHAPI1.scn +++ b/applications/plugins/SofaHAPI/examples/SofaHAPI1.scn @@ -51,7 +51,7 @@ - + diff --git a/applications/plugins/Xitact/examples/1xitact.scn b/applications/plugins/Xitact/examples/1xitact.scn index 338be5d68d8..95974f073d8 100644 --- a/applications/plugins/Xitact/examples/1xitact.scn +++ b/applications/plugins/Xitact/examples/1xitact.scn @@ -14,7 +14,7 @@ - + diff --git a/applications/plugins/Xitact/examples/2xitact2.scn b/applications/plugins/Xitact/examples/2xitact2.scn index 4f62edbbb67..6e71be55a05 100644 --- a/applications/plugins/Xitact/examples/2xitact2.scn +++ b/applications/plugins/Xitact/examples/2xitact2.scn @@ -15,7 +15,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping.scn b/applications/plugins/Xitact/examples/XitactGrasping.scn index 228bf45a0c6..57c2e91115b 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn b/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn index 7a15d6ce5ff..388b97b5b10 100644 --- a/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn +++ b/applications/plugins/Xitact/examples/XitactGraspingWithForceFeedBack.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn index a08c6f561d8..284885d1dfe 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -221,7 +221,7 @@ - + diff --git a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn index bf57c1fb18c..0e625b3584b 100644 --- a/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn +++ b/applications/plugins/Xitact/examples/XitactGrasping_coupledModel_withITP.scn @@ -85,7 +85,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -221,7 +221,7 @@ - + @@ -319,7 +319,7 @@ - + @@ -338,7 +338,7 @@ - + diff --git a/applications/plugins/Xitact/examples/xitactTest.scn b/applications/plugins/Xitact/examples/xitactTest.scn index 88bad4d4613..1783aa68326 100644 --- a/applications/plugins/Xitact/examples/xitactTest.scn +++ b/applications/plugins/Xitact/examples/xitactTest.scn @@ -17,7 +17,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/examples/Component/LinearSystem/PendulumSpringsDistanceMapping.scn b/examples/Component/LinearSystem/PendulumSpringsDistanceMapping.scn index 1f63bdf6863..4c36ac10a17 100644 --- a/examples/Component/LinearSystem/PendulumSpringsDistanceMapping.scn +++ b/examples/Component/LinearSystem/PendulumSpringsDistanceMapping.scn @@ -41,7 +41,7 @@ - + @@ -65,7 +65,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/AreaMapping.scn b/examples/Component/Mapping/NonLinear/AreaMapping.scn index 98365cc1d55..7c7562c6338 100644 --- a/examples/Component/Mapping/NonLinear/AreaMapping.scn +++ b/examples/Component/Mapping/NonLinear/AreaMapping.scn @@ -45,7 +45,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/DistanceFromTargetMapping.scn b/examples/Component/Mapping/NonLinear/DistanceFromTargetMapping.scn index f899824f573..2f1d251b5c3 100644 --- a/examples/Component/Mapping/NonLinear/DistanceFromTargetMapping.scn +++ b/examples/Component/Mapping/NonLinear/DistanceFromTargetMapping.scn @@ -24,11 +24,11 @@ - + - + diff --git a/examples/Component/Mapping/NonLinear/DistanceMapping.scn b/examples/Component/Mapping/NonLinear/DistanceMapping.scn index f59c162005c..1c2441eaf27 100644 --- a/examples/Component/Mapping/NonLinear/DistanceMapping.scn +++ b/examples/Component/Mapping/NonLinear/DistanceMapping.scn @@ -31,7 +31,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/DistanceMultiMapping.scn b/examples/Component/Mapping/NonLinear/DistanceMultiMapping.scn index 5b5e072928a..f0023598332 100644 --- a/examples/Component/Mapping/NonLinear/DistanceMultiMapping.scn +++ b/examples/Component/Mapping/NonLinear/DistanceMultiMapping.scn @@ -37,7 +37,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -61,7 +61,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/SquareDistanceMapping.scn b/examples/Component/Mapping/NonLinear/SquareDistanceMapping.scn index 15fc8f2ebf1..72855708b84 100644 --- a/examples/Component/Mapping/NonLinear/SquareDistanceMapping.scn +++ b/examples/Component/Mapping/NonLinear/SquareDistanceMapping.scn @@ -31,7 +31,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/SquareMapping.scn b/examples/Component/Mapping/NonLinear/SquareMapping.scn index e0f4f93e672..743d7e466dd 100644 --- a/examples/Component/Mapping/NonLinear/SquareMapping.scn +++ b/examples/Component/Mapping/NonLinear/SquareMapping.scn @@ -37,7 +37,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/examples/Component/Mapping/NonLinear/VolumeMapping.scn b/examples/Component/Mapping/NonLinear/VolumeMapping.scn index 2fb335f5c77..4d615673628 100644 --- a/examples/Component/Mapping/NonLinear/VolumeMapping.scn +++ b/examples/Component/Mapping/NonLinear/VolumeMapping.scn @@ -41,7 +41,7 @@ - + diff --git a/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField.scn b/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField.scn index 3fa366e76c6..1c7265ae96b 100644 --- a/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField.scn +++ b/examples/Component/SolidMechanics/Spring/RestShapeSpringsForceField.scn @@ -19,7 +19,7 @@ - + @@ -43,7 +43,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -87,7 +87,7 @@ - + From 70c5c4aa0ad34d14b6828e28e816a1144abf8190 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 4 Mar 2025 17:46:05 +0100 Subject: [PATCH 18/21] Remove RestshapeSpringFF test because it only tested the FixedWeakConstraint part which doesn't make any sense now --- .../tests/RestShapeSpringsForceField_test.cpp | 141 ------------------ 1 file changed, 141 deletions(-) delete mode 100644 Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp diff --git a/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp b/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp deleted file mode 100644 index cc6d7bf5d39..00000000000 --- a/Sofa/Component/SolidMechanics/Spring/tests/RestShapeSpringsForceField_test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -using sofa::testing::BaseTest; - -#include -using namespace sofa::simpleapi; - -#include -#include - -#include -using sofa::component::statecontainer::MechanicalObject; - -using sofa::defaulttype::Vec3Types; -using sofa::defaulttype::Rigid3dTypes; -using sofa::helper::ReadAccessor; -using sofa::Data; - -/// Test suite for RestShapeSpringsForceField -class RestSpringsForceField_test : public BaseTest -{ -public: - ~RestSpringsForceField_test() override; - sofa::simulation::Node::SPtr createScene(const std::string& type); - - template - void testDefaultBehavior(sofa::simulation::Node::SPtr root); - - template - void checkDifference(MechanicalObject& mo, bool isFixed); -}; - -RestSpringsForceField_test::~RestSpringsForceField_test() -{ -} - -sofa::simulation::Node::SPtr RestSpringsForceField_test::createScene(const std::string& type) -{ - const auto theSimulation = createSimulation(); - auto theRoot = createRootNode(theSimulation, "root"); - sofa::simpleapi::importPlugin(Sofa.Component.ODESolver.Backward); - sofa::simpleapi::importPlugin(Sofa.Component.LinearSolver.Iterative); - sofa::simpleapi::importPlugin(Sofa.Component.StateContainer); - sofa::simpleapi::importPlugin(Sofa.Component.Mass); - - createObject(theRoot, "DefaultAnimationLoop"); - createObject(theRoot, "EulerImplicitSolver"); - createObject(theRoot, "CGLinearSolver", {{ "iterations", "25" }, { "tolerance", "1e-5" }, {"threshold", "1e-5"}}); - - /// Create an object with a mass and use a rest shape spring ff so it stays - /// at the initial position - const auto fixedObject = createChild(theRoot, "fixedObject"); - auto fixedObject_dofs = createObject(fixedObject, "MechanicalObject", {{"name","dofs"}, - {"size","10"}, - {"template",type}}); - createObject(fixedObject, "UniformMass", {{"totalMass", "1"}}); - - createObject(fixedObject, "RestShapeSpringsForceField", {{"stiffness","1000"}}); - - const auto movingObject = createChild(theRoot, "movingObject"); - auto movingObject_dofs =createObject(movingObject, "MechanicalObject", {{"name","dofs"}, - {"size","10"}, - {"template",type}}); - createObject(movingObject, "UniformMass", {{"totalMass", "1"}}); - - sofa::simulation::node::initRoot(theRoot.get()); - for(unsigned int i=0;i<20;i++) - { - sofa::simulation::node::animate(theRoot.get(), 0.01_sreal); - } - return theRoot; -} - -template -void RestSpringsForceField_test::checkDifference(MechanicalObject& mo, bool isFixed) -{ - ReadAccessor< Data > positions = mo.x; - ReadAccessor< Data > rest_positions = mo.x0; - for(size_t i=0;i -void RestSpringsForceField_test::testDefaultBehavior(sofa::simulation::Node::SPtr root) -{ - auto fixedDofs = dynamic_cast*>(root->getChild("fixedObject")->getObject("dofs")); - ASSERT_TRUE( fixedDofs != nullptr ); - - auto movingDofs = dynamic_cast*>(root->getChild("movingObject")->getObject("dofs")); - ASSERT_TRUE( movingDofs != nullptr ); - - checkDifference(*fixedDofs, true); - checkDifference(*movingDofs, false); -} - - -TEST_F(RestSpringsForceField_test, defaultBehaviorVec3) -{ - this->testDefaultBehavior(this->createScene("Vec3")); -} - -TEST_F(RestSpringsForceField_test, defaultBehaviorRigid3) -{ - this->testDefaultBehavior(this->createScene("Rigid3")); -} From 5688b58393856aa38f972d697059543428794dbe Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 4 Mar 2025 17:48:57 +0100 Subject: [PATCH 19/21] Forgot CMakeLists.txt --- Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt b/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt index efb46546b5b..800e0fba4b0 100644 --- a/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt +++ b/Sofa/Component/SolidMechanics/Spring/tests/CMakeLists.txt @@ -4,7 +4,6 @@ project(Sofa.Component.SolidMechanics.Spring_test) set(SOURCE_FILES PolynomialRestShapeSpringsForceField_test.cpp - RestShapeSpringsForceField_test.cpp SpringForceField_test.cpp TriangularBendingSprings_test.cpp FixedWeakConstraint_test.cpp From 7542160c9a062da23381e97d199664b92b9a69a7 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 13 Mar 2025 09:45:20 +0100 Subject: [PATCH 20/21] Fix one unit test --- .../Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp b/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp index f62537fceb7..2d93c6a7890 100644 --- a/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp +++ b/Sofa/Component/Mapping/NonLinear/tests/SquareDistanceMapping_test.cpp @@ -182,7 +182,7 @@ struct SquareDistanceMappingCompare_test : NumericTest {{"topology", "@../topology"}, {"input", "@../defoDOF"}, {"output", "@extensionsDOF"}, {"geometricStiffness", "1"}, {"applyRestPosition", "true"}}); - simpleapi::createObject(oneMappingExtension, "RestShapeSpringsForceField", {{"template", "Vec1"}, {"stiffness", "10000"}}); + simpleapi::createObject(oneMappingExtension, "FixedWeakConstraint", {{"template", "Vec1"}, {"stiffness", "10000"},{"fixAll", "true"}}); @@ -197,7 +197,7 @@ struct SquareDistanceMappingCompare_test : NumericTest {{"input", "@../extensionsDOF"}, {"output", "@squaredDOF"}, {"geometricStiffness", "1"}, {"applyRestPosition", "true"}}); - simpleapi::createObject(distanceMappingNode, "RestShapeSpringsForceField", {{"template", "Vec1"}, {"stiffness", "10000"}}); + simpleapi::createObject(distanceMappingNode, "FixedWeakConstraint", {{"template", "Vec1"}, {"stiffness", "10000"},{"fixAll", "true"}}); } From 46612efd2984a99ade39067c4680f76d992cd44e Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 3 Apr 2025 14:31:08 +0200 Subject: [PATCH 21/21] Fix tests --- .../ODESolver/Backward/tests/NewtonRaphsonSolver_test.cpp | 2 +- applications/plugins/CMakeLists.txt | 1 + .../Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sofa/Component/ODESolver/Backward/tests/NewtonRaphsonSolver_test.cpp b/Sofa/Component/ODESolver/Backward/tests/NewtonRaphsonSolver_test.cpp index 4579eee7b92..619b2f9b691 100644 --- a/Sofa/Component/ODESolver/Backward/tests/NewtonRaphsonSolver_test.cpp +++ b/Sofa/Component/ODESolver/Backward/tests/NewtonRaphsonSolver_test.cpp @@ -294,7 +294,7 @@ struct NewtonRaphsonTest : public testing::BaseSimulationTest { sofa::simpleapi::importPlugin("Sofa.Component.SolidMechanics.Spring"); - sofa::simpleapi::createObject(m_scene.root, "RestShapeSpringsForceField", {{"points", "0"}, {"stiffness", std::to_string(k)}}); + sofa::simpleapi::createObject(m_scene.root, "FixedWeakConstraint", {{"indices", "0"}, {"stiffness", std::to_string(k)}}); m_scene.initScene(); EXPECT_EQ(m_solver->d_status.getValue(), component::odesolver::backward::NewtonStatus("Undefined")); diff --git a/applications/plugins/CMakeLists.txt b/applications/plugins/CMakeLists.txt index a58836c2820..4a6fc9e9d5b 100644 --- a/applications/plugins/CMakeLists.txt +++ b/applications/plugins/CMakeLists.txt @@ -43,6 +43,7 @@ sofa_add_subdirectory(plugin SofaMatrix SofaMatrix) # Depends on image, CImgPlug sofa_add_external(plugin BeamAdapter GIT_REF master GIT_REPOSITORY https://www.github.com/sofa-framework/BeamAdapter.git) sofa_add_external(plugin STLIB GIT_REF master GIT_REPOSITORY https://www.github.com/SofaDefrost/STLIB.git) sofa_add_external(plugin SoftRobots GIT_REF master GIT_REPOSITORY https://www.github.com/SofaDefrost/SoftRobots.git) +sofa_add_external(plugin SoftRobots.Inverse GIT_REF master GIT_REPOSITORY https://www.github.com/SofaDefrost/SoftRobots.Inverse.git) sofa_add_external(plugin Cosserat GIT_REF master GIT_REPOSITORY https://www.github.com/SofaDefrost/Cosserat.git) # Cosserat has an optional dependency on SoftRobots sofa_add_external(plugin CollisionAlgorithm GIT_REF master GIT_REPOSITORY https://forge.icube.unistra.fr/sofa/CollisionAlgorithm.git) sofa_add_external(plugin ConstraintGeometry GIT_REF master GIT_REPOSITORY https://forge.icube.unistra.fr/sofa/ConstraintGeometry.git) diff --git a/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn index 6787469b811..917cb9fd628 100644 --- a/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn +++ b/examples/Component/SolidMechanics/Spring/FixedWeakConstaint_Vec3.scn @@ -27,7 +27,7 @@ - +

    Z#>VP{?LKfP14`@#Z1W_MERwZSaG6fiZ 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 diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Viewer.png b/Sofa/GUI/Qt/src/sofa/gui/qt/Doc_Viewer/index_fichiers/Viewer.png deleted file mode 100644 index 4ffdf78bde31bc6daf359ff97b8050d90b076583..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10961 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 N_`cS?%HJ%){}(FxaG3xA diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.cpp deleted file mode 100644 index c6f296bac98..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/FileManagement.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "FileManagement.h" -#include - -namespace sofa::gui::qt -{ - -#include - -QString getExistingDirectory ( QWidget* parent, const QString & dir, const char * name, const QString & caption) -{ - QFileDialog::Options options = QFileDialog::ShowDirsOnly; -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - options |= QFileDialog::DontUseSheet; -#endif - return QFileDialog::getExistingDirectory ( parent, name?QString(name):caption, dir, options ); -} - -QString getOpenFileName ( QWidget* parent, const QString & startWith, const QString & filter, const char * name, const QString & caption, QString * selectedFilter ) -{ -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - QFileDialog::Options options = 0; - options |= QFileDialog::DontUseSheet; -#else - QFileDialog::Options options; -#endif - return QFileDialog::getOpenFileName ( parent, name?QString(name):caption, startWith, filter, selectedFilter, options ); -} - -QString getSaveFileName ( QWidget* parent, const QString & startWith, const QString & filter, const char * name, const QString & caption, QString * selectedFilter ) -{ -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - QFileDialog::Options options = 0; - options |= QFileDialog::DontUseSheet; -#else - QFileDialog::Options options; -#endif - return QFileDialog::getSaveFileName ( parent, name?QString(name):caption, startWith, filter, selectedFilter, options ); -} - -void getFilesInDirectory( const QString &p, std::vector< QString > &files, bool recursive, const std::vector< QString > &filter ) -{ - QString path=p; - if (path.endsWith("/")) - { - const int slash=path.indexOf('/',-1); - path.truncate(slash); - } - else if (path.endsWith("\\")) - { - const int slash=path.indexOf('\\',-1); - path.truncate(slash); - } - - QDir d(path); - - d.setFilter( QDir::Dirs | QDir::Hidden | QDir::NoSymLinks ); - - std::vector< QString > subDir; - - const QFileInfoList &listDirectories = d.entryInfoList(); - QStringList filters; - for (unsigned int i=0; i. * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include - - -namespace sofa::gui::qt -{ - - -QString SOFA_GUI_QT_API getExistingDirectory ( QWidget* parent, const QString & dir = QString(), const char * name = nullptr, const QString & caption = QString() ); - -QString SOFA_GUI_QT_API getOpenFileName ( QWidget* parent, const QString & startWith = QString(), const QString & filter = QString(), const char * name = nullptr, const QString & caption = QString(), QString * selectedFilter = nullptr ); - -QString SOFA_GUI_QT_API getSaveFileName ( QWidget* parent, const QString & startWith = QString(), const QString & filter = QString(), const char * name = nullptr, const QString & caption = QString(), QString * selectedFilter = nullptr ); - - -void SOFA_GUI_QT_API getFilesInDirectory( const QString &path, std::vector< QString > &files, bool recursive=true, const std::vector< QString > &filter=std::vector< QString >() ); - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.cpp deleted file mode 100644 index 3a9c874eea1..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -namespace sofa::gui::qt -{ - -using namespace sofa::component::collision::geometry; -using namespace sofa::gui::common; -using namespace sofa::gui::component::performer; - -GLPickHandler::GLPickHandler(double defaultLength) - : Inherit(defaultLength) - , _fboAllocated(false) - , _fbo(true,true,true,false,0) -{ - -} - - -GLPickHandler::~GLPickHandler() -{ - - -} - -void GLPickHandler::allocateSelectionBuffer(int width, int height) -{ - /*called when shift key is pressed */ - assert(_fboAllocated == false ); - - static bool firstTime=true; - if (firstTime) - { - _fboParams.depthInternalformat = GL_DEPTH_COMPONENT24; -#if defined(GL_VERSION_3_0) - if (GLEW_VERSION_3_0) - { - _fboParams.colorInternalformat = GL_RGBA32F; - } - else -#endif // (GL_VERSION_3_0) - { - _fboParams.colorInternalformat = GL_RGBA16; - } - _fboParams.colorFormat = GL_RGBA; - _fboParams.colorType = GL_FLOAT; - - _fbo.setFormat(_fboParams); - firstTime=false; - } - _fbo.init(width,height); - - _fboAllocated = true; -} - -void GLPickHandler::destroySelectionBuffer() -{ - /*called when shift key is released */ - assert(_fboAllocated); - - _fbo.destroy(); - - _fboAllocated = false; -} - -//WARNING: do not use this method with Ogre -BodyPicked GLPickHandler::findCollisionUsingColourCoding(const type::Vec3& origin, - const type::Vec3& direction) -{ - assert(_fboAllocated); - BodyPicked result; - - result.dist = 0; - type::RGBAColor color; - const int x = mousePosition.x; - const int y = mousePosition.screenHeight - mousePosition.y; - TriangleCollisionModel* tmodel; - SphereCollisionModel* smodel; - _fbo.start(); - if(renderCallback) - { - renderCallback->render(ColourPickingVisitor::ENCODE_COLLISIONELEMENT ); - glReadPixels(x,y,1,1,_fboParams.colorFormat,_fboParams.colorType, &color[0]); - decodeCollisionElement(color,result); - renderCallback->render(ColourPickingVisitor::ENCODE_RELATIVEPOSITION ); - glReadPixels(x,y,1,1,_fboParams.colorFormat,_fboParams.colorType, &color[0]); - if( ( tmodel = dynamic_cast*>(result.body) ) != nullptr ) - { - decodePosition(result,color,tmodel,result.indexCollisionElement); - } - if( ( smodel = dynamic_cast*>(result.body)) != nullptr) - { - decodePosition(result, color,smodel,result.indexCollisionElement); - } - result.rayLength = (result.point-origin)*direction; - } - _fbo.stop(); - - return result; -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.h deleted file mode 100644 index e4f2f81a8e8..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GLPickHandler.h +++ /dev/null @@ -1,68 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include - -#include -#include -#include - -namespace sofa::component::collision::model -{ - class RayCollisionModel; -} // namespace sofa::component::collision::model - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API GLPickHandler : public common::PickHandler -{ - typedef PickHandler Inherit; - typedef sofa::component::collision::model::RayCollisionModel MouseCollisionModel; - typedef sofa::component::statecontainer::MechanicalObject< defaulttype::Vec3Types > MouseContainer; - -public: - enum PickingMethod - { - RAY_CASTING, - SELECTION_BUFFER - }; - - GLPickHandler(double defaultLength = 1000000); - virtual ~GLPickHandler() override; - - void allocateSelectionBuffer(int width, int height) override; - void destroySelectionBuffer() override; - - common::BodyPicked findCollisionUsingColourCoding(const type::Vec3& origin, const type::Vec3& direction) override; - -protected: - bool _fboAllocated; - gl::FrameBufferObject _fbo; - gl::fboParameters _fboParams; - -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GUI.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/GUI.ui deleted file mode 100644 index fef9ad0c8de..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GUI.ui +++ /dev/null @@ -1,1008 +0,0 @@ - - - GUI - - - - 0 - 0 - 800 - 600 - - - - - 0 - 0 - - - - - 210 - 481 - - - - true - - - Sofa - - - - - 0 - 0 - - - - - 0 - 0 - - - - - QLayout::SetNoConstraint - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - true - - - - 0 - 0 - 800 - 22 - - - - - &File - - - - - - - - - - &Edit - - - - - - - - - - - - &View - - - - - - - - Help - - - - - - - - - - - - - - 0 - 0 - - - - - 200 - 551 - - - - 1 - - - - - 0 - 0 - - - - - 200 - 0 - - - - - - - true - - - - 0 - 0 - - - - - QLayout::SetNoConstraint - - - - - QLayout::SetNoConstraint - - - - - true - - - Set the camera to initial position and orientation - - - Reset &View - - - Alt+V - - - - - - - Launch the Simulation - - - &Animate - - - Alt+A - - - true - - - - - - - true - - - Save the position and orientation of the camera - - - Save Vie&w - - - Alt+W - - - - - - - true - - - Reload the simulation file - - - &Reload Scene - - - Alt+R - - - - - - - Compute the simulation at time t+DT - - - S&tep - - - Alt+T - - - true - - - - - - - Save S&creenshot - - - Alt+C - - - - - - - QLayout::SetNoConstraint - - - - - DT: - - - false - - - - - - - - 0 - 0 - - - - - 20 - 0 - - - - - 80 - 32767 - - - - - - - - Use the duration of the previous simulation step as the next DT - - - Real Time - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - - 0 - 0 - - - - - 200 - 0 - - - - 0 - - - - Graph - - - - - - - - - 0 - 0 - - - - Export Graph... - - - - image1image1 - - - Alt+X - - - - - - - Collapse All - - - - - - - - - - - - - Expand All - - - - - - - - - - - - - The scene graph update button has three states -State 0: unlocked (all the changes on the graph are immediately taken into account) -State 1: locked (the changes on the graph are not done but the simulation graph is set to dirty if - there is some changes on the graph. A click on the button unlocks the graph (go to state 0). -State 2: dirty, in that state the button reflect the fact that the scene graph view has changed but not displayed. - A click on the button refreshes the graph view but does not change the Lock/Unlock state - - - - - - - - - - - - - - 0 - 0 - - - - View - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Ignored - - - - 0 - 16 - - - - - - - - - 0 - 0 - - - - http://sofa-framework.org - - - image0 - - - true - - - false - - - - - - - Qt::Horizontal - - - QSizePolicy::Ignored - - - - 0 - 16 - - - - - - - - - - - - - Visual - - - - - - E&xport Graph... - - - - image1image1 - - - Alt+X - - - - - - - - Stats - - - - - - Record the state at each time step in file "dumpState.data" - - - Dump State - - - - - - - Display information about the time spent at each branch of the graph - - - Log Time - - - - - - - Create gnuplot files for each named element of the simulation - - - Export state as gnuplot files - - - - - - - Open a Dialog showing a trace of the execution and time spent - - - Trace Visitor and Component execution - - - - - - - Display AdvancedTimer profiler - - - - - - - - Viewer - - - - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 10 - 2 - - - - - - - - 30000 - - - 800 - - - - - - - - 0 - 0 - - - - <p align="center">x</p> - - - false - - - - - - - 30000 - - - 600 - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 10 - 2 - - - - - - - - - - - - - - - - - - - - - - - image3image3 - - - &Open... - - - Open - - - Ctrl+O - - - fileOpenAction - - - - - &Reload - - - Reload - - - Ctrl+R - - - fileReloadAction - - - - - E&xit - - - Exit - - - - - - fileExitAction - - - - - true - - - &About - - - About - - - - - - false - - - helpAboutAction - - - - - Viewer - - - ViewerAction - - - - - Record Directory... - - - Record Directory... - - - editRecordDirectoryAction - - - - - Gnuplot Directory... - - - Gnuplot Directory... - - - editGnuplotDirectoryAction - - - - - Plugin Manager... - - - Plugin Manager... - - - PluginManagerAction - - - - - Mouse Manager... - - - Mouse Manager... - - - MouseManagerAction - - - - - Recently Opened Files... - - - Action - - - - - Test - - - Test - - - TestAction - - - - - Video Recorder Manager... - - - Video Recorder Manager... - - - VideoRecorderManagerAction - - - - - false - - - Show doc browser - - - false - - - - - Data Graph... - - - Data Graph Window - - - - - - sofa/gui/qt/config.h - - - - - fileOpenAction - triggered() - GUI - popupOpenFileSelector() - - - -1 - -1 - - - 20 - 20 - - - - - fileReloadAction - triggered() - GUI - fileReload() - - - -1 - -1 - - - 20 - 20 - - - - - fileExitAction - triggered() - GUI - fileExit() - - - -1 - -1 - - - 20 - 20 - - - - - editRecordDirectoryAction - triggered() - GUI - editRecordDirectory() - - - -1 - -1 - - - 20 - 20 - - - - - PluginManagerAction - triggered() - GUI - showPluginManager() - - - -1 - -1 - - - 20 - 20 - - - - - MouseManagerAction - triggered() - GUI - showMouseManager() - - - -1 - -1 - - - 20 - 20 - - - - - DataGraphAction - triggered() - GUI - showWindowDataGraph() - - - -1 - -1 - - - 20 - 20 - - - - - editGnuplotDirectoryAction - triggered() - GUI - editGnuplotDirectory() - - - -1 - -1 - - - 20 - 20 - - - - - VideoRecorderManagerAction - triggered() - GUI - showVideoRecorderManager() - - - -1 - -1 - - - 20 - 20 - - - - - helpShowDocBrowser - triggered() - GUI - showDocBrowser() - - - -1 - -1 - - - 399 - 299 - - - - - - showDocBrowser() - fileNew() - popupOpenFileSelector() - fileReload() - fileSave() - fileExit() - editRecordDirectory() - showPluginManager() - showMouseManager() - showWindowDataGraph() - editGnuplotDirectory() - showVideoRecorderManager() - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.cpp deleted file mode 100644 index 279eca9f45d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "GenGraphForm.h" - -#ifdef WIN32 -#include -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -GenGraphForm::GenGraphForm(QWidget *parent) - : QDialog(parent) - , currentTask(nullptr) - , settingFilter(false) -{ - setupUi(this); - // signals and slots connections - connect(browseButton, &QPushButton::clicked, this, &GenGraphForm::doBrowse); - connect(exportButton, &QPushButton::clicked, this, &GenGraphForm::doExport); - connect(displayButton, &QPushButton::clicked, this, &GenGraphForm::doDisplay); - connect(closeButton, &QPushButton::clicked, this, &GenGraphForm::doClose); - connect(filename, &QLineEdit::textChanged, this, &GenGraphForm::change); - connect(presetFilter, QOverload::of(&QComboBox::activated), [=](int){ setFilter(); }); - connect(showNodes, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showObjects, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showBehaviorModels, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showCollisionModels, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showVisualModels, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showMappings, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showContext, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showCollisionPipeline, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showSolvers, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showMechanicalStates, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showForceFields, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showInteractionForceFields, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showConstraints, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showMass, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showTopology, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - connect(showMechanicalMappings, &QCheckBox::toggled, this, &GenGraphForm::changeFilter); - - // init preset filters - { - std::set& filt = presetFilters["Full Graph"]; - filt.insert("showNodes"); - filt.insert("showObjects"); - filt.insert("showBehaviorModels"); - filt.insert("showCollisionModels"); - filt.insert("showVisualModels"); - filt.insert("showMappings"); - filt.insert("showContext"); - filt.insert("showCollisionPipeline"); - filt.insert("showSolvers"); - filt.insert("showMechanicalStates"); - filt.insert("showForceFields"); - filt.insert("showInteractionForceFields"); - filt.insert("showConstraints"); - filt.insert("showMass"); - filt.insert("showTopology"); - filt.insert("showMechanicalMappings"); - } - { - std::set& filt = presetFilters["All Objects"]; - filt = presetFilters["Full Graph"]; - filt.erase("showNodes"); - } - { - std::set& filt = presetFilters["All Nodes"]; - filt.insert("showNodes"); - } - { - std::set& filt = presetFilters["Mechanical Graph"]; - filt = presetFilters["Full Graph"]; - filt.erase("showCollisionModels"); - filt.erase("showVisualModels"); - filt.erase("showMappings"); - filt.erase("showCollisionPipeline"); - } - { - std::set& filt = presetFilters["Mechanical Objects"]; - filt = presetFilters["Mechanical Graph"]; - filt.erase("showNodes"); - } - { - std::set& filt = presetFilters["Visual Graph"]; - filt.insert("showNodes"); - filt.insert("showObjects"); - filt.insert("showVisualModels"); - } - { - std::set& filt = presetFilters["Visual Objects"]; - filt = presetFilters["Visual Graph"]; - filt.erase("showNodes"); - } - { - std::set& filt = presetFilters["Collision Graph"]; - filt.insert("showNodes"); - filt.insert("showObjects"); - filt.insert("showCollisionModels"); - filt.insert("showCollisionPipeline"); - } - { - std::set& filt = presetFilters["Collision Objects"]; - filt = presetFilters["Collision Graph"]; - filt.erase("showNodes"); - } - { - std::set& filt = presetFilters["Collision Response Graph"]; - filt.insert("showNodes"); - filt.insert("showObjects"); - //filt.insert("showBehaviorModels"); - filt.insert("showCollisionModels"); - //filt.insert("showVisualModels"); - //filt.insert("showMappings"); - //filt.insert("showContext"); - //filt.insert("showCollisionPipeline"); - filt.insert("showSolvers"); - filt.insert("showMechanicalStates"); - //filt.insert("showForceFields"); - filt.insert("showInteractionForceFields"); - filt.insert("showConstraints"); - //filt.insert("showMass"); - //filt.insert("showTopology"); - filt.insert("showMechanicalMappings"); - } - { - std::set& filt = presetFilters["Collision Response Objects"]; - filt = presetFilters["Collision Response Graph"]; - filt.erase("showNodes"); - } - -} - -void GenGraphForm::change() -{ - //exported = false; - displayButton->setEnabled(false); - if (exportButton->text() != "&Kill") - exportButton->setEnabled(filename->text()!=QString("")); -} - -void GenGraphForm::changeFilter() -{ - displayButton->setEnabled(false); - if (settingFilter) return; - const std::set filt = getCurrentFilter(); - for (std::map >::const_iterator it = presetFilters.begin(); it != presetFilters.end(); ++it) - { - if (it->second == filt) - { - const int index = presetFilter->findText(it->first.c_str()); - presetFilter->setCurrentIndex(index); - return; - } - } - const int index = presetFilter->findText(""); - presetFilter->setCurrentIndex(index); -} - -QString removeFileExt(const QString &s) -{ - const int ext = s.lastIndexOf('.'); - if (ext==-1) return s; - if (s.indexOf('/', ext+1) != -1|| s.indexOf('\\', ext+1) != -1) - return s; - return s.left(ext); -} - -void GenGraphForm::doBrowse() -{ - QString s = QFileDialog::getSaveFileName( - this, - "Choose a file to save", -// "export graph file dialog", - filename->text(), - "DOT Graph (*.dot)" ); - if (s.length()>0) - { - if (removeFileExt(s)==s) // no extension specified - s += ".dot"; - filename->setText(s); - change(); - } -} - -void GenGraphForm::doExport() -{ - if (!tasks.empty()) - { - killAllTasks(); - return; - } - if (filename->text()==QString("")) return; - - filename->setStyleSheet(""); - - QString dotfile = filename->text(); - - QString basefile = removeFileExt(dotfile); - - if (basefile==dotfile) // no extension specified - dotfile += ".dot"; - - std::ofstream fdot; - fdot.open(dotfile.toStdString().c_str(), std::ofstream::out | std::ofstream::trunc); - if (!fdot.is_open()) - { - msg_error("GenGraphForm") << "Output to " << dotfile.toStdString() << " failed."; - filename->clear(); - filename->setFocus(); - filename->setStyleSheet("border: 1px solid red"); - return; - } - { - sofa::simulation::graph::ExportDotVisitor act(sofa::core::execparams::defaultInstance(), &fdot); - act.showNode = this->showNodes->isChecked(); - act.showObject = this->showObjects->isChecked(); - act.showBehaviorModel = this->showBehaviorModels->isChecked(); - act.showCollisionModel = this->showCollisionModels->isChecked(); - act.showVisualModel = this->showVisualModels->isChecked(); - act.showMapping = this->showMappings->isChecked(); - act.showContext = this->showContext->isChecked(); - act.showCollisionPipeline = this->showCollisionPipeline->isChecked(); - act.showSolver = this->showSolvers->isChecked(); - act.showMechanicalState = this->showMechanicalStates->isChecked(); - act.showForceField = this->showForceFields->isChecked(); - act.showInteractionForceField = this->showInteractionForceFields->isChecked(); - act.showConstraint = this->showConstraints->isChecked(); - act.showMass = this->showMass->isChecked(); - act.showTopology = this->showTopology->isChecked(); - act.showMechanicalMapping = this->showMechanicalMappings->isChecked(); - act.labelNodeName = this->labelNodeName->isChecked(); - act.labelNodeClass = this->labelNodeClass->isChecked(); - act.labelObjectName = this->labelObjectName->isChecked(); - act.labelObjectClass = this->labelObjectClass->isChecked(); - graph->executeVisitor(&act); - } - fdot.close(); - msg_info("GenGraphForm") << "File saved in " << dotfile.toStdString(); - - QStringList argv0; - if (layoutDirV->isChecked()) - argv0 << "dot" << "-Grankdir=TB"; - else if (layoutDirH->isChecked()) - argv0 << "dot" << "-Grankdir=LR"; - else if (layoutSpring->isChecked()) - argv0 << "neato"; - else if (layoutRadial->isChecked()) - argv0 << "twopi"; - - bool exp = false; - - exportedFile = dotfile; - - if (genPNG->isChecked()) - { - QStringList argv = argv0; - argv << "-Tpng" << "-o" << basefile+".png"; - argv << dotfile; - addTask(argv); - if (!exp) - { - exp = true; - exportedFile = basefile+".png"; - } - } - - if (genPS->isChecked()) - { - QStringList argv = argv0; - argv << "-Tps" << "-o" << basefile+".ps"; - argv << dotfile; - addTask(argv); - if (!exp) - { - exp = true; - exportedFile = basefile+".ps"; - } - } - - if (genFIG->isChecked()) - { - QStringList argv = argv0; - argv << "-Tfig" << "-o" << basefile+".fig"; - argv << dotfile; - addTask(argv); - if (!exp) - { - exp = true; - exportedFile = basefile+".fig"; - } - } - - if (genSVG->isChecked()) - { - QStringList argv = argv0; - argv << "-Tsvg" << "-o" << basefile+".svg"; - argv << dotfile; - addTask(argv); - if (!exp) - { - exp = true; - exportedFile = basefile+".svg"; - } - } - //exported = true; - //displayButton->setEnabled(true); -} - -void GenGraphForm::doDisplay() -{ - if (exportedFile==QString("")) return; - - msg_info("GenGraphForm") << "OPEN " << exportedFile.toStdString(); - -#ifdef WIN32 - ShellExecuteA(nullptr, "open", exportedFile.toStdString().c_str(), nullptr, nullptr, SW_SHOWNORMAL); -#else - QStringList argv; - argv << "display" << exportedFile; - - QString program = argv.front(); - argv.pop_front(); - //QProcess::startDetached(program, argv); //QString("start \"\"\"")+exportedFile+QString("\"\"\"")); - QProcess::startDetached(program, argv); //QString("start \"\"\"")+exportedFile+QString("\"\"\"")); -#endif -} - -void GenGraphForm::doClose() -{ - killAllTasks(); - this->close(); -} - -void GenGraphForm::setScene(sofa::simulation::Node* scene) -{ - graph = scene; -} - -void GenGraphForm::killAllTasks() -{ - exportButton->setText("&Export"); - if (currentTask) - { - currentTask->kill(); - delete currentTask; - currentTask = nullptr; - } - tasks.clear(); -} - -void GenGraphForm::addTask(QStringList argv) -{ - tasks.push_back(argv); - if (currentTask == nullptr) - runTask(); -} - -void GenGraphForm::taskFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - static const std::map exitStatusMap { - { QProcess::ExitStatus::NormalExit, "normal exit"}, - { QProcess::ExitStatus::CrashExit, "crash exit"}, - }; - const auto it = exitStatusMap.find(exitStatus); - const auto exitStatusString = it == exitStatusMap.end() ? "unknown" : it->second; - msg_info("GenGraphForm") << "TASK FINISHED (exit code: " << exitCode << ", exit status: " << exitStatusString << ")"; - if (currentTask == nullptr) return; - - delete currentTask; - currentTask = nullptr; - if (tasks.empty()) - { - displayButton->setEnabled(true); - exportButton->setText("&Export"); - } - else - { - runTask(); - } -} - -void GenGraphForm::taskError(QProcess::ProcessError error) -{ - static const std::map errorMap { - { QProcess::ProcessError::FailedToStart, "failed to start"}, - { QProcess::ProcessError::Crashed, "crashed"}, - { QProcess::ProcessError::Timedout, "timed out"}, - { QProcess::ProcessError::ReadError, "read error"}, - { QProcess::ProcessError::WriteError, "write error"}, - { QProcess::ProcessError::UnknownError, "unknown error"}, - }; - const auto it = errorMap.find(error); - const auto errorString = it == errorMap.end() ? "unknown" : it->second; - msg_error("GenGraphForm") << "An error occurred: " << errorString; - - if (error == QProcess::ProcessError::FailedToStart) - { - msg_error("GenGraphForm") << "Check that the required program (Graphviz) is in your PATH environment variable"; - } - - exportButton->setText("&Export"); - if (currentTask) - { - currentTask->kill(); - delete currentTask; - currentTask = nullptr; - } -} - -void GenGraphForm::runTask() -{ - QStringList argv = tasks.front(); - tasks.pop_front(); - exportButton->setText("&Kill"); - const QString cmd = argv.join(QString(" ")); - msg_info("GenGraphForm") << "STARTING TASK " << cmd.toStdString(); - - auto* p = new QProcess(this); - const QString program = argv.front(); - argv.pop_front(); -#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) - p->setReadChannelMode(QProcess::ForwardedChannels); -#else - p->setProcessChannelMode(QProcess::ForwardedChannels); -#endif - connect(p, - QOverload::of(&QProcess::finished), - this,&GenGraphForm::taskFinished); - connect(p,&QProcess::errorOccurred,this,&GenGraphForm::taskError); - p->start(program, argv); - currentTask = p; -} - -void GenGraphForm::setFilter() -{ - const QString fname = presetFilter->currentText(); - if (fname == "") return; - const std::string name = fname.toStdString(); - if (presetFilters.count(name) > 0) - { - const std::set & filt = presetFilters[name]; - settingFilter = true; - this->showNodes->setChecked(filt.find("showNodes")!=filt.end()); - this->showObjects->setChecked(filt.find("showObjects")!=filt.end()); - this->showBehaviorModels->setChecked(filt.find("showBehaviorModels")!=filt.end()); - this->showCollisionModels->setChecked(filt.find("showCollisionModels")!=filt.end()); - this->showVisualModels->setChecked(filt.find("showVisualModels")!=filt.end()); - this->showMappings->setChecked(filt.find("showMappings")!=filt.end()); - this->showContext->setChecked(filt.find("showContext")!=filt.end()); - this->showCollisionPipeline->setChecked(filt.find("showCollisionPipeline")!=filt.end()); - this->showSolvers->setChecked(filt.find("showSolvers")!=filt.end()); - this->showMechanicalStates->setChecked(filt.find("showMechanicalStates")!=filt.end()); - this->showForceFields->setChecked(filt.find("showForceFields")!=filt.end()); - this->showInteractionForceFields->setChecked(filt.find("showInteractionForceFields")!=filt.end()); - this->showConstraints->setChecked(filt.find("showConstraints")!=filt.end()); - this->showMass->setChecked(filt.find("showMass")!=filt.end()); - this->showTopology->setChecked(filt.find("showTopology")!=filt.end()); - this->showMechanicalMappings->setChecked(filt.find("showMechanicalMappings")!=filt.end()); - settingFilter = false; - displayButton->setEnabled(false); - const int index = presetFilter->findText(fname); - presetFilter->setCurrentIndex(index); - } - else - { - //if (QMessage::question(this,"Graph Preset Filters",...) - presetFilters[name] = getCurrentFilter(); - } -} - -std::set GenGraphForm::getCurrentFilter() -{ - std::set filt; - if (this->showNodes->isChecked()) filt.insert("showNodes"); - if (this->showObjects->isChecked()) filt.insert("showObjects"); - if (this->showBehaviorModels->isChecked()) filt.insert("showBehaviorModels"); - if (this->showCollisionModels->isChecked()) filt.insert("showCollisionModels"); - if (this->showVisualModels->isChecked()) filt.insert("showVisualModels"); - if (this->showMappings->isChecked()) filt.insert("showMappings"); - if (this->showContext->isChecked()) filt.insert("showContext"); - if (this->showCollisionPipeline->isChecked()) filt.insert("showCollisionPipeline"); - if (this->showSolvers->isChecked()) filt.insert("showSolvers"); - if (this->showMechanicalStates->isChecked()) filt.insert("showMechanicalStates"); - if (this->showForceFields->isChecked()) filt.insert("showForceFields"); - if (this->showInteractionForceFields->isChecked()) filt.insert("showInteractionForceFields"); - if (this->showConstraints->isChecked()) filt.insert("showConstraints"); - if (this->showMass->isChecked()) filt.insert("showMass"); - if (this->showTopology->isChecked()) filt.insert("showTopology"); - if (this->showMechanicalMappings->isChecked()) filt.insert("showMechanicalMappings"); - return filt; -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.h deleted file mode 100644 index cba9f697bb9..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GenGraphForm.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include "QProcess" -#include "QStringList" -#include - -#include -#include -#include - -namespace sofa::gui::qt -{ - -class GenGraphForm : public QDialog, public Ui_BaseGenGraphForm -{ - Q_OBJECT -public: - GenGraphForm(QWidget *parent = Q_NULLPTR); - - void setScene(sofa::simulation::Node* scene); - -public slots: - virtual void change(); - virtual void doBrowse(); - virtual void doExport(); - virtual void doDisplay(); - virtual void doClose(); - virtual void taskFinished(int exitCode ,QProcess::ExitStatus exitStatus); - virtual void taskError(QProcess::ProcessError error); - virtual void changeFilter(); - virtual void setFilter(); - -protected: - QString exportedFile; - sofa::simulation::Node* graph; - std::list tasks; - QProcess* currentTask; - - void addTask(QStringList argv); - void runTask(); - void killAllTasks(); - - std::map > presetFilters; - bool settingFilter; - std::set getCurrentFilter(); -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GenericWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GenericWidget.h deleted file mode 100644 index 594e6cc21fb..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GenericWidget.h +++ /dev/null @@ -1,84 +0,0 @@ -/****************************************************************************** - * SOFA, Simulation Open-Framework Architecture * - * (c) 2006 INRIA, USTL, UJF, CNRS, MGH * - * * - * This program is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the Free * - * Software Foundation; either version 2 of the License, or (at your option) * - * any later version. * - * * - * This program is distributed in the hope that it will be useful, but WITHOUT * - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * - * more details. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program. If not, see . * - ******************************************************************************* - * Authors: The SOFA Team and external contributors (see Authors.txt) * - * * - * Contact information: contact@sofa-framework.org * - ******************************************************************************/ -#pragma once - -#include - -namespace sofa::gui::qt -{ -template -class GenericDataWidget : public sofa::gui::qt::DataWidget -{ -public: - typedef DATA MyData; - typedef WIDGET MyWidget; - - GenericDataWidget(QWidget* parent, const char* name, MyData* d) : sofa::gui::qt::DataWidget(parent, name, d), m_data(d) {} - - virtual bool createWidgets() - { - m_widget = new MyWidget(this, *m_data); - m_widget->setParent(this); - setLayout(new QVBoxLayout(this)); - layout()->addWidget(m_widget); - m_widget->setVisible(true); - readFromData(); - return true; - } - - template - static RealObject* create(RealObject*, CreatorArgument& arg) - { - typename RealObject::MyData* realData = dynamic_cast(arg.data); - if (!realData) - return nullptr; - else - { - RealObject* obj = new RealObject(arg.parent, arg.name.c_str(), realData); - if (!obj->createWidgets()) - { - delete obj; - obj = nullptr; - } - if (obj) - { - obj->setDataReadOnly(arg.readOnly); - } - return obj; - } - } - - virtual void setDataReadOnly(bool readOnly) { m_widget->setEnabled(!readOnly); } - - virtual void readFromData() { m_widget->readFromData(*m_data); } - - virtual void writeToData() { m_widget->writeToData(*m_data); } - -protected: - MyData* m_data; - MyWidget* m_widget; -}; - -} // namespace sofa::gui::qt - -template -using GenericDataWidget = sofa::gui::qt::GenericDataWidget; diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.cpp deleted file mode 100644 index a56e7dd1365..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -using sofa::helper::Creator; -using sofa::type::fixed_array; -using namespace sofa::type; -using namespace sofa::defaulttype; - -Creator > > > DWClass_mapvectorf("graph",true); -Creator > > > DWClass_mapvectord("graph",true); -Creator > > > DWClass_mapvector2d("graph",true); -Creator > > > DWClass_mapdequef("graph",true); -Creator > > > DWClass_mapdequed("graph",true); -Creator > > > DWClass_mapdeque2d("graph",true); - -Creator > > > DWLClass_mapvectorf("graph_linear",true); -Creator > > > DWLClass_mapvectord("graph_linear",true); -Creator > > > DWLClass_mapvector2d("graph_linear",true); -Creator > > > DWLClass_mapdequef("graph_linear",true); -Creator > > > DWLClass_mapdequed("graph_linear",true); -Creator > > > DWLClass_mapdeque2d("graph_linear",true); - - - -GraphOptionWidget::GraphOptionWidget(const std::string &dataName, GraphSetting *graphConf):graph(graphConf) -{ - QVBoxLayout *generalLayout = new QVBoxLayout(this); - generalLayout->setContentsMargins(0, 0, 0, 0); - generalLayout->setSpacing(0); - QWidget *gnuplotExport=new QWidget(this); - QHBoxLayout* gnuplotLayout = new QHBoxLayout(gnuplotExport); - exportGNUPLOTButton = new QPushButton(QString("GNUPLOT"), gnuplotExport); - - //Create field to enter the base name of the gnuplot files - fileGNUPLOTLineEdit = new QLineEdit(gnuplotExport); - findGNUPLOTFile = new QPushButton(QString("..."), gnuplotExport); - - std::string gnuplotDirectory; //=simulation::getSimulation()->gnuplotDirectory.getValue(); - if (gnuplotDirectory.empty()) - gnuplotDirectory=sofa::helper::system::SetDirectory::GetParentDir(sofa::helper::system::DataRepository.getFirstPath().c_str()) + "/"; - gnuplotDirectory += dataName; - fileGNUPLOTLineEdit->setText(QString(gnuplotDirectory.c_str())); - - gnuplotLayout->addWidget(exportGNUPLOTButton); - gnuplotLayout->addWidget(fileGNUPLOTLineEdit); - gnuplotLayout->addWidget(findGNUPLOTFile); - generalLayout->addWidget(gnuplotExport); - - connect(exportGNUPLOTButton, &QPushButton::clicked, this, &GraphOptionWidget::exportGNUPlot); - connect(findGNUPLOTFile, &QPushButton::clicked, this, &GraphOptionWidget::openFindFileDialog); - - QWidget *imageExport=new QWidget(this); - QHBoxLayout* imageLayout = new QHBoxLayout(imageExport); - - checkBox = new QCheckBox("Check the box to dump the graph at each edit of the data"); - - exportImageButton = new QPushButton(QString("Image"), imageExport); - //Create field to enter the base name of the gnuplot files - fileImageLineEdit = new QLineEdit(imageExport); - findImageFile = new QPushButton(QString("..."), imageExport); - - std::string imageDirectory; //=simulation::getSimulation()->gnuplotDirectory.getValue(); - if (imageDirectory.empty()) - imageDirectory=sofa::helper::system::SetDirectory::GetParentDir(sofa::helper::system::DataRepository.getFirstPath().c_str()) + "/"; - imageDirectory += dataName; - fileImageLineEdit->setText(QString(imageDirectory.c_str())); - - imageLayout->addWidget(exportImageButton); - imageLayout->addWidget(fileImageLineEdit); - imageLayout->addWidget(findImageFile); - generalLayout->addWidget(imageExport); - - connect(exportImageButton, &QPushButton::clicked, this, &GraphOptionWidget::exportImage); - connect(findImageFile, &QPushButton::clicked, this, &GraphOptionWidget::openFindFileDialog); - - generalLayout->addWidget(checkBox); - - idfile = 0; -} - -void GraphOptionWidget::openFindFileDialog() -{ - QLineEdit *fileLineEdit=0; - const QPushButton *button=(QPushButton*)sender(); - if (button == findGNUPLOTFile) fileLineEdit = fileGNUPLOTLineEdit; - - else if (button == findImageFile) fileLineEdit = fileImageLineEdit; - - const std::string filename(sofa::helper::system::SetDirectory::GetParentDir(sofa::helper::system::DataRepository.getFirstPath().c_str())); - std::string directory; - const QString s = getExistingDirectory ( this, filename.empty() ?NULL:filename.c_str(), "open directory dialog", "Choose a directory" ); - if (s.length() > 0) - { - directory = s.toStdString(); - if (directory.at(directory.size()-1) != '/') directory+="/"; - fileLineEdit->setText(directory.c_str()); - } -} -void GraphOptionWidget::exportGNUPlot() -{ - graph->exportGNUPlot(fileGNUPLOTLineEdit->text().toStdString()); -} - -void GraphOptionWidget::exportImage() -{ - const unsigned nbpad=5; - - std::stringstream ss; - ss << idfile; - const std::string idstring = ss.str(); - - const std::string pad(nbpad-idstring.length(),'0'); - idfile++; - if (idfile>99999) idfile = 0; - - std::string filename = fileImageLineEdit->text().toStdString(); - filename.append("_"); - filename.append(pad); - filename.append(idstring); - graph->exportImage(filename); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.h deleted file mode 100644 index 910a20bdbfb..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphDataWidget.h +++ /dev/null @@ -1,385 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "TableDataWidget.h" -#include "FileManagement.h" - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include - - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -using namespace QtCharts; -#endif - -namespace sofa::gui::qt -{ - -template -class QDataSeries : public QLineSeries -{ -protected: - const T* data0; -public: - typedef vector_data_trait trait; - typedef typename trait::value_type value_type; - typedef vector_data_trait vtrait; - typedef typename vtrait::value_type real_type; - QDataSeries() : data0(NULL) {} - QDataSeries(const QDataSeries& c) - : QLineSeries() - , data0(c.data0) - { - parseData(); - } - - void setData(const T* p) - { - data0 = p; - parseData(); - } - - virtual QLineSeries* copy() const { return new QDataSeries(*this); } - virtual sofa::Size size() const - { - if (data0 == NULL) - return 0; - else - return trait::size(*(data0)); - } - - virtual void parseData() - { - clear(); - m_xMin = m_yMin = 1000000000.0; - m_xMax = m_yMax = -1000000000.0; - - for (sofa::Index i = 0; i < this->size(); i++) - { - QPointF data = sample(i); - append(data); - - if (data.x() > m_xMax) - m_xMax = data.x(); - if (data.x() < m_xMin) - m_xMin = data.x(); - - if (data.y() > m_yMax) - m_yMax = data.y(); - if (data.y() < m_yMin) - m_yMin = data.y(); - } - } - - virtual QPointF sample (sofa::Index i) const - { - if (i >= size()) - return QPointF(); - else if (vtrait::size(*trait::get(*(data0), i)) < 2) - return QPointF(i, (double)(*vtrait::get(*trait::get(*(data0), i), 0))); - else - return QPointF((double)(*vtrait::get(*trait::get(*(data0), i), 0)), (double)(*vtrait::get(*trait::get(*(data0), i), 1))); - } - - real_type m_xMin, m_yMin; - real_type m_xMax, m_yMax; -}; - -class GraphSetting -{ -public: - virtual ~GraphSetting() {}; - virtual void exportGNUPlot(const std::string &baseFileName) const=0; - virtual void exportImage(const std::string &baseFileName) const=0; -}; - -class GraphOptionWidget: public QWidget -{ - Q_OBJECT -public: - - GraphOptionWidget(const std::string &dataName, GraphSetting *graphConf); -public slots: - - void openFindFileDialog(); - void exportGNUPlot(); - void exportImage(); -//MOC_SKIP_END - - bool isCheckedBox() { - return checkBox->isChecked(); - } - -protected: - unsigned idfile; - QPushButton* exportGNUPLOTButton; - QLineEdit *fileGNUPLOTLineEdit; - QPushButton* findGNUPLOTFile; - - QCheckBox * checkBox; - QPushButton* exportImageButton; - QLineEdit *fileImageLineEdit; - QPushButton* findImageFile; - - GraphSetting *graph; -}; - - - - -template -class GraphWidget: public GraphSetting -{ -public: - typedef DataType data_type; - typedef vector_data_trait trait; - typedef typename trait::value_type curve_type; - typedef QChartView Widget; - typedef QDataSeries CurveData; - - GraphWidget(QWidget *parent) - { - m_chart = new QChart(); - w = new QChartView(m_chart, parent); - w->setMinimumHeight(300); - - m_axisX = new QValueAxis(); - m_axisX->setRange(0, 100); - - m_axisY = new QValueAxis(); - m_chart->addAxis(m_axisX, Qt::AlignBottom); - m_chart->addAxis(m_axisY, Qt::AlignLeft); - m_chart->legend()->setAlignment(Qt::AlignBottom); - } - - virtual ~GraphWidget() {}; - - QWidget *getWidget() {return w;} - - void readFromData(const data_type& d0) - { - double minX = 1000000000.0; - double maxX = -1000000000.0; - double minY = 1000000000.0; - double maxY = -1000000000.0; - currentData=d0; - const data_type& d = currentData; - auto nbData = trait::size(d); - - for (int i = 0; i < nbData; ++i) - { - const curve_type* v = trait::get(d, i); - const char* name = trait::header(d, i); - QString sName; - if (name && *name) - sName = name; - else - sName = "Unknown_" + QString::number(m_curves.size()); - - auto itM = m_curves.find(sName); - CurveData* cdata; - if (itM != m_curves.end()) - { - cdata = itM->second; - } - else { - // new curve data to register and plot - cdata = new CurveData(); - m_curves[sName] = cdata; - - cdata->setName(sName); - cdata->setPen(QColor::fromHsv(255 * i / nbData, 255, 255)); - m_chart->addSeries(cdata); - - cdata->attachAxis(m_axisY); - cdata->attachAxis(m_axisX); - } - - cdata->setData(v); - // gather min and max over all curves - if(cdata->m_xMin < minX) minX = cdata->m_xMin; - if(cdata->m_xMax > maxX) maxX = cdata->m_xMax; - if(cdata->m_yMin < minY) minY = cdata->m_yMin; - if(cdata->m_yMax > maxY) maxY = cdata->m_yMax; - } - - m_axisX->setRange(minX, maxX); - m_axisY->setRange(minY, maxY); - } - - void exportGNUPlot(const std::string &baseFileName) const - { - const int n = trait::size(currentData); - for (int i=0; isize()); - QPainter *paint = new QPainter(&p); - w->render(paint); - - QFile* file = new QFile(QString::fromStdString(filename)); - file->open(QIODevice::WriteOnly); - p.save(file, "PNG"); - - std::cerr << "Export Image: " << filename << std::endl; - } - -protected: - std::string getCurveFilename(unsigned int idx) const - { - std::string name(trait::header(currentData,idx)); - std::replace(name.begin(),name.end(),' ', '_'); - return name; - } - - QChartView* w; - - /// Pointer to the chart Data - QChart *m_chart; - - /// x axis pointer - QValueAxis* m_axisX; - /// y axis pointer - QValueAxis* m_axisY; - - /// vector of series to be plotted - std::map m_curves; - - data_type currentData; -}; - - - -template -class graph_data_widget_container -{ -public: - typedef T data_type; - typedef GraphWidget Widget; - typedef QVBoxLayout Layout; - Widget* w; - GraphOptionWidget *options; - Layout* container_layout; - - - graph_data_widget_container() : w(NULL), options(NULL), container_layout(NULL) {} - - - bool createLayout( DataWidget* parent ) - { - if( parent->layout() != NULL || container_layout != NULL ) - { - return false; - } - container_layout = new Layout(parent); - return true; - } - - bool createLayout( QLayout* layout) - { - if ( container_layout != NULL ) return false; - container_layout = new Layout(); - layout->addItem(container_layout); - return true; - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool /*readOnly*/) - { - w = new Widget(parent); - options = new GraphOptionWidget(parent->getBaseData()->getName(),w); - w->readFromData(d); - return true; - } - void setReadOnly(bool /*readOnly*/) - { - } - void readFromData(const data_type& d0) - { - w->readFromData(d0); - if (options->isCheckedBox()) options->exportImage(); - } - void writeToData(data_type& /*d*/) - { - } - - void insertWidgets() - { - assert(container_layout); - container_layout->addWidget(w->getWidget()); - container_layout->addWidget(options); - } -}; - -template -class GraphDataWidget : public SimpleDataWidget > -{ -public: - typedef SimpleDataWidget > Inherit; - typedef sofa::core::objectmodel::Data MyData; -public: - GraphDataWidget(QWidget* parent,const char* name, MyData* d) : Inherit(parent,name,d) {} - virtual unsigned int sizeWidget() {return 8;} - virtual unsigned int numColumnWidget() {return 1;} -}; - -template -class GraphDataWidget_Linear : public GraphDataWidget< T > -{ -public: - typedef sofa::core::objectmodel::Data MyData; - GraphDataWidget_Linear(QWidget* parent,const char* name, MyData* d) : GraphDataWidget (parent,name,d) { } - virtual bool createWidgets() - { - const bool b = GraphDataWidget::createWidgets(); - //typename GraphWidget::Widget* w = dynamic_cast::Widget*>(this->container.w->getWidget()); - //if (w) - //{ - // w->setAxisScaleEngine(GraphWidget::Widget::yLeft, new QwtLinearScaleEngine); - //} - return b; - } -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp deleted file mode 100644 index 0a57b822880..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "GraphListenerQListView.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using sofa::component::sceneutility::InfoComponent ; - -#include "resources/icons/iconmultinode.xpm" -#include "resources/icons/iconnode.xpm" -#include "resources/icons/iconinfo.xpm" -#include "resources/icons/iconwarning.xpm" -#include "resources/icons/iconerror.xpm" -#include "resources/icons/icondata.xpm" -#include "resources/icons/iconsleep.xpm" - - -#include -using sofa::helper::logging::Message ; - -using namespace sofa::core::objectmodel; - -namespace sofa::gui::qt -{ - - - -//*********************************************************************************************************** - -static const int iconWidth=8; -static const int iconHeight=16; -static const int iconMargin=6; - -static int hexval(char c) -{ - if (c>='0' && c<='9') return c-'0'; - else if (c>='a' && c<='f') return (c-'a')+10; - else if (c>='A' && c<='F') return (c-'A')+10; - else return 0; -} - -const std::string getClass(core::objectmodel::Base* obj){ - if (obj->toBaseNode()) - { - return "Node"; - } - if (obj->toBaseObject()) - { - if (obj->toContextObject()) - return "Context"; - if (obj->toBehaviorModel()) - return "BehaviorModel"; - if (obj->toCollisionModel()) - return "CollisionModel"; - if (obj->toBaseMechanicalState()) - return "MechanicalModel"; - if (obj->toBaseProjectiveConstraintSet()) - return "ProjectiveConstraintSet"; - if (obj->toBaseConstraintSet()) - return "BaseConstraintSet"; - if (obj->toBaseInteractionForceField() && - obj->toBaseInteractionForceField()->getMechModel1()!=obj->toBaseInteractionForceField()->getMechModel2()) - return "InteractionForceField"; - if (obj->toBaseForceField()) - return "ForceField"; - if (obj->toBaseAnimationLoop() - || obj->toOdeSolver()) - return "Solver"; - if (obj->toPipeline() - || obj->toIntersection() - || obj->toDetection() - || obj->toContactManager() - || obj->toCollisionGroupManager()) - return "Collision"; - if (obj->toBaseMapping()) - return "Mapping"; - if (obj->toBaseMass()) - return "Mass"; - if (obj->toTopology () - || obj->toBaseTopologyObject() ) - return "Topology"; - if (obj->toBaseLoader()) - return "Loader"; - if (obj->toConfigurationSetting()) - return "Configuration"; - if (obj->toVisualModel()) - return "Visual"; - } - return "Other"; -} - - - -QPixmap* getPixmap(core::objectmodel::Base* obj, bool haveInfo, bool haveWarning, bool haveErrors) -{ - static QPixmap pixInfo(reinterpret_cast(iconinfo_xpm)); - static QImage imgInfo8 = pixInfo.scaledToWidth(16).toImage(); - - static QPixmap pixError(reinterpret_cast(iconerror_xpm)); - static QImage imgError8 = pixError.scaledToWidth(16).toImage(); - - static QPixmap pixWarning(reinterpret_cast(iconwarning_xpm)); - static QImage imgWarning8 = pixWarning.scaledToWidth(16).toImage(); - - - using namespace sofa::simulation::Colors; - unsigned int flags = 0; - - if (obj->toBaseNode()) - { - - const char** icon = reinterpret_cast(iconsleep_xpm); - if( !obj->toBaseNode()->getContext()->isSleeping() ){ - icon = reinterpret_cast(iconnode_xpm) ; - flags = 1 ; - } - - if(haveInfo) - flags |= 1 << (2) ; - - if(haveWarning) - flags |= 1 << (3) ; - - if(haveErrors) - flags |= 1 << (4) ; - - static std::map pixmaps; - if (!pixmaps.count(flags)) - { - /// Create a new image from pixmap - const QImage timg(icon) ; - QImage* img = new QImage(timg.convertToFormat(QImage::Format_ARGB32)) ; - - const QImage* overlaysymbol=nullptr; - if( haveInfo ) - overlaysymbol = &imgInfo8 ; - if( haveWarning ) - overlaysymbol = &imgWarning8 ; - if( haveErrors ) - overlaysymbol = &imgError8 ; - - if(overlaysymbol){ - for (int x=0;x<16;x++) - { - for(int y=0;y<16;y++) - { - if( qAlpha(overlaysymbol->pixel(x,y)) == 255 ){ - img->setPixel(x, y, overlaysymbol->pixel(x,y) ); - } - } - } - } - pixmaps[flags] = new QPixmap(QPixmap::fromImage(*img)); - } - - return pixmaps[flags] ; - } - else if (obj->toBaseObject()) - { - if (obj->toContextObject()) - flags |= 1 << CONTEXT; - if (obj->toBehaviorModel()) - flags |= 1 << BMODEL; - if (obj->toCollisionModel()) - flags |= 1 << CMODEL; - if (obj->toBaseMechanicalState()) - flags |= 1 << MMODEL; - if (obj->toBaseProjectiveConstraintSet()) - flags |= 1 << PROJECTIVECONSTRAINTSET; - if (obj->toBaseConstraintSet()) - flags |= 1 << CONSTRAINTSET; - if (obj->toBaseInteractionForceField() && - obj->toBaseInteractionForceField()->getMechModel1()!=obj->toBaseInteractionForceField()->getMechModel2()) - flags |= 1 << IFFIELD; - else if (obj->toBaseForceField()) - flags |= 1 << FFIELD; - if (obj->toBaseAnimationLoop() - || obj->toOdeSolver()) - flags |= 1 << SOLVER; - if (obj->toPipeline() - || obj->toIntersection() - || obj->toDetection() - || obj->toContactManager() - || obj->toCollisionGroupManager()) - flags |= 1 << COLLISION; - if (obj->toBaseMapping()) - flags |= 1 << ((obj->toBaseMapping())->isMechanical()?MMAPPING:MAPPING); - if (obj->toBaseMass()) - flags |= 1 << MASS; - if (obj->toTopology () - || obj->toBaseTopologyObject() ) - flags |= 1 << TOPOLOGY; - if (obj->toBaseLoader()) - flags |= 1 << LOADER; - if (obj->toConfigurationSetting()) - flags |= 1 << CONFIGURATIONSETTING; - if (obj->toVisualModel() && !flags) - flags |= 1 << VMODEL; - if (!flags) - flags |= 1 << OBJECT; - } - else return nullptr; - - if(haveInfo) - flags |= 1 << (ALLCOLORS+1) ; - - if(haveWarning) - flags |= 1 << (ALLCOLORS+2) ; - - if(haveErrors) - flags |= 1 << (ALLCOLORS+3) ; - - static std::map pixmaps; - if (!pixmaps.count(flags)) - { - int nc = 0; - for (int i=0; ifill(qRgba(0,0,0,0)); - // Workaround for qt 3.x where fill() does not set the alpha channel - for (int y=0 ; y < iconHeight ; y++) - for (int x=0 ; x < nx ; x++) - img->setPixel(x,y,qRgba(0,0,0,0)); - - // left Line - for (int y=iconMargin ; y < iconHeight ; y++) - img->setPixel(0,y,qRgba(0,0,0,255)); - - nc = 0; - for (int i=0; isetPixel(x,iconMargin-1,qRgba(0,0,0,255)); - img->setPixel(x,iconHeight-1,qRgba(0,0,0,255)); - for (int y=iconMargin ; y < iconHeight-1 ; y++) - img->setPixel(x,y,qRgba(r,g,b,a)); - } - ++nc; - } - - // right line Line - for (int y=iconMargin ; y < iconHeight ; y++) - img->setPixel(2+iconWidth*nc-1,y,qRgba(0,0,0,255)); - - const QImage* overlaysymbol=nullptr; - if( haveInfo ) - overlaysymbol = &imgInfo8 ; - if( haveWarning ) - overlaysymbol = &imgWarning8 ; - if( haveErrors ) - overlaysymbol = &imgError8 ; - - if(overlaysymbol){ - for (int x=0;x<16;x++) - { - for(int y=0;y<16;y++) - { - if( qAlpha(overlaysymbol->pixel(x,y)) == 255 ) - img->setPixel(x, y, overlaysymbol->pixel(x,y) ); - } - } - } - - pixmaps[flags] = new QPixmap(QPixmap::fromImage(*img)); - - delete img; - } - return pixmaps[flags]; -} - -void setMessageIconFrom(QTreeWidgetItem* item, Base* object) -{ - const bool haveInfos = object->countLoggedMessages({Message::Info, Message::Deprecated, Message::Advice})!=0; - const bool haveWarnings = object->countLoggedMessages({Message::Warning})!=0; - const bool haveErrors = object->countLoggedMessages({Message::Error, Message::Fatal})!=0; - - const QPixmap* pix = getPixmap(object, haveInfos, haveWarnings, haveErrors); - if (pix) - item->setIcon(0, QIcon(*pix)); -} - -ObjectStateListener::ObjectStateListener( - QTreeWidgetItem* item_, - sofa::core::objectmodel::Base* object_) : item(item_), object(object_) -{ - // We want the view to react to a change in the message log - object->d_messageLogCount.addOutput(this); - - // We want the view to react to a change in the name - object->name.addOutput(this); -} - -ObjectStateListener::~ObjectStateListener() -{ - object->d_messageLogCount.delOutput(this); - object->name.delOutput(this); -} - -void ObjectStateListener::update() {} -void ObjectStateListener::notifyEndEdit() -{ - setMessageIconFrom(item, object.get()); - - const QString oldName = item->text(0); - const QString newName = QString::fromStdString(object->getName()); - if(newName != oldName) - item->setText(0, newName); -} - -GraphListenerQListView::~GraphListenerQListView() -{ - for(auto [key, listener] : listeners) - { - delete listener; - } - listeners.clear(); -} - -/*****************************************************************************************************************/ -QTreeWidgetItem* GraphListenerQListView::createItem(QTreeWidgetItem* parent) -{ - if(parent->childCount() == 0) - return new QTreeWidgetItem(parent); - return new QTreeWidgetItem(parent, parent->child(parent->childCount()-1)); -} - -/*****************************************************************************************************************/ -void GraphListenerQListView::onBeginAddChild(Node* parent, Node* child) -{ - if (widget->isLocked()) - { - widget->setViewToDirty(); - return; - } - if (items.count(child)) - { - QTreeWidgetItem* item = items[child]; - if (item->treeWidget() == nullptr) - { - if (parent == nullptr) - { - dmsg_info("GraphListenerQListView") << "CREATING TOP LEVEL NODE '"<getName()<<"'"; - widget->insertTopLevelItem(0, item); - } - else if (items.count(parent)) - { - items[parent]->insertChild(0, item); - } - else - { - dmsg_error("GraphListenerQListView") << "Unknown parent node '"<getName()<<"'"; - return; - } - } - else - { - static QPixmap pixMultiNode(reinterpret_cast(iconmultinode_xpm)); - - // Node with multiple parents - if (parent && - parent != findObject(item->parent()) ) - { - // check that the multinode have not been added yet - // i.e. verify that all every item equivalent to current 'item' (in nodeWithMultipleParents) do not have the same 'parent' - std::multimap::iterator it=nodeWithMultipleParents.lower_bound(item), itend=nodeWithMultipleParents.upper_bound(item); - for ( ; it!=itend && it->second->parent() != items[parent] ; ++it); - if( it==itend ) - { - QTreeWidgetItem* itemNew = createItem(items[parent]); - //itemNew->setDropEnabled(true); - // QString name=QString("MultiNode ") + QString(child->getName().c_str()); - // itemNew->setText(0, name); - itemNew->setText(0, child->getName().c_str()); - nodeWithMultipleParents.insert(std::make_pair(item, itemNew)); - itemNew->setIcon(0, QIcon(pixMultiNode)); - - // this is one more parent, the first child item must be displayed as a multinode - { - item->setIcon(0, QIcon(pixMultiNode)); - } - } - } - } - } - else - { - QTreeWidgetItem* item; - if (parent == nullptr) - item = new QTreeWidgetItem(widget); - else if (items.count(parent)) - { - item = createItem(items[parent]); - } - else - { - dmsg_error("GraphListenerQListView") << "Unknown parent node '"<getName()<<"'"; - return; - } - - item->setText(0, child->getName().c_str()); - item->setText(1, child->getClassName().c_str()); - item->setForeground(1, nameColor); - QFont font = QApplication::font(); - font.setBold(true); - item->setFont(0, font); - setMessageIconFrom(item, child); - - item->setExpanded(true); - items[child] = item; - - // Add a listener to connect changes on the component state with its graphical view. - listeners[child] = new ObjectStateListener(item, child); - } - - for (BaseObject::SPtr obj : child->object) - onBeginAddObject(child, obj.get()); - for (Node::SPtr node : child->child) - onBeginAddChild(child, node.get()); -} - -/*****************************************************************************************************************/ -void GraphListenerQListView::onBeginRemoveChild(Node* parent, Node* child) -{ - SOFA_UNUSED(parent); - for (Node::ObjectIterator it = child->object.begin(); it != child->object.end(); ++it) - onBeginRemoveObject(child, it->get()); - for (Node::ChildIterator it = child->child.begin(); it != child->child.end(); ++it) - onBeginRemoveChild(child, it->get()); - - if (items.count(child)) - { - delete items[child]; - delete listeners[child]; - items.erase(child); - listeners.erase(child); - } -} - - -/*****************************************************************************************************************/ -void GraphListenerQListView::onBeginAddObject(Node* parent, core::objectmodel::BaseObject* object) -{ - if(widget->isLocked()) - { - widget->setViewToDirty(); - return; - } - if (items.count(object)) - { - QTreeWidgetItem* item = items[object]; - if (item->treeWidget() == nullptr) - { - if (items.count(parent)) - // items[parent]->insertItem(item); - items[parent]->addChild(item); - else - { - dmsg_error("GraphListenerQListView") << "Unknown parent node " << parent->getName()<< "'"; - return; - } - } - } - else - { - QTreeWidgetItem* item; - if (items.count(parent)) - item = createItem(items[parent]); - else - { - dmsg_error("GraphListenerQListView") << "Unknown parent node " << parent->getName()<< "'"; - return; - } - - std::string name; - if(dynamic_cast(object)) - { - name = object->getName() ; - }else if(dynamic_cast(object)){ - name = object->getClassName() ; - }else - { - name = object->getName() ; - item->setText(1, object->getClassName().c_str()); - item->setForeground(1, nameColor); - const QString tooltip( ("Name: " + name + "\nClass Name: " + object->getClassName()).c_str()); - item->setToolTip(0, tooltip); - item->setToolTip(1, tooltip); - } - - item->setText(0, name.c_str()); - - setMessageIconFrom(item, object); - - items[object] = item; - listeners[object] = new ObjectStateListener(item, object); - } - for (BaseObject::SPtr slave : object->getSlaves()) - onBeginAddSlave(object, slave.get()); -} - - -/*****************************************************************************************************************/ -void GraphListenerQListView::onBeginRemoveObject(Node* parent, core::objectmodel::BaseObject* object) -{ - SOFA_UNUSED(parent); - for (BaseObject::SPtr slave : object->getSlaves()) - onBeginRemoveSlave(object, slave.get()); - - if (items.count(object)) - { - delete items[object]; - items.erase(object); - - delete listeners[object]; - listeners.erase(object); - } -} - - -/*****************************************************************************************************************/ -void GraphListenerQListView::onBeginAddSlave(core::objectmodel::BaseObject* master, core::objectmodel::BaseObject* slave) -{ - if(widget->isLocked()) - { - widget->setViewToDirty(); - return; - } - if (items.count(slave)) - { - QTreeWidgetItem* item = items[slave]; - if (item->treeWidget() == nullptr) - { - if (items.count(master)) - // items[master]->insertItem(item); - items[master]->addChild(item); - else - { - dmsg_error("GraphListenerQListView") << "Unknown master node '"<getName()<<"'"; - return; - } - } - } - else - { - QTreeWidgetItem* item; - if (items.count(master)) - item = createItem(items[master]); - else - { - dmsg_error("GraphListenerQListView") << "Unknown master node '"<getName()<<"'"; - return; - } - std::string className = sofa::helper::gettypename(typeid(*slave)); - if (const std::string::size_type pos = className.find('<'); pos != std::string::npos) - className.erase(pos); - if (!slave->toConfigurationSetting()) - { - const auto& name = slave->getName(); - item->setText(0, name.c_str()); - item->setForeground(1, nameColor); - - const QString tooltip( ("Name: " + name + "\nClass Name: " + className).c_str()); - item->setToolTip(0, tooltip); - item->setToolTip(1, tooltip); - } - item->setText(1, className.c_str()); - - setMessageIconFrom(item, slave); - - items[slave] = item; - } - - const core::objectmodel::BaseObject::VecSlaves& slaves = slave->getSlaves(); - for (unsigned int i=0; igetSlaves(); - for (unsigned int i=0; isetIcon(0, QIcon(*pix)); - } -} - -/*****************************************************************************************************************/ -core::objectmodel::Base* GraphListenerQListView::findObject(const QTreeWidgetItem* item) -{ - core::objectmodel::Base* base = nullptr; - - if(item) - { - for ( std::map::iterator it = items.begin() ; it != items.end() ; ++ it ) - { - if ( ( *it ).second == item ) - { - base = (*it).first; - return base; - } - } - } - if (!base) //Can be a multi node - { - std::multimap::iterator it; - for (it=nodeWithMultipleParents.begin(); it!=nodeWithMultipleParents.end(); ++it) - { - if (it->second == item) return findObject(it->first); - } - } - return base; -} - -/*****************************************************************************************************************/ -core::objectmodel::BaseData* GraphListenerQListView::findData(const QTreeWidgetItem* item) -// returns nullptr if nothing is found. -{ - BaseData* data = nullptr; - if(item) - { - std::map::const_iterator it; - for( it = datas.begin(); it != datas.end(); ++it) - { - if((*it).second == item) - { - data = (*it).first; - } - } - } - return data; -} -/*****************************************************************************************************************/ -void GraphListenerQListView::removeDatas(core::objectmodel::BaseObject* parent) -{ - if (widget->isLocked()) - { - widget->setViewToDirty(); - return; - } - - BaseData* data = nullptr; - std::string name; - - if( items.count(parent) ) - { - const sofa::core::objectmodel::Base::VecData& fields = parent->getDataFields(); - for( sofa::core::objectmodel::Base::VecData::const_iterator it = fields.begin(); - it != fields.end(); - ++it) - { - data = (*it); - if(datas.count(data)) - { - delete datas[data]; - datas.erase(data); - } - } - } -} - -/*****************************************************************************************************************/ -void GraphListenerQListView::addDatas(sofa::core::objectmodel::BaseObject *parent) -{ - if (widget->isLocked()) - { - widget->setViewToDirty(); - return; - } - - QTreeWidgetItem* new_item; - std::string name; - BaseData* data = nullptr; - if(items.count(parent)) - { - const sofa::core::objectmodel::Base::VecData& fields = parent->getDataFields(); - for( sofa::core::objectmodel::Base::VecData::const_iterator it = fields.begin(); - it!=fields.end(); - ++it) - { - data = (*it); - if(!datas.count(data)) - { - static QPixmap pixData(reinterpret_cast(icondata_xpm)); - new_item = createItem(items[parent]); - name += " "; - name += data->getName(); - datas.insert(std::pair(data,new_item)); - new_item->setText(0, name.c_str()); - new_item->setIcon(0, QIcon(pixData)); - // widget->ensureItemVisible(new_item); - widget->scrollToItem(new_item); - name.clear(); - } - } - } -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.h deleted file mode 100644 index cf6aa376848..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphListenerQListView.h +++ /dev/null @@ -1,96 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ -using sofa::simulation::Node; -using sofa::simulation::MutationListener; - -QPixmap* getPixmap(core::objectmodel::Base* obj, bool, bool,bool); - - -/// A listener to connect changes on the component state with its graphical view. -/// The listener is added to the ComponentState of an object to track changes to -/// and update the icon/treewidgetitem when this happens. -class ObjectStateListener : public sofa::core::objectmodel::DDGNode -{ -public: - QTreeWidgetItem* item; - - // Use a SPtr here because otherwise sofa may decide to remove the base without notifying the ObjectStateListener - // is going to a segfault the right way. - sofa::core::objectmodel::Base::SPtr object; - - ObjectStateListener(QTreeWidgetItem* item_, sofa::core::objectmodel::Base* object_); - ~ObjectStateListener() override; - void update() override; - void notifyEndEdit() override; -}; - - -class SOFA_GUI_QT_API GraphListenerQListView : public MutationListener -{ -public: - SofaSceneGraphWidget* widget; - std::map listeners; - std::map items; - std::map datas; - std::multimap nodeWithMultipleParents; - - GraphListenerQListView(SofaSceneGraphWidget* w) - : widget(w) - { - } - ~GraphListenerQListView() override; - - /*****************************************************************************************************************/ - QTreeWidgetItem* createItem(QTreeWidgetItem* parent); - virtual void onBeginAddChild(Node* parent, Node* child) override; - virtual void onBeginRemoveChild(Node* parent, Node* child) override; - virtual void onBeginAddObject(Node* parent, core::objectmodel::BaseObject* object) override; - virtual void onBeginRemoveObject(Node* /*parent*/, core::objectmodel::BaseObject* object) override; - virtual void onBeginAddSlave(core::objectmodel::BaseObject* master, core::objectmodel::BaseObject* slave) override; - virtual void onBeginRemoveSlave(core::objectmodel::BaseObject* master, core::objectmodel::BaseObject* slave) override; - - virtual void sleepChanged(Node* node) override; - virtual void addDatas(core::objectmodel::BaseObject* parent); - virtual void removeDatas(core::objectmodel::BaseObject* parent); - core::objectmodel::Base* findObject(const QTreeWidgetItem* item); - core::objectmodel::BaseData* findData(const QTreeWidgetItem* item); - - inline static QColor nameColor { 120, 120, 120}; -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.cpp deleted file mode 100755 index 83e7b0492c7..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "GraphVisitor.h" - -#include - -#include - -#include - -#include -#include - - -namespace sofa::gui::qt -{ - -typedef sofa::helper::system::thread::CTime CTime; - -bool cmpTime(const dataTime &a, const dataTime &b) { return a.time > b.time;} -bool GraphVisitor::load(std::string &file) -{ - //Open it using TinyXML - tinyxml2::XMLDocument doc; - doc.Parse(file.c_str()); - - //std::cerr << "GRAPH:"<< std::endl << file << std::endl; - - tinyxml2::XMLHandle hDoc(&doc); - tinyxml2::XMLNode* pElem; - //Getting the root of the file - pElem=hDoc.FirstChildElement().ToElement(); - - // should always have a valid root but handle gracefully if it does - if (!pElem) return false; - - totalTime = getTotalTime(pElem); - - componentsTime.clear(); - visitorsTime.clear(); - - - openNode( pElem, NULL, NULL); - - - std::sort(componentsTime.begin(),componentsTime.end(),cmpTime); - std::sort(visitorsTime.begin(),visitorsTime.end(),cmpTime); - - std::sort(componentsTimeTotal.begin(),componentsTimeTotal.end(),cmpTime); - std::sort(visitorsTimeTotal.begin(),visitorsTimeTotal.end(),cmpTime); - - - if (totalTimeMaxpieChart->setChart(visitorsTime, visitorsTime.size()); - window->setCharts(componentsTime,componentsTimeMax,componentsTimeTotal, - visitorsTime,visitorsTimeMax,visitorsTimeTotal); - - if (!initSize) - { - const int sizeLeft = window->graphView->columnWidth(0)+window->graphView->columnWidth(1)+7; - - QList< int > listSize; - listSize << sizeLeft - << window->statsWidget->width()-(sizeLeft-window->graphView->width()); - window->splitterStats->setSizes(listSize); - initSize=true; - } - return true; -} - - -void GraphVisitor::openAttribute ( tinyxml2::XMLElement* element, QTreeWidgetItem* item) -{ - if (!element) return; - const tinyxml2::XMLAttribute* attribute=element->FirstAttribute(); - while (attribute) - { - std::string nameOfAttribute(attribute->Name()); - std::string valueOfAttribute(attribute->Value()); - addInformation(item, nameOfAttribute, valueOfAttribute); - attribute=attribute->Next(); - } - -} - - - -void GraphVisitor::openTime ( tinyxml2::XMLNode* node, QTreeWidgetItem* item) -{ - tinyxml2::XMLElement* element=node->ToElement(); - if (!element) return; - const tinyxml2::XMLAttribute* attribute=element->FirstAttribute(); - double timeSec= getTime(attribute); - double time = 100.0*timeSec/totalTime; - std::ostringstream s; - s.setf(std::ios::fixed, std::ios::floatfield); - s.precision(3); - - s << time << "%"; - - tinyxml2::XMLNode* parent = node->Parent(); - if (parent) - { - std::string nodeType = parent->Value(); - if (nodeType == "Component") - { - const tinyxml2::XMLAttribute* attribute=parent->ToElement()->FirstAttribute(); - std::string componentName, componentType, componentPtr; - while (attribute) - { - std::string nameOfAttribute(attribute->Name()); - std::string valueOfAttribute(attribute->Value()); - if (nameOfAttribute=="name") - componentName=valueOfAttribute; - else if (nameOfAttribute=="type") - componentType=valueOfAttribute; - else if (nameOfAttribute=="ptr") - componentPtr=valueOfAttribute; - attribute=attribute->Next(); - } - if (std::find(visitedNode.begin(), visitedNode.end(), componentName) == visitedNode.end()) - { - dataTime t(timeSec-timeComponentsBelow.back() - , componentType, componentName, componentPtr); - std::vector< dataTime >::iterator it=std::find(componentsTime.begin(),componentsTime.end(),t); - if (it != componentsTime.end()) it->time += t.time; - else componentsTime.push_back(t); - - - it=std::find(componentsTimeTotal.begin(),componentsTimeTotal.end(),t); - if (it != componentsTimeTotal.end()) it->time += t.time; - else componentsTimeTotal.push_back(t); - - - visitedNode.push_back(componentName); - } - } - else - { - if (nodeType != "Node" && nodeType != "Input" && nodeType != "Output" && nodeType != "Vector" && - std::find(visitedNode.begin(), visitedNode.end(),nodeType) == visitedNode.end()) - { - dataTime t(timeSec, nodeType); - std::vector< dataTime >::iterator it=std::find(visitorsTime.begin(),visitorsTime.end(),t); - if (it != visitorsTime.end()) it->time += timeSec; - else visitorsTime.push_back(t); - - it=std::find(visitorsTimeTotal.begin(),visitorsTimeTotal.end(),t); - if (it != visitorsTimeTotal.end()) it->time += t.time; - else visitorsTimeTotal.push_back(t); - - - visitedNode.push_back(nodeType); - } - } - - if (nodeType == "Node" || nodeType == "Component" || nodeType.rfind("Visitor") == nodeType.size()-7) - timeComponentsBelow.back() = timeSec; - } - - addTime(item, s.str()); -} - -double GraphVisitor::getTime(const tinyxml2::XMLAttribute* attribute) const -{ - static double conversion=1.0/(double)CTime::getTicksPerSec(); - std::string valueOfAttribute(attribute->Value()); - double result=1000.0*atof(valueOfAttribute.c_str())*conversion; - return result; -} - -double GraphVisitor::getTotalTime(tinyxml2::XMLNode* node) const -{ - - for ( tinyxml2::XMLNode* child = node->FirstChild(); child != 0; child = child->NextSibling()) - { - std::string nameOfNode=child->Value(); - if (nameOfNode == "TotalTime") - { - const tinyxml2::XMLAttribute* attribute=child->ToElement()->FirstAttribute(); - double total=getTime(attribute); - std::ostringstream out; out << total; - child->ToElement()->SetAttribute(attribute->Name(),out.str().c_str()); - return total; - } - } - return 1; -} - -QTreeWidgetItem* GraphVisitor::openNode( tinyxml2::XMLNode* node, QTreeWidgetItem* parent, QTreeWidgetItem* elementAbove) -{ - if (!node) return NULL; - - unsigned int sizeVisitedNode=visitedNode.size(); - std::string nameOfNode=node->Value(); - // TinyXml API changed in 2.6.0, ELEMENT was replaced with TINYXML_ELEMENT - // As the version number is not available as a macro, the most portable was is to - // replace these constants with checks of the return value of ToElement(), ... - // -- Jeremie A. 02/07/2011 - //int typeOfNode=node->Type(); - QTreeWidgetItem *graphNode=NULL; - if (node->ToDocument()) // case tinyxml2::XMLNode::DOCUMENT: - { - } - else if (node->ToElement()) // case tinyxml2::XMLNode::ELEMENT: - { - if (nameOfNode == "Time") - { - openTime( node, parent); - } - else - { - graphNode = addNode(parent, elementAbove, nameOfNode); - openAttribute( node->ToElement(), graphNode); - } - } - else if (node->ToComment()) // case tinyxml2::XMLNode::COMMENT: - { - graphNode = addComment(parent, elementAbove, nameOfNode); - } - else if (node->ToText()) // case tinyxml2::XMLNode::TEXT: - { - } - else if (node->ToDeclaration()) // case tinyxml2::XMLNode::DECLARATION: - { - } - else // default: - { - } - - QTreeWidgetItem *element=NULL; - timeComponentsBelow.push_back(0); - - for ( tinyxml2::XMLNode* child = node->FirstChild(); child != 0; child = child->NextSibling()) - { - element = openNode( child, graphNode, element); - } - double t=timeComponentsBelow.back(); - - timeComponentsBelow.pop_back(); - - if (!timeComponentsBelow.empty()) timeComponentsBelow.back() += t; - - if (sizeVisitedNode != visitedNode.size()) visitedNode.resize(sizeVisitedNode); - return graphNode; -} - - -QTreeWidgetItem *GraphVisitor::addNode(QTreeWidgetItem *parent, QTreeWidgetItem *elementAbove, std::string name) -{ - QTreeWidgetItem *item=NULL; - if (!parent) - { - //Add a Root - item=new QTreeWidgetItem(graph); - item->setText(0, QString(name.c_str())); - item->setExpanded(true); - } - else - { - //Add a child to a node - item=new QTreeWidgetItem(parent,elementAbove); - item->setText(0, QString(name.c_str())); - } - QPixmap* icon=WindowVisitor::getPixmap(WindowVisitor::getComponentType(name)); - if (icon) item->setIcon(0,QIcon(*icon)); - //item->setMultiLinesEnabled(true); - return item; -} - -void GraphVisitor::addTime(QTreeWidgetItem *element, std::string info) -{ - if (!element) return; - element->setText(1, QString( info.c_str())); -} - -void GraphVisitor::addInformation(QTreeWidgetItem *element, std::string name, std::string info) -{ - if (!element) return; - if (element->text(0) == QString("Node")) - element->setText(0, QString(info.c_str())); - else if (element->text(0) == QString("Component")) - element->setText(0, QString(info.c_str())); - else - { - - QString nameQt = element->text(2); - QString infoQt = element->text(3); - if (!nameQt.isEmpty()) - { - nameQt += QString("\n"); - infoQt += QString("\n"); - } - - if (element->text(0) == QString("Vector") && name=="value" && !info.empty()) - { - std::istringstream ss(info); - std::ostringstream result; - unsigned int size; ss >> size; - while (!ss.eof()) - { - result << "["; - for (unsigned int i=0; i> v; - result << v; - if (i!=size-1) result << " "; - } - result << "]\n"; - } - info = result.str(); - } - - nameQt += QString(name.c_str()); - infoQt += QString(info.c_str()); - - if (name != "ptr") - { - element->setText(2, nameQt); - element->setText(3, infoQt); - } - } -} - -QTreeWidgetItem *GraphVisitor::addComment(QTreeWidgetItem *element,QTreeWidgetItem *elementAbove, std::string comment) -{ - if (!element) return NULL; - QTreeWidgetItem *result = new QTreeWidgetItem(element, elementAbove); - result->setIcon(0,QIcon(*WindowVisitor::getPixmap(WindowVisitor::COMMENT))); - result->setText(1, QString(comment.c_str())); - //result->setSelectable(false); - result->setFlags(Qt::ItemIsEnabled); - //result->setMultiLinesEnabled(true); - return result; -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.h b/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.h deleted file mode 100755 index 4e056e87a13..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/GraphVisitor.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -//#include - -#include -#include - -namespace sofa::gui::qt -{ - -class GraphVisitor -{ -public: - GraphVisitor(WindowVisitor *w) { window=w; graph=w->graphView; totalTimeMax=-1; initSize=false;} - QTreeWidgetItem *addNode(QTreeWidgetItem *parent,QTreeWidgetItem *elementAbove, std::string info); - QTreeWidgetItem *addComment(QTreeWidgetItem *element, QTreeWidgetItem *elementAbove, std::string comment); - void addInformation(QTreeWidgetItem *element, std::string name, std::string info); - void addTime(QTreeWidgetItem *element, std::string info); - - bool load(std::string &file); - - void setGraph(QTreeWidget* g) {graph = g;} - void clear() {graph->clear();} - - double getTotalTime(tinyxml2::XMLNode* node) const; - inline double getTime(const tinyxml2::XMLAttribute* attribute) const; - -protected: - void openTime ( tinyxml2::XMLNode* element, QTreeWidgetItem* item); - void openAttribute ( tinyxml2::XMLElement* element, QTreeWidgetItem* item); - QTreeWidgetItem* openNode( tinyxml2::XMLNode* node, QTreeWidgetItem* parent, QTreeWidgetItem* elementAbove); - - QTreeWidget *graph; - WindowVisitor *window; - - double totalTime; - double totalTimeMax; - - std::vector timeComponentsBelow; - int level; - - std::vector< dataTime > componentsTime; - std::vector< dataTime > visitorsTime; - - std::vector< dataTime > componentsTimeTotal; - std::vector< dataTime > visitorsTimeTotal; - - std::vector< dataTime > componentsTimeMax; - std::vector< dataTime > visitorsTimeMax; - - std::vector< std::string > visitedNode; - - bool initSize; -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.cpp deleted file mode 100644 index bdca3c99bcf..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#define SOFA_GUI_QT_LINKWIDGET_CPP - -#include "LinkWidget.h" -#include "ModifyObject.h" -#include - -#include - -#define SIZE_TEXT 60 - -namespace sofa::gui::qt -{ - -LinkWidget *LinkWidget::CreateLinkWidget(const LinkWidget::CreatorArgument &/*dwarg*/) -{ - return nullptr; // TODO -} - -/*QDisplayLinkInfoWidget definitions */ - -QDisplayLinkInfoWidget::QDisplayLinkInfoWidget(QWidget* parent, const std::string& helper, - core::objectmodel::BaseLink* l, bool /*modifiable*/) - : QWidget(parent), link(l), numLines_(1) -{ - QHBoxLayout* layout = new QHBoxLayout(this); - - layout->setContentsMargins(0,0,0,0); - - std::string final_str; - formatHelperString(helper,final_str); - - const core::objectmodel::BaseClass* ownerClass=link->getOwnerClass(); - std::string ownerClassName; - if (ownerClass) ownerClassName = ownerClass->className; - - /* -#ifndef SOFA_GUI_QT_NO_DATA_HELP - QLabel* helper_label = new QLabel(this); - helper_label->setText(QString(final_str.c_str())); - helper_label->setMinimumWidth(20); - layout->addWidget(helper_label); - if (!ownerClassName.empty()) QToolTip::add(helper_label, ("Link from "+ownerClassName).c_str()); -#else - numLines_ = 0; - if (!final_str.empty() || !ownerClassName.empty()) - { - if (!final_str.empty()) final_str += '\n'; - final_str += "Link from "; - final_str += ownerClassName; - QToolTip::add(parent, final_str.c_str()); - } -#endif - */ -} - -void QDisplayLinkInfoWidget::formatHelperString(const std::string& helper, std::string& final_text) -{ - std::string label_text=helper; - numLines_ = 0; - while (!label_text.empty()) - { - const std::string::size_type pos = label_text.find('\n'); - std::string current_sentence; - if (pos != std::string::npos) - current_sentence = label_text.substr(0,pos+1); - else - current_sentence = label_text; - if (current_sentence.size() > SIZE_TEXT) - { - const std::size_t cut = current_sentence.size()/SIZE_TEXT; - for (std::size_t index_cut=1; index_cut<=cut; index_cut++) - { - const std::string::size_type numero_char=current_sentence.rfind(' ',SIZE_TEXT*index_cut); - current_sentence = current_sentence.insert(numero_char+1,1,'\n'); - numLines_++; - } - } - if (pos != std::string::npos) label_text = label_text.substr(pos+1); - else label_text = ""; - final_text += current_sentence; - numLines_++; - } -} - -unsigned int QDisplayLinkInfoWidget::numLines(const std::string& str) -{ - std::string::size_type newline_pos; - unsigned int numlines = 1; - newline_pos = str.find('\n',0); - while( newline_pos != std::string::npos ) - { - numlines++; - newline_pos = str.find('\n',newline_pos+1); - } - return numlines; -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.h deleted file mode 100644 index 0508f9d9469..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/LinkWidget.h +++ /dev/null @@ -1,189 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include - - - -namespace sofa::gui::qt -{ - -/** - *\brief Abstract Interface of a qwidget which allows to edit a link. - */ -class SOFA_GUI_QT_API LinkWidget : public QWidget -{ - Q_OBJECT -public: - // - // Factory related code - // - - struct CreatorArgument - { - std::string name; - core::objectmodel::BaseLink* link; - QWidget* parent; - bool readOnly; - }; - - static LinkWidget *CreateLinkWidget(const LinkWidget::CreatorArgument &dwarg); - - -public slots: - /// Checks that widget has been edited - /// emit LinkOwnerDirty in case the name field has been modified - void updateLinkValue() - { - if(dirty) - { - const bool hasOwner = baseLink->getOwnerBase(); - std::string previousName; - if ( hasOwner ) previousName = baseLink->getOwnerBase()->getName(); - writeToLink(); - updateVisibility(); - if(hasOwner && baseLink->getOwnerBase()->getName() != previousName) - { - emit LinkOwnerDirty(true); - } - } - - dirty = false; - counter = baseLink->getCounter(); - - } - /// First checks that the widget is not currently being edited - /// checks that the link has changed since the last time the widget - /// has read the link value. - /// ultimately read the link value. - void updateWidgetValue() - { - if(!dirty) - { - if(counter != baseLink->getCounter()) - { - readFromLink(); - this->update(); - } - } - - - } - /// You call this slot anytime you want to specify that the widget - /// value is out of sync with the underlying link value. - void setWidgetDirty() - { - setWidgetDirty(true); - } - - void setWidgetDirty(bool b) - { - dirty = b; - emit WidgetDirty(b); - } -signals: - /// Emitted each time setWidgetDirty is called. You can also emit - /// it if you want to tell the widget value is out of sync with - /// the underlying link value. - void WidgetDirty(bool ); - /// Currently this signal is used to reflect the changes of the - /// component name in the sofaListview. - void LinkOwnerDirty(bool ); - - void LinkBeingChanged(); -public: - typedef core::objectmodel::BaseLink MyLink; - - LinkWidget(QWidget* parent,const char* /*name*/, MyLink* l) : - QWidget(parent /*,name */), baseLink(l), dirty(false), counter(-1) - { - } - ~LinkWidget() override {} - - inline virtual void setLink( MyLink* d) - { - baseLink = d; - readFromLink(); - } - - - /// BaseLink pointer accessor function. - const core::objectmodel::BaseLink* getBaseLink() const { return baseLink; } - core::objectmodel::BaseLink* getBaseLink() { return baseLink; } - - void updateVisibility() - { - //parentWidget()->setShown(baseLink->isDisplayed()); - } - bool isDirty() { return dirty; } - - /// The implementation of this method holds the widget creation and the signal / slot - /// connections. - virtual bool createWidgets() = 0; - /// Helper method to give a size. - virtual unsigned int sizeWidget() {return 1;} - /// Helper method for column. - virtual unsigned int numColumnWidget() {return 3;} - -protected: - /// The implementation of this method tells how the widget reads the value of the link. - virtual void readFromLink() = 0; - /// The implementation of this methods needs to tell how the widget can write its value - /// in the link - virtual void writeToLink() = 0; - - core::objectmodel::BaseLink* baseLink; - bool dirty; - int counter; -}; - - - -/// Widget used to display the name of a Link -class SOFA_GUI_QT_API QDisplayLinkInfoWidget: public QWidget -{ - Q_OBJECT -public: - QDisplayLinkInfoWidget(QWidget* parent, const std::string& helper, core::objectmodel::BaseLink* l, bool modifiable); -public slots: - unsigned int getNumLines() const { return numLines_;} -protected: - void formatHelperString(const std::string& helper, std::string& final_text); - static unsigned int numLines(const std::string& str); - core::objectmodel::BaseLink* link; - unsigned int numLines_; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.cpp deleted file mode 100644 index f1b497b9973..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "MaterialDataWidget.h" -#include - -namespace sofa::gui::qt::materialdatawidget_h -{ -helper::Creator DWClass_MeshMaterial("default",true); -helper::Creator DWClass_MeshVectorMaterial("default",true); - -bool MaterialDataWidget::createWidgets() -{ - - _nameEdit = new QLineEdit(this); - _ambientPicker = new QRGBAColorPicker(this); - _ambientCheckBox = new QCheckBox(this); - _emissivePicker = new QRGBAColorPicker(this); - _emissiveCheckBox = new QCheckBox(this); - _specularPicker = new QRGBAColorPicker(this); - _specularCheckBox = new QCheckBox(this); - _diffusePicker = new QRGBAColorPicker(this); - _diffuseCheckBox = new QCheckBox(this); - _shininessEdit = new QLineEdit(this); - _shininessEdit->setValidator(new QDoubleValidator(this) ); - _shininessCheckBox = new QCheckBox(this); - QVBoxLayout* layout = new QVBoxLayout(this); - - //QGridLayout* grid = new QGridLayout(5,3); - QGridLayout* grid = new QGridLayout(); - grid->setSpacing(1); - QHBoxLayout* hlayout = new QHBoxLayout(); - hlayout->addWidget(new QLabel("Name",this)); - hlayout->addWidget(_nameEdit); - - grid->addWidget(_ambientCheckBox,0,0,Qt::AlignHCenter); - grid->addWidget(new QLabel("Ambient",this),0,1,Qt::AlignHCenter); - grid->addWidget(_ambientPicker,0,2,Qt::AlignHCenter); - - grid->addWidget(_emissiveCheckBox,1,0,Qt::AlignHCenter); - grid->addWidget(new QLabel("Emissive",this),1,1,Qt::AlignHCenter); - grid->addWidget(_emissivePicker,1,2,Qt::AlignHCenter); - - grid->addWidget(_diffuseCheckBox,2,0,Qt::AlignHCenter); - grid->addWidget(new QLabel("Diffuse",this),2,1,Qt::AlignHCenter); - grid->addWidget(_diffusePicker,2,2,Qt::AlignHCenter); - - grid->addWidget(_specularCheckBox,3,0,Qt::AlignHCenter); - grid->addWidget(new QLabel("Specular",this),3,1,Qt::AlignHCenter); - grid->addWidget(_specularPicker,3,2,Qt::AlignHCenter); - - grid->addWidget(_shininessCheckBox,4,0,Qt::AlignHCenter); - grid->addWidget(new QLabel("Shininess",this),4,1,Qt::AlignHCenter); - grid->addWidget(_shininessEdit,4,2,Qt::AlignHCenter); - - layout->addLayout(hlayout); - layout->addLayout(grid); - - - connect(_nameEdit, &QLineEdit::textChanged, this , [=](const QString &){ setWidgetDirty(true); }); - connect(_shininessEdit, &QLineEdit::textChanged, this , [=](const QString &){ setWidgetDirty(true); }); - - connect(_ambientCheckBox, &QCheckBox::toggled, this , &MaterialDataWidget::setWidgetDirty); - connect(_ambientCheckBox, &QCheckBox::toggled, _ambientPicker , &MaterialDataWidget::setEnabled); - - connect(_emissiveCheckBox, &QCheckBox::toggled, this , &MaterialDataWidget::setWidgetDirty); - connect(_emissiveCheckBox, &QCheckBox::toggled, _emissivePicker, &MaterialDataWidget::setEnabled); - - connect(_specularCheckBox, &QCheckBox::toggled, this , &MaterialDataWidget::setWidgetDirty); - connect(_specularCheckBox, &QCheckBox::toggled, _specularPicker, &MaterialDataWidget::setEnabled); - - connect(_diffuseCheckBox, &QCheckBox::toggled, this , &MaterialDataWidget::setWidgetDirty); - connect(_diffuseCheckBox, &QCheckBox::toggled, _diffusePicker, &MaterialDataWidget::setEnabled); - - connect(_shininessCheckBox, &QCheckBox::toggled, this, &MaterialDataWidget::setWidgetDirty); - connect(_shininessCheckBox, &QCheckBox::toggled, _shininessEdit, &MaterialDataWidget::setEnabled); - - connect(_ambientPicker, &QRGBAColorPicker::hasChanged, this, [=](){ setWidgetDirty(true); }); - connect(_emissivePicker, &QRGBAColorPicker::hasChanged, this, [=](){ setWidgetDirty(true); }); - connect(_specularPicker, &QRGBAColorPicker::hasChanged, this, [=](){ setWidgetDirty(true); }); - connect(_diffusePicker, &QRGBAColorPicker::hasChanged, this, [=](){ setWidgetDirty(true); }); - - readFromData(); - - return true; -} -void MaterialDataWidget::setDataReadOnly(bool readOnly) -{ - _nameEdit->setReadOnly(readOnly); - _nameEdit->setEnabled(!readOnly); - _ambientPicker->setEnabled(!readOnly); - _ambientCheckBox->setEnabled(!readOnly); - _emissivePicker->setEnabled(!readOnly); - _emissiveCheckBox->setEnabled(!readOnly); - _specularPicker->setEnabled(!readOnly); - _specularCheckBox->setEnabled(!readOnly); - _diffusePicker->setEnabled(!readOnly); - _diffuseCheckBox->setEnabled(!readOnly); - _shininessEdit->setReadOnly(readOnly); - _shininessCheckBox->setEnabled(!readOnly); -} -void MaterialDataWidget::readFromData() -{ - const Material& material = getData()->getValue(); - _nameEdit->setText( QString( material.name.c_str() ) ); - _ambientCheckBox->setChecked( material.useAmbient ); - _emissiveCheckBox->setChecked( material.useEmissive ); - _diffuseCheckBox->setChecked( material.useDiffuse ); - _specularCheckBox->setChecked( material.useSpecular ); - _shininessCheckBox->setChecked(material.useShininess); - QString str; - str.setNum(material.shininess); - _shininessEdit->setText(str); - - _ambientPicker->setColor( material.ambient ); - _emissivePicker->setColor( material.emissive ); - _specularPicker->setColor( material.specular ); - _diffusePicker->setColor( material.diffuse ); - - _ambientPicker->setEnabled( _ambientCheckBox->isChecked() ); - _emissivePicker->setEnabled( _emissiveCheckBox->isChecked() ); - _specularPicker->setEnabled( _specularCheckBox->isChecked() ); - _diffusePicker->setEnabled( _diffuseCheckBox->isChecked() ); - - -} -void MaterialDataWidget::writeToData() -{ - Material* material = getData()->beginEdit(); - - material->name = _nameEdit->text().toStdString(); - material->ambient = _ambientPicker->getColor(); - material->diffuse = _diffusePicker->getColor(); - material->emissive = _emissivePicker->getColor(); - material->specular = _specularPicker->getColor(); - material->shininess = _shininessEdit->text().toFloat(); - material->useAmbient = _ambientCheckBox->isChecked(); - material->useDiffuse = _diffuseCheckBox->isChecked(); - material->useShininess = _shininessCheckBox->isChecked(); - material->useEmissive = _emissiveCheckBox->isChecked(); - material->useSpecular = _specularCheckBox->isChecked(); - - - getData()->endEdit(); - -} - - -bool VectorMaterialDataWidget::createWidgets() -{ - if( getData()->getValue().empty() ) - { - return false; - } - _comboBox = new QComboBox(this); - _materialDataWidget = new MaterialDataWidget(this,this->objectName().toStdString().c_str(),&_currentMaterial); - _materialDataWidget->createWidgets(); - QVBoxLayout* layout = new QVBoxLayout(this); - layout->addWidget(_comboBox); - layout->addWidget(_materialDataWidget); - - connect( _comboBox, QOverload::of(&QComboBox::activated), this, &VectorMaterialDataWidget::changeMaterial ); - connect( _materialDataWidget, &MaterialDataWidget::WidgetDirty, this, &VectorMaterialDataWidget::setWidgetDirty ); - - readFromData(); - - return true; -} - -void VectorMaterialDataWidget::setDataReadOnly(bool readOnly) -{ - if (_materialDataWidget) - _materialDataWidget->setDataReadOnly(readOnly); -} - -void VectorMaterialDataWidget::readFromData() -{ - VectorMaterial::const_iterator iter; - const VectorMaterial& vecMaterial = getData()->getValue(); - if( vecMaterial.empty() ) - { - return; - } - _comboBox->clear(); - _vectorEditedMaterial.clear(); - std::copy(vecMaterial.begin(), vecMaterial.end(), std::back_inserter(_vectorEditedMaterial) ); - for( iter = _vectorEditedMaterial.begin(); iter != _vectorEditedMaterial.end(); ++iter ) - { - _comboBox->addItem( QString( (*iter).name.c_str() ) ); - } - _currentMaterialPos = 0; - _comboBox->setCurrentIndex(_currentMaterialPos); - _currentMaterial.setValue(_vectorEditedMaterial[_currentMaterialPos]); - _materialDataWidget->setData(&_currentMaterial); - _materialDataWidget->updateWidgetValue(); -} - -void VectorMaterialDataWidget::changeMaterial( int index ) -{ - //Save previous Material - _materialDataWidget->updateDataValue(); - const Material mat(_currentMaterial.getValue() ); - _vectorEditedMaterial[_currentMaterialPos] = mat; - - //Update current Material - _currentMaterialPos = index; - _currentMaterial.setValue(_vectorEditedMaterial[index]); - - //Update Widget - _materialDataWidget->setData(&_currentMaterial); - _materialDataWidget->updateWidgetValue(); -} - -void VectorMaterialDataWidget::writeToData() -{ - _materialDataWidget->updateDataValue(); - const Material mat(_currentMaterial.getValue() ); - _vectorEditedMaterial[_currentMaterialPos] = mat; - - VectorMaterial* vecMaterial = getData()->beginEdit(); - assert(vecMaterial->size() == _vectorEditedMaterial.size() ); - std::copy(_vectorEditedMaterial.begin(), _vectorEditedMaterial.end(), vecMaterial->begin() ); - - getData()->endEdit(); -} - -} // namespace sofa::gui::qt::materialdatawidget_h diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.h deleted file mode 100644 index 41785c73817..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/MaterialDataWidget.h +++ /dev/null @@ -1,123 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "DataWidget.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "QRGBAColorPicker.h" - -/// Private namespace -namespace sofa::gui::qt::materialdatawidget_h -{ - -using sofa::gui::qt::QRGBAColorPicker ; -using sofa::type::Material ; -using sofa::core::objectmodel::Data ; - -class MaterialDataWidget : public TDataWidget -{ - Q_OBJECT -public: - MaterialDataWidget(QWidget* parent, - const char* name, - Data* data): - TDataWidget(parent,name,data) - {} - - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - virtual unsigned int numColumnWidget() {return 1;} - -protected: - virtual void readFromData(); - virtual void writeToData(); - QLineEdit* _nameEdit; - QRGBAColorPicker* _ambientPicker; - QRGBAColorPicker* _emissivePicker; - QRGBAColorPicker* _specularPicker; - QRGBAColorPicker* _diffusePicker; - QLineEdit* _shininessEdit; - QCheckBox* _ambientCheckBox; - QCheckBox* _emissiveCheckBox; - QCheckBox* _specularCheckBox; - QCheckBox* _diffuseCheckBox; - QCheckBox* _shininessCheckBox; -}; - - -typedef type::vector VectorMaterial; -class VectorMaterialDataWidget : public TDataWidget< VectorMaterial > -{ - Q_OBJECT -public: - VectorMaterialDataWidget(QWidget* parent, - const char* name, - Data< type::vector >* data): - TDataWidget< type::vector >(parent,name,data), - _materialDataWidget(nullptr), - _currentMaterial(0,data->isDisplayed(),data->isReadOnly()), - _comboBox(nullptr) - { - - } - - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - virtual unsigned int numColumnWidget() {return 1;} - - -protected: - virtual void readFromData(); - virtual void writeToData(); - - MaterialDataWidget* _materialDataWidget; - VectorMaterial _vectorEditedMaterial; - core::objectmodel::Data _currentMaterial; - QComboBox* _comboBox; - int _currentMaterialPos; - -protected slots: - void changeMaterial( int ); -}; - -} // namespace sofa::gui::qt::materialdatawidget_h - -namespace sofa::gui::qt -{ - using sofa::gui::qt::materialdatawidget_h::MaterialDataWidget; -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.cpp deleted file mode 100644 index 19a9ed49dc5..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "ModifyObject.h" -#include "DataWidget.h" -#include "QDisplayDataWidget.h" -#include "QDataDescriptionWidget.h" -#include "QTabulationModifyObject.h" -#include -#include -#include -#include -#if SOFA_GUI_QT_HAVE_QT_CHARTS -#include -#include -#endif -#include -using sofa::helper::logging::Message; - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -ModifyObject::ModifyObject(void *Id, - QTreeWidgetItem* item_clicked, - QWidget* parent, - const ModifyObjectFlags& dialogFlags, - const char* name, - bool modal, Qt::WindowFlags f ) - :QDialog(parent, f), - Id_(Id), - item_(item_clicked), - basenode(nullptr), - data_(nullptr), - dialogFlags_(dialogFlags), - messageTab(nullptr), - messageEdit(nullptr) - #if SOFA_GUI_QT_HAVE_QT_CHARTS - ,energy(nullptr) - ,momentum(nullptr) - #endif -{ - setWindowTitle(name); - //setObjectName(name); - setModal(modal); -} - -void ModifyObject::createDialog(core::objectmodel::Base* base) -{ - if(base == nullptr) - { - return; - } - emit beginObjectModification(base); - basenode = base; - data_ = nullptr; - - //Layout to organize the whole window - QVBoxLayout *generalLayout = new QVBoxLayout(this); - generalLayout->setObjectName("generalLayout"); - generalLayout->setContentsMargins(0,0,0,0); - generalLayout->setSpacing(1); - - //Tabulation widget - dialogTab = new QTabWidget(this); - - //add a scrollable area for data properties - QScrollArea* m_scrollArea = new QScrollArea(); - - // const int screenHeight = QApplication::desktop()->height(); - QRect geometry = QGuiApplication::primaryScreen()->availableGeometry(); - - m_scrollArea->setMinimumSize(600, geometry.height() * 0.75); - m_scrollArea->setWidgetResizable(true); - dialogTab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_scrollArea->setWidget(dialogTab); - generalLayout->addWidget(m_scrollArea); - - connect(dialogTab, SIGNAL( currentChanged(int)), this, SLOT( updateTables())); - - buttonUpdate = new QPushButton( this ); - buttonUpdate->setObjectName("buttonUpdate"); - buttonUpdate->setText("&Update"); - buttonUpdate->setEnabled(false); - QPushButton *buttonOk = new QPushButton( this ); - buttonOk->setObjectName("buttonOk"); - buttonOk->setText( tr( "&OK" ) ); - - QPushButton *buttonCancel = new QPushButton( this ); - buttonCancel->setObjectName("buttonCancel"); - buttonCancel->setText( tr( "&Cancel" ) ); - - QPushButton *buttonRefresh = new QPushButton( this ); - buttonRefresh->setObjectName("buttonRefresh"); - buttonRefresh->setText( tr( "Refresh" ) ); - - // displayWidget - if (basenode) - { - const sofa::core::objectmodel::Base::VecData& fields = basenode->getDataFields(); - const sofa::core::objectmodel::Base::VecLink& links = basenode->getLinks(); - - std::map< std::string, std::vector > groupTabulation; - - std::vector tabNames; - //Put first the Property Tab - tabNames.push_back("Property"); - - for( sofa::core::objectmodel::Base::VecData::const_iterator it = fields.begin(); it!=fields.end(); ++it) - { - core::objectmodel::BaseData* data=*it; - if (!data) - { - dmsg_error("ModifyObject") << "nullptr Data in '" << basenode->getName() << "'" ; - continue; - } - - if (data->getName().empty()) continue; // ignore unnamed data - - //For each Data of the current Object - //We determine where it belongs: - std::string currentGroup=data->getGroup(); - - if (currentGroup.empty()) currentGroup="Property"; - - // Ignore the data in group "Infos" so they can be putted in the real Infos panel that is - // handled in a different way (see QDataDescriptionWidget) - if (currentGroup == "Infos") - continue; - - QTabulationModifyObject* currentTab=nullptr; - - std::vector &tabs=groupTabulation[currentGroup]; - bool newTab = false; - if (tabs.empty()) tabNames.push_back(currentGroup); - if (tabs.empty() || tabs.back()->isFull()) - { - newTab = true; - m_tabs.push_back(new QTabulationModifyObject(this,basenode, item_,tabs.size()+1)); - tabs.push_back(m_tabs.back()); - } - currentTab = tabs.back(); - currentTab->addData(data, getFlags()); - if (newTab) - { - connect(buttonUpdate, SIGNAL(clicked() ), currentTab, SLOT( updateDataValue() ) ); - connect(buttonOk, SIGNAL(clicked() ), currentTab, SLOT( updateDataValue() ) ); - connect(this, SIGNAL(updateDataWidgets()), currentTab, SLOT( updateWidgetValue()) ); - - /// The timer is deleted when the 'this' object is destroyed. - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(updateTables())); - connect(timer, SIGNAL(timeout()), currentTab, SLOT(updateDataValue())); - timer->start(10); - - connect(currentTab, SIGNAL( TabDirty(bool) ), buttonUpdate, SLOT( setEnabled(bool) ) ); - connect(currentTab, SIGNAL( TabDirty(bool) ), this, SIGNAL( componentDirty(bool) ) ); - } - } - - for( sofa::core::objectmodel::Base::VecLink::const_iterator it = links.begin(); it!=links.end(); ++it) - { - core::objectmodel::BaseLink* link=*it; - - if (link->getName().empty()) continue; // ignore unnamed links - if (!link->storePath() && link->getSize() == 0) continue; // ignore empty links - - //For each Link of the current Object - //We determine where it belongs: - std::string currentGroup="Links"; - - QTabulationModifyObject* currentTab=nullptr; - - std::vector &tabs=groupTabulation[currentGroup]; - if (tabs.empty()) tabNames.push_back(currentGroup); - if (tabs.empty() || tabs.back()->isFull()) - { - m_tabs.push_back(new QTabulationModifyObject(this,basenode, item_,tabs.size()+1)); - tabs.push_back(m_tabs.back() ); - } - currentTab = tabs.back(); - - currentTab->addLink(link, getFlags()); - connect(buttonUpdate, SIGNAL(clicked() ), currentTab, SLOT( updateDataValue() ) ); - connect(buttonOk, SIGNAL(clicked() ), currentTab, SLOT( updateDataValue() ) ); - connect(this, SIGNAL(updateDataWidgets()), currentTab, SLOT( updateWidgetValue()) ); - - connect(currentTab, SIGNAL( TabDirty(bool) ), buttonUpdate, SLOT( setEnabled(bool) ) ); - connect(currentTab, SIGNAL( TabDirty(bool) ), this, SIGNAL( componentDirty(bool) ) ); - } - - for (std::vector::const_iterator it = tabNames.begin(), itend = tabNames.end(); it != itend; ++it) - { - const std::string& groupName = *it; - std::vector &tabs=groupTabulation[groupName]; - - for (unsigned int i=0; igetIndex()) + "/" + QString::number(tabs.size()); - dialogTab->addTab(tabs[i],nameTab); - tabs[i]->addStretch(); - } - } - -#if SOFA_GUI_QT_HAVE_QT_CHARTS - //Energy Widget - if (simulation::Node* real_node = sofa::core::castTo(basenode)) - { - if (dialogFlags_.REINIT_FLAG) - { - energy = new QEnergyStatWidget(dialogTab, real_node); - dialogTab->addTab(energy, QString("Energy Stats")); - } - } - - //Momentum Widget - if (simulation::Node* real_node = sofa::core::castTo(basenode)) - { - if (dialogFlags_.REINIT_FLAG) - { - momentum = new QMomentumStatWidget(dialogTab, real_node); - dialogTab->addTab(momentum, QString("Momentum Stats")); - } - } -#endif - - - /// Info Widget - { - QDataDescriptionWidget* description=new QDataDescriptionWidget(dialogTab, basenode); - dialogTab->addTab(description, QString("Infos")); - } - - /// Message widget - { - updateConsole(); - if (messageTab) - { - std::stringstream tmp; - int numMessages = basenode->countLoggedMessages({Message::Info, Message::Advice, Message::Deprecated, - Message::Error, Message::Warning, Message::Fatal}); - tmp << "Messages(" << numMessages << ")" ; - dialogTab->addTab(messageTab, QString::fromStdString(tmp.str())); - } - } - - //Adding buttons at the bottom of the dialog - QHBoxLayout *lineLayout = new QHBoxLayout( nullptr); - lineLayout->setContentsMargins(0,0,0,0); - lineLayout->setSpacing(6); - lineLayout->setObjectName("Button Layout"); - lineLayout->addWidget(buttonUpdate); - QSpacerItem *Horizontal_Spacing = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); - lineLayout->addItem( Horizontal_Spacing ); - - lineLayout->addWidget(buttonOk); - lineLayout->addWidget(buttonCancel); - lineLayout->addWidget(buttonRefresh); - generalLayout->addLayout( lineLayout ); - - //Signals and slots connections - connect( buttonUpdate, SIGNAL( clicked() ), this, SLOT( updateValues() ) ); - connect(buttonRefresh, SIGNAL(clicked() ), this, SLOT( updateTables() )); - connect( buttonOk, SIGNAL( clicked() ), this, SLOT( accept() ) ); - connect( buttonCancel, SIGNAL( clicked() ), this, SLOT( reject() ) ); - - resize( QSize(450, 130).expandedTo(minimumSizeHint()) ); - } -} - -void ModifyObject::clearMessages() -{ - basenode->clearLoggedMessages(); - messageEdit->clear(); - - std::stringstream tmp; - const int numMessages = basenode->countLoggedMessages({Message::Info, Message::Advice, Message::Deprecated, - Message::Error, Message::Warning, Message::Fatal}); - tmp << "Messages(" << numMessages << ")" ; - - dialogTab->setTabText(dialogTab->indexOf(messageTab), QString::fromStdString(tmp.str())); -} - - - -void ModifyObject::createDialog(core::objectmodel::BaseData* data) -{ - data_ = data; - basenode = nullptr; - - emit beginDataModification(data); - - QVBoxLayout *generalLayout = new QVBoxLayout(this); - generalLayout->setContentsMargins(0, 0, 0, 0); - generalLayout->setSpacing(1); - generalLayout->setObjectName("generalLayout"); - QHBoxLayout *lineLayout = new QHBoxLayout( nullptr); - lineLayout->setContentsMargins(0, 0, 0, 0); - lineLayout->setSpacing(6); - lineLayout->setObjectName("Button Layout"); - buttonUpdate = new QPushButton( this ); - buttonUpdate->setObjectName("buttonUpdate"); - buttonUpdate->setText("&Update"); - buttonUpdate->setEnabled(false); - QPushButton *buttonOk = new QPushButton( this ); - buttonOk->setObjectName("buttonOk"); - buttonOk->setText( tr( "&OK" ) ); - QPushButton *buttonCancel = new QPushButton( this ); - buttonCancel->setObjectName("buttonCancel"); - buttonCancel->setText( tr( "&Cancel" ) ); - - QDisplayDataWidget* displaydatawidget = new QDisplayDataWidget(this,data,getFlags()); - generalLayout->addWidget(displaydatawidget); - lineLayout->addWidget(buttonUpdate); - - QSpacerItem *Horizontal_Spacing = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); - lineLayout->addItem( Horizontal_Spacing ); - - lineLayout->addWidget(buttonOk); - lineLayout->addWidget(buttonCancel); - generalLayout->addLayout( lineLayout ); - connect(buttonUpdate, SIGNAL( clicked() ), displaydatawidget, SLOT( UpdateData() ) ); - connect(displaydatawidget, SIGNAL( WidgetDirty(bool) ), buttonUpdate, SLOT( setEnabled(bool) ) ); - connect(displaydatawidget, SIGNAL( WidgetDirty(bool) ), this, SIGNAL( componentDirty(bool) ) ); - connect(buttonOk, SIGNAL(clicked() ), displaydatawidget, SLOT( UpdateData() ) ); - connect( buttonOk, SIGNAL( clicked() ), this, SLOT( accept() ) ); - connect( buttonCancel, SIGNAL( clicked() ), this, SLOT( reject() ) ); - connect(this, SIGNAL(updateDataWidgets()), displaydatawidget, SLOT(UpdateWidgets()) ); -} - -const std::string toHtmlString(const Message::Type t) -{ - switch(t) - { - case Message::Info: - return "Info"; - case Message::Advice: - return "Advice"; - case Message::Deprecated: - return "Deprecated"; - case Message::Warning: - return "Warning"; - case Message::Error: - return "Error"; - case Message::Fatal: - return "Fatal"; - default: - return "Undefine"; - } - return "Undefine"; -} - -class ClickableTextEdit : public QTextEdit -{ -public: - Q_OBJECT - -public: - ClickableTextEdit(QWidget* w) : QTextEdit(w) {} -}; - -void ModifyObject::openExternalBrowser(const QUrl &link) -{ - QDesktopServices::openUrl(link) ; -} - -//****************************************************************************************** -void ModifyObject::updateConsole() -{ - if (!messageEdit) - { - messageTab = new QWidget(); - QVBoxLayout* tabLayout = new QVBoxLayout( messageTab); - tabLayout->setContentsMargins(0, 0, 0, 0); - tabLayout->setSpacing(1); - tabLayout->setObjectName("tabWarningLayout"); - QPushButton *buttonClearWarnings = new QPushButton(messageTab); - buttonClearWarnings->setObjectName("buttonClearWarnings"); - tabLayout->addWidget(buttonClearWarnings); - buttonClearWarnings->setText( tr("&Clear")); - connect( buttonClearWarnings, SIGNAL( clicked()), this, SLOT( clearMessages())); - - messageEdit = new QTextBrowser(messageTab); - //messageEdit->backwardAvailable(false); - connect(messageEdit, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(openExternalBrowser(const QUrl&))); - messageEdit->setObjectName("WarningEdit"); - messageEdit->setOpenExternalLinks(false); - messageEdit->setOpenLinks(false); - tabLayout->addWidget( messageEdit ); - messageEdit->setReadOnly(true); - } - - if (dialogTab->currentWidget() == messageTab) - { - std::stringstream tmp; - tmp << ""; - tmp << ""; - tmp << "" ; - m_numMessages++; - } - tmp << "
    " ; - m_numMessages = 0 ; - for(const Message& message : basenode->getLoggedMessages()) - { - tmp << "
    ["<" ; - tmp << "" << message.messageAsString() << "
    "; - - messageEdit->setHtml(QString(tmp.str().c_str())); - messageEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); - messageEdit->ensureCursorVisible(); - } -} - -//******************************************************************************************************************* -void ModifyObject::updateValues() -{ - // this is controlling if we need to re-init (eg: not in the Modeller) - if(!dialogFlags_.REINIT_FLAG) - return; - - if (basenode == nullptr) - return; - - simulation::Node* node = sofa::core::castTo(basenode); - core::objectmodel::BaseObject* object = sofa::core::castTo(basenode); - - // if the selected object is a node - if (node) - { - node->reinit(sofa::core::execparams::defaultInstance()); - } - else if (object) //< if the selected is an object - { - object->reinit(); //< we need to fully re-initialize the object to be sure it is ok. - } - else - { - throw std::runtime_error("Invalid type, only Node and BaseObject are supported. " - "This is a BUG, please report to https://github.com/sofa-framework/sofa/issues"); - } - - // trigger the internal updates (eg: updateDataCallback), - basenode->d_componentState.updateIfDirty(); - - emit objectUpdated(); - emit endObjectModification(basenode); - emit beginObjectModification(basenode); - - if (buttonUpdate) - buttonUpdate->setEnabled(false); -} - -//************************************************************************************************************************************** -//Called each time a new step of the simulation if computed -void ModifyObject::updateTables() -{ - emit updateDataWidgets(); -#if SOFA_GUI_QT_HAVE_QT_CHARTS - if (energy) - { - if (dialogTab->currentWidget() == energy) energy->step(); - } - - if (momentum) - { - if (dialogTab->currentWidget() == momentum) momentum->step(); - } -#endif - - if(basenode) - { - updateConsole(); - } -} - -void ModifyObject::reject () -{ - if (basenode) - { - emit endObjectModification(basenode); - } - - const QString dataModifiedString = parseDataModified(); - if (!dataModifiedString.isEmpty()) - { - emit dataModified( dataModifiedString ); - } - - emit dialogClosed(Id_); - deleteLater(); - QDialog::reject(); -} //When closing a window, inform the parent. - -void ModifyObject::accept () -{ - updateValues(); - - const QString dataModifiedString = parseDataModified(); - if (!dataModifiedString.isEmpty()) - { - emit dataModified( dataModifiedString ); - } - - if (basenode) - { - emit endObjectModification(basenode); - } - emit dialogClosed(Id_); - deleteLater(); - QDialog::accept(); -} //if closing by using Ok button, update the values - -QString ModifyObject::parseDataModified() -{ - QString cat; - - for (std::size_t i = 0; i < m_tabs.size(); ++i) - { - const QString tabString = m_tabs[i]->getDataModifiedString(); - if (!tabString.isEmpty()) - { - cat += tabString; - if (i != (m_tabs.size() - 1)) - { - cat += "\n"; - } - } - } - - return cat; -} - -bool ModifyObject::hideData(core::objectmodel::BaseData* data) { return (!data->isDisplayed()) && dialogFlags_.HIDE_FLAG;} - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.h b/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.h deleted file mode 100644 index 95ad164f984..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/ModifyObject.h +++ /dev/null @@ -1,188 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace sofa::gui::qt -{ - -class QTransformationWidget; -#if SOFA_GUI_QT_HAVE_QT_CHARTS -class QEnergyStatWidget; -class QMomentumStatWidget; -#endif -class QTabulationModifyObject; - -typedef struct ModifyObjectFlags -{ - - bool HIDE_FLAG; //if we allow to hide Datas - bool READONLY_FLAG; //if we allow ReadOnly Datas - bool EMPTY_FLAG;//if we allow empty data - bool RESIZABLE_FLAG; - bool REINIT_FLAG; - bool LINKPATH_MODIFIABLE_FLAG; //if we allow to modify the links of the Data - bool MODELER_FLAG; //if we attempt to create this dialog from the Modeler. - bool PROPERTY_WIDGET_FLAG; //if we attempt to create this dialog in the property widget. - - ModifyObjectFlags(): - HIDE_FLAG(true), - READONLY_FLAG(true), - EMPTY_FLAG(false), - RESIZABLE_FLAG(false), - REINIT_FLAG(true), - LINKPATH_MODIFIABLE_FLAG(false), - MODELER_FLAG(false), - PROPERTY_WIDGET_FLAG(false) - {} - - void setFlagsForSofa() - { - HIDE_FLAG = true; - READONLY_FLAG = true; - EMPTY_FLAG = false; - RESIZABLE_FLAG = true; - REINIT_FLAG = true; - LINKPATH_MODIFIABLE_FLAG = false; - MODELER_FLAG = false; - PROPERTY_WIDGET_FLAG = false; - }; - - void setFlagsForModeler() - { - HIDE_FLAG = false; - READONLY_FLAG=false; //everything will be editable - EMPTY_FLAG = true; - RESIZABLE_FLAG = true; - REINIT_FLAG = false; - LINKPATH_MODIFIABLE_FLAG = true; - MODELER_FLAG = true; - PROPERTY_WIDGET_FLAG = false; - }; -} ModifyObjectFlags; - -class SOFA_GUI_QT_API ModifyObject : public QDialog -{ - Q_OBJECT -public: - - explicit ModifyObject( void *Id, - QTreeWidgetItem* item_clicked, - QWidget* parent, - const ModifyObjectFlags& dialogFlags, - const char* name= nullptr, - bool modal= false, - Qt::WindowFlags f= Qt::WindowType::Widget ); - - ~ModifyObject() override - { - delete buttonUpdate; - } - - const ModifyObjectFlags& getFlags() { return dialogFlags_;} - - void createDialog(core::objectmodel::Base* node); - void createDialog(core::objectmodel::BaseData* data); - bool hideData(core::objectmodel::BaseData* data); - void readOnlyData(QTableWidget *widget, core::objectmodel::BaseData* data); - void readOnlyData(QWidget *widget, core::objectmodel::BaseData* data); - -public slots: - void openExternalBrowser(const QUrl &link); - void reject () override; - void accept () override; - void closeNow () {emit(reject());} //called from outside to close the current widget - void closeEvent ( QCloseEvent * ) override {emit(reject());} - void updateTables(); - virtual void updateValues(); //update the node with the values of the field -signals: - void updateDataWidgets(); // emitted eachtime updateValues is called to propagate the changes to the widgets. - void objectUpdated(); //update done - void dialogClosed(void *); //the current window has been closed: we give the Id of the current window - void nodeNameModification(simulation::Node*); - void componentDirty(bool); - void dataModified( QString ); - - - void beginObjectModification(sofa::core::objectmodel::Base* object); - void endObjectModification(sofa::core::objectmodel::Base* object); - void beginDataModification(sofa::core::objectmodel::BaseData* data); - void endDataModification(sofa::core::objectmodel::BaseData* data); - -protected slots: - //update the tables of value at each step of the simulation - void clearMessages() ; - -protected: - void updateConsole(); //update the console log of warnings and outputs - QString parseDataModified(); - void* Id_; - QTreeWidgetItem* item_; - core::objectmodel::Base* basenode; - core::objectmodel::BaseData* data_; - const ModifyObjectFlags dialogFlags_; - - QWidget *messageTab; - QTextBrowser *messageEdit; - - QTabWidget *dialogTab; - QPushButton *buttonUpdate; - int m_numMessages; - -#if SOFA_GUI_QT_HAVE_QT_CHARTS - //Energy widget: plot the kinetic & potential energy - QEnergyStatWidget* energy; - //Momentum widget: plot the linear & angular momentum - QMomentumStatWidget* momentum; -#endif - //Visual Flags - - std::vector< QTabulationModifyObject* > m_tabs; - -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/MouseManager.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/MouseManager.ui deleted file mode 100644 index 7cca58ab10b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/MouseManager.ui +++ /dev/null @@ -1,104 +0,0 @@ - - - MouseManager - - - - 0 - 0 - 295 - 612 - - - - MouseManager - - - - - - Left Button - - - - - - Operation: - - - false - - - - - - - - - - - - - Middle Button - - - - - - Operation: - - - false - - - - - - - - - - - - - Right Button - - - - - - Operation: - - - false - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.cpp deleted file mode 100644 index a2149cc4daa..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "PickHandlerCallBacks.h" -#include "RealGUI.h" -#include "viewer/SofaViewer.h" -#include "QSofaListView.h" -#include -#include - -#include - -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ - -InformationOnPickCallBack::InformationOnPickCallBack() - :gui(nullptr) -{ -} - -InformationOnPickCallBack::InformationOnPickCallBack(RealGUI *g) - :gui(g) -{ -} - -void InformationOnPickCallBack::execute(const BodyPicked &body) -{ - if(!gui) return; - core::objectmodel::BaseObject *objectPicked=nullptr; - if (body.body) - { - QTreeWidgetItem* item=gui->simulationGraph->getListener()->items[body.body]; -// gui->simulationGraph->ensureItemVisible(item); - gui->simulationGraph->scrollToItem(item); - gui->simulationGraph->clearSelection(); -// gui->simulationGraph->setSelected(item,true); - gui->simulationGraph->setCurrentItem(item); - objectPicked=body.body; - } - else if (body.mstate) - { - QTreeWidgetItem* item=gui->simulationGraph->getListener()->items[body.mstate]; -// gui->simulationGraph->ensureItemVisible(item); - gui->simulationGraph->scrollToItem(item); - gui->simulationGraph->clearSelection(); -// gui->simulationGraph->setSelected(item,true); - gui->simulationGraph->setCurrentItem(item); - objectPicked=body.mstate; - } - else - gui->simulationGraph->clearSelection(); - - if (objectPicked) - { - QString messagePicking; - const simulation::Node *n=static_cast(objectPicked->getContext()); - messagePicking=QString("Index ") + QString::number(body.indexCollisionElement) - + QString(" of ") - + QString(n->getPathName().c_str()) - + QString("/") + QString(objectPicked->getName().c_str()) - + QString(" : ") + QString(objectPicked->getClassName().c_str()); - if (!objectPicked->getTemplateName().empty()) - messagePicking += QString("<") + QString(objectPicked->getTemplateName().c_str()) + QString(">"); - gui->statusBar()->showMessage(messagePicking,3000); //display message during 3 seconds - } -} - -ColourPickingRenderCallBack::ColourPickingRenderCallBack() - :_viewer(nullptr) -{ -} - -ColourPickingRenderCallBack::ColourPickingRenderCallBack(viewer::SofaViewer* viewer) - :_viewer(viewer) -{ -} - -void ColourPickingRenderCallBack::render(ColourPickingVisitor::ColourCode code) -{ - if(_viewer) - { - _viewer->drawColourPicking(code); - } - -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.h b/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.h deleted file mode 100644 index 5d9729a46fd..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/PickHandlerCallBacks.h +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include - -namespace sofa::component::collision -{ - struct BodyPicked; -} // namespace sofa::component::collision - -namespace sofa::gui::qt::viewer -{ - class SofaViewer; -} // namespace sofa::gui::qt::viewer - -namespace sofa::gui::qt -{ -class RealGUI; - -class InformationOnPickCallBack: public common::CallBackPicker -{ -public: - using BodyPicked = sofa::gui::component::performer::BodyPicked; - InformationOnPickCallBack(); - InformationOnPickCallBack(RealGUI *g); - void execute(const BodyPicked &body) override; -protected: - RealGUI *gui; -}; - - -class ColourPickingRenderCallBack : public sofa::gui::common::CallBackRender -{ -public: - ColourPickingRenderCallBack(); - ColourPickingRenderCallBack(viewer::SofaViewer* viewer); - void render(common::ColourPickingVisitor::ColourCode code) override; -protected: - viewer::SofaViewer* _viewer; - -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.cpp deleted file mode 100644 index 3f928550623..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include - -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -std::vector< type::Vec<3,int> > PieWidget::colorArray; - -type::Vec<3,int> PieWidget::getColor(int i) -{ - type::Vec<3,int> res=PieWidget::colorArray[i%PieWidget::colorArray.size()]; - float factor=1.0/(1.0+(0.3*(i/PieWidget::colorArray.size()))); - res[0] = (int)(res[0]*factor); - res[1] = (int)(res[1]*factor); - res[2] = (int)(res[2]*factor); - return res; -} - -PieWidget::PieWidget(QWidget *parent): QWidget(parent) -{ - if (PieWidget::colorArray.empty()) - { - colorArray.push_back( type::Vec<3,int>(250,125,70) ); - colorArray.push_back( type::Vec<3,int>(120,220,110) ); - colorArray.push_back( type::Vec<3,int>(215,90,215) ); - colorArray.push_back( type::Vec<3,int>(255,210,40) ); - colorArray.push_back( type::Vec<3,int>(75,210,210) ); - } -} -void PieWidget::paintEvent( QPaintEvent* ) -{ - sizePie = (int)(std::min(this->width(),this->height())*0.95); - if (data.empty()) return; - - QPainter p( this ); - - int initDraw=0; - int startAngle=0; - - p.setBrush(Qt::SolidPattern); - - for (unsigned int i=0; i c=PieWidget::getColor(i); - QColor color(c[0],c[1],c[2]); - p.setBrush(color); - int spanAngle=(int)(16*360*data[i].time/totalTime); - p.drawPie(initDraw,initDraw,sizePie,sizePie,startAngle,spanAngle); - startAngle+= spanAngle; - } -} - -void PieWidget::setChart( std::vector< dataTime >& value, unsigned int s) -{ - data=value; - selection=s; - totalTime=0; - for (unsigned int i=0; isetOrientation(Qt::Horizontal); - QGridLayout *grid = new QGridLayout(this); - pie = new PieWidget(splitter); - - table = new QTableWidget(0,3,splitter); - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - table->horizontalHeader()->setResizeMode(0,QHeaderView::Fixed); - table->horizontalHeader()->setResizeMode(1,QHeaderView::ResizeToContents); - table->horizontalHeader()->setResizeMode(2,QHeaderView::ResizeToContents); -#else - table->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Fixed); - table->horizontalHeader()->setSectionResizeMode(1,QHeaderView::ResizeToContents); - table->horizontalHeader()->setSectionResizeMode(2,QHeaderView::ResizeToContents); -#endif // QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - - table->horizontalHeader()->resizeSection(0,30); - - QStringList list; list<<"Id" << name.c_str() << "Time"; - table->setHorizontalHeaderLabels(list); - - grid->addWidget(splitter,0,0); - -} - - -void ChartsWidget::clear() -{ - int rows=table->rowCount(); - - for (int i=0; iremoveRow(0); - pie->clear(); -} - -void ChartsWidget::setChart( std::vector< dataTime >& value, unsigned int s) -{ - clear(); - pie->setChart(value,s); - selection=s; - for (unsigned int i=0; iinsertRow(i); - - type::Vec<3,int> c=PieWidget::getColor(i); - QColor color(c[0],c[1],c[2]); - - QString text(value[i].name.c_str()); - QString time= QString::number(value[i].time); - time += QString(" ms"); - if (!value[i].type.empty()) - { - text+="("; - text+= QString(value[i].type.c_str()); - text+=")"; - } - - QTableWidgetItem *itemColor = new QTableWidgetItem(); - itemColor->setBackground(color); - QTableWidgetItem *item = new QTableWidgetItem(); - QTableWidgetItem *itemTime = new QTableWidgetItem(); - table->setItem(i,0, itemColor); - item->setText(text); - table->setItem(i,1, item); - itemTime->setText(time); - table->setItem(i,2, itemTime); - table->resizeColumnToContents(1); - itemColor->setFlags(QFlag(0)); - item->setFlags(QFlag(0)); - itemTime->setFlags(QFlag(0)); - - } - pie->repaint(); - -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.h deleted file mode 100644 index 194b83d3a60..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/PieWidget.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include -#include -#include - - -#include -#include - -namespace sofa::gui::qt -{ - -struct dataTime -{ - dataTime(double t, - std::string n, - std::string ty=std::string(),std::string address=std::string()):time(t), name(n), type(ty), ptr(address) {} - bool operator== (const dataTime& other) - { - if (ptr.empty()) return name == other.name; - else return ptr == other.ptr; - } - double time; - std::string name; - std::string type; - std::string ptr; -}; - - -class PieWidget: public QWidget -{ -public: - - PieWidget(QWidget *parent); - - void paintEvent( QPaintEvent* ); - - void setChart( std::vector< dataTime >& value, unsigned int s); - void clear(); - static type::Vec<3,int> getColor(int i); - static std::vector< type::Vec<3,int> > colorArray; -protected: - std::vector< dataTime > data; - - unsigned int selection; - double totalTime; - int sizePie; -}; - -class ChartsWidget: public QWidget -{ -public: - ChartsWidget(const std::string &name, QWidget *parent); - - void setChart( std::vector< dataTime >& value, unsigned int s); - void clear(); -protected: - - unsigned int selection; - - PieWidget* pie; - QTableWidget *table; -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/PluginManager.ui b/Sofa/GUI/Qt/src/sofa/gui/qt/PluginManager.ui deleted file mode 100644 index 6c5c28dc02d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/PluginManager.ui +++ /dev/null @@ -1,186 +0,0 @@ - - - PluginManager - - - true - - - - 0 - 0 - 800 - 400 - - - - Plugin Manager - - - false - - - - - - - - Qt::Vertical - - - - - 416 - 0 - - - - 1 - - - true - - - true - - - 4 - - - - 1 - - - - - - - - - - - Description - - - false - - - - - - - true - - - false - - - true - - - - - - - - - true - - - - 1 - - - - - - - - - - - - - - - - &Add... - - - Alt+A - - - true - - - true - - - - - - - &Remove - - - Alt+R - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 237 - 20 - - - - - - - - &Close - - - Alt+C - - - true - - - - - - - - - - - - buttonClose - clicked() - PluginManager - close() - - - 20 - 20 - - - 20 - 20 - - - - - diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.cpp deleted file mode 100644 index 491de6d3661..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QDataDescriptionWidget.h" - -#include -#include - -#include -#include -#include - - - -namespace sofa::gui::qt -{ -void QDataDescriptionWidget::addRow(QGridLayout* grid, const std::string& title, - const std::string& value, unsigned int row, - unsigned int /*minimumWidth*/) -{ - QLabel* titlew = new QLabel(QString(title.c_str())); - grid->addWidget(titlew, row, 0, Qt::AlignTop); - - QLabel* tmplabel = (new QLabel(QString(value.c_str()))); - tmplabel->setMinimumWidth(20); - tmplabel->setWordWrap(true); - tmplabel->setAlignment(Qt::AlignTop); - tmplabel->setSizePolicy(QSizePolicy::MinimumExpanding, - QSizePolicy::MinimumExpanding); - grid->addWidget(tmplabel, row, 1, Qt::AlignTop); -} - -void QDataDescriptionWidget::addRowHyperLink(QGridLayout* grid, - const std::string& title, const std::string& value, unsigned int row, - unsigned int minimumWidth) -{ - SOFA_UNUSED(minimumWidth); - QLabel* titlew = new QLabel(QString(title.c_str())); - grid->addWidget(titlew, row, 0, Qt::AlignTop); - - QLabel* tmplabel = (new QLabel(QString(value.c_str()))); - tmplabel->setMinimumWidth(20); - tmplabel->setWordWrap(true); - tmplabel->setAlignment(Qt::AlignTop); - tmplabel->setSizePolicy(QSizePolicy::MinimumExpanding, - QSizePolicy::MinimumExpanding); - tmplabel->setTextFormat(Qt::RichText); - tmplabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - tmplabel->setOpenExternalLinks(true); - grid->addWidget(tmplabel, row, 1, Qt::AlignTop); -} - -QDataDescriptionWidget::QDataDescriptionWidget(QWidget* parent, core::objectmodel::Base* object) - :QWidget(parent) -{ - - QVBoxLayout* tabLayout = new QVBoxLayout(this); - tabLayout->setContentsMargins(0,0,0,0); - tabLayout->setSpacing(1); - tabLayout->setObjectName("tabInfoLayout"); - - //Instance - { - QGroupBox *box = new QGroupBox(this); - tabLayout->addWidget(box); - QGridLayout* boxLayout = new QGridLayout(); - box->setLayout(boxLayout); - - box->setTitle(QString("Instance")); - - addRow(boxLayout, "Name", object->getName(), 0); - addRow(boxLayout, "Class", object->getClassName(), 1); - - const std::string namespacename = sofa::helper::NameDecoder::decodeNamespaceName(typeid(*object)); - - int nextRow = 2; - if (!namespacename.empty()) - { - addRow(boxLayout, "Namespace", namespacename, nextRow, 20); - nextRow++; - } - if (!object->getTemplateName().empty()) - { - addRow(boxLayout, "Template", object->getTemplateName(), nextRow, 20); - nextRow++; - } - - const core::objectmodel::BaseNode* node = object->toBaseNode(); // Node - if (node && node->getNbParents()>1) // MultiNode - { - addRow(boxLayout, "Path", node->getPathName(), nextRow, 20); - nextRow++; - } - - tabLayout->addWidget( box ); - } - - - //Class description - core::ObjectFactory::ClassEntry entry = core::ObjectFactory::getInstance()->getEntry(object->getClassName()); - if (! entry.creatorMap.empty()) - { - QGroupBox *box = new QGroupBox(this); - tabLayout->addWidget(box); - QGridLayout* boxLayout = new QGridLayout(); - box->setLayout(boxLayout); - box->setTitle(QString("Class")); - - int nextRow = 0; - if (!entry.description.empty() && entry.description != std::string("TODO")) - { - addRow(boxLayout, "Description", entry.description, nextRow, 20); - nextRow++; - } - if (!entry.documentationURL.empty() && entry.documentationURL != std::string("TODO")) - { - const std::string textURL = "
    " + entry.documentationURL + ""; - addRowHyperLink(boxLayout, "Documentation URL", textURL, nextRow, 20); - nextRow++; - } - const core::ObjectFactory::CreatorMap::iterator it = entry.creatorMap.find(object->getTemplateName()); - if (it != entry.creatorMap.end() && *it->second->getTarget()) - { - addRow(boxLayout, "Provided by",it->second->getTarget(), nextRow, 20); - nextRow++; - } - - if (!entry.authors.empty() && entry.authors != std::string("TODO")) - { - addRow(boxLayout, "Authors", entry.authors, nextRow, 20); - nextRow++; - } - if (!entry.license.empty() && entry.license != std::string("TODO")) - { - addRow(boxLayout, "License", entry.license, nextRow, 20); - nextRow++; - } - tabLayout->addWidget( box ); - } - - - - //Extra description - std::vector selecteddatum ; - for(sofa::core::objectmodel::BaseData* datafield : object->getDataFields()) - { - if( datafield->getGroup() == "Infos" ) - selecteddatum.push_back(datafield) ; - } - - if(!selecteddatum.empty()) - { - QGroupBox *box = new QGroupBox(this); - tabLayout->addWidget(box); - QGridLayout* boxLayout = new QGridLayout(); - - box->setLayout(boxLayout); - - box->setTitle(QString("Extra information")); - - unsigned int row = 0; - for(const auto& data : selecteddatum) - { - addRow(boxLayout, data->getName(), data->getValueString(), row++); - } - } - - - tabLayout->addStretch(); -} - - - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.h deleted file mode 100644 index cd4f4669897..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDataDescriptionWidget.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include -#include -#include -#include - - - -namespace sofa::gui::qt -{ - -struct ModifyObjectFlags; -class SOFA_GUI_QT_API QDataDescriptionWidget : public QWidget -{ - Q_OBJECT -public: - QDataDescriptionWidget(QWidget* parent, core::objectmodel::Base* object); - - void addRow(QGridLayout* grid, const std::string& title, - const std::string& value, unsigned int row, unsigned int minimumWidth =0); - - void addRowHyperLink(QGridLayout* grid, const std::string& title, - const std::string& value, unsigned int row, unsigned int minimumWidth =0); -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.cpp deleted file mode 100644 index f34018ffb5e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QDisplayDataWidget.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define TEXTSIZE_THRESHOLD 45 - -using namespace sofa::core::objectmodel; - -namespace sofa::gui::qt -{ - -QDisplayDataWidget::QDisplayDataWidget(QWidget* parent, - BaseData* data, - const ModifyObjectFlags& flags):QGroupBox(), - data_(data), - flags_(flags), - datainfowidget_(nullptr), - datawidget_(nullptr), - numWidgets_(0) - -{ - gridLayout_ = new QGridLayout(); - this->setLayout(gridLayout_); - - parent->layout()->addWidget(this); - - setAutoFillBackground(true); - - if(data_ == nullptr) - return; - - const std::string& help = data_->getHelp().c_str(); - const std::string valuetype = data_->getValueTypeString(); - const std::string& ownerClass = data_->getOwner()->getClassName(); - const std::string defaultValue = data_->getDefaultValueString(); - std::stringstream s; - - s << (!help.empty() ? help : "< No help found >") - << "\nData type: " << valuetype - << "\nOwner: " << (!ownerClass.empty() ? ownerClass : "< No owner found >"); - - if (!defaultValue.empty()) - { - s << "\nDefault value: " << defaultValue; - } - - const std::string fullHelpText = s.str(); - setToolTip(fullHelpText.c_str()); - datainfowidget_ = new QDisplayDataInfoWidget(this,fullHelpText,data_, - flags.LINKPATH_MODIFIABLE_FLAG, flags_); - datainfowidget_->setContentsMargins(0, 0, 0, 0); - datainfowidget_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - gridLayout_->addWidget(datainfowidget_, 0,0); - numWidgets_ += 1; - - - DataWidget::CreatorArgument dwarg; - dwarg.name = data_->getName(); - dwarg.data = data_; - dwarg.parent = this; - dwarg.readOnly = (data_->isReadOnly() && flags.READONLY_FLAG); - - if( dynamic_cast(data_) != nullptr ) - { - // a bit of a hack for DataFileName widgets. - // A custom widget is used by default if we run this code from the Modeler - - std::string widgetName=data_->getWidget(); - if( widgetName.empty() && flags.MODELER_FLAG ) - { - data_->setWidget("widget_filename"); - } - } - - datawidget_= DataWidget::CreateDataWidget(dwarg); - - if (datawidget_ == nullptr) - { - datawidget_ = new QDataSimpleEdit(this,dwarg.data->getName().c_str(), dwarg.data); - datawidget_->createWidgets(); - datawidget_->setDataReadOnly(dwarg.readOnly); - assert(datawidget_ != nullptr); - } - - if(datawidget_->layout()) - { - datawidget_->layout()->setAlignment(Qt::AlignCenter); - datawidget_->layout()->setContentsMargins(0, 0, 0, 0); - } - - datawidget_->setContentsMargins(0, 16, 0, 0); - datawidget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - datawidget_->setToolTip(s.str().c_str()); - - numWidgets_ += datawidget_->sizeWidget(); - connect(datawidget_,SIGNAL(WidgetDirty(bool)), this, SIGNAL ( WidgetDirty(bool) ) ); - connect(this, SIGNAL( WidgetUpdate() ), datawidget_, SLOT( updateWidgetValue() ) ); - connect(this, SIGNAL( DataUpdate() ), datawidget_, SLOT(updateDataValue() ) ); - connect(datawidget_,SIGNAL(DataOwnerDirty(bool)),this,SIGNAL(DataOwnerDirty(bool)) ); - connect(datawidget_,SIGNAL(dataValueChanged(QString)),this,SIGNAL(dataValueChanged(QString)) ); - - if(flags.PROPERTY_WIDGET_FLAG) - { - QWidget* refreshWidget = new QWidget(this); - refreshWidget->setFixedSize(QSize(16, 16)); - QPushButton *refresh = new QPushButton(RefreshIcon(), "", refreshWidget); - refresh->setHidden(true); - refresh->setFixedSize(QSize(16, 16)); - refresh->setContentsMargins(0, 0, 0, 0); - - ++numWidgets_; - - { - connect(datawidget_,SIGNAL(WidgetDirty(bool)), refresh, SLOT ( setVisible(bool) ) ); - - if(datainfowidget_ && flags.LINKPATH_MODIFIABLE_FLAG) - { - connect(datainfowidget_,SIGNAL(WidgetDirty()), refresh, SLOT ( show() ) ); - connect(refresh, SIGNAL(clicked()), datainfowidget_, SLOT(linkEdited())); - } - - connect(refresh, SIGNAL(clicked()), this, SLOT(UpdateData())); - connect(refresh, SIGNAL(clicked(bool)), refresh, SLOT(setVisible(bool))); - } - - setStyleSheet("QGroupBox{border:0;}"); - setContentsMargins(0, 0, 0, 0); - } - else - { - setTitle(data_->getName().c_str()); - setContentsMargins(0,0,0,0); - } - gridLayout_->setContentsMargins(10,10,10,10); - gridLayout_->addWidget(datawidget_, 0, 1); - gridLayout_->setAlignment(datawidget_, Qt::AlignVCenter); -} - -void QDisplayDataWidget::UpdateData() -{ - emit DataUpdate(); -} - -void QDisplayDataWidget::UpdateWidgets() -{ - emit WidgetUpdate(); -} - -QDataSimpleEdit::QDataSimpleEdit(QWidget* parent, const char* name, BaseData* data): - DataWidget(parent,name,data) -{ -} -bool QDataSimpleEdit::createWidgets() -{ - const QString str = QString( getBaseData()->getValueString().c_str() ); - QLayout* layout = new QHBoxLayout(this); - if( str.length() > TEXTSIZE_THRESHOLD ) - { - innerWidget_.type = TEXTEDIT; - innerWidget_.widget.textEdit = new QTextEdit(this); innerWidget_.widget.textEdit->setText(str); - connect(innerWidget_.widget.textEdit , SIGNAL( textChanged() ), this, SLOT ( setWidgetDirty() ) ); - layout->addWidget(innerWidget_.widget.textEdit); - } - else - { - innerWidget_.type = LINEEDIT; - innerWidget_.widget.lineEdit = new QLineEdit(this); - innerWidget_.widget.lineEdit->setText(str); - connect( innerWidget_.widget.lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT( setWidgetDirty() ) ); - layout->addWidget(innerWidget_.widget.lineEdit); - } - - - - - return true; -} - -void QDataSimpleEdit::setDataReadOnly(bool readOnly) -{ - if(innerWidget_.type == TEXTEDIT) - { - innerWidget_.widget.textEdit->setReadOnly(readOnly); - } - else if(innerWidget_.type == LINEEDIT) - { - innerWidget_.widget.lineEdit->setReadOnly(readOnly); - } -} - -void QDataSimpleEdit::readFromData() -{ - const QString str = QString( getBaseData()->getValueString().c_str() ); - if(innerWidget_.type == TEXTEDIT) - { - innerWidget_.widget.textEdit->setText(str); - } - else if(innerWidget_.type == LINEEDIT) - { - innerWidget_.widget.lineEdit->setText(str); - } -} - -void QDataSimpleEdit::writeToData() -{ - if(!getBaseData()) - return ; - - if(getBaseData()->isReadOnly()) - return ; - std::string value; - if( innerWidget_.type == TEXTEDIT) - { - value = innerWidget_.widget.textEdit->toPlainText().toStdString(); - } - else if( innerWidget_.type == LINEEDIT) - { - value = innerWidget_.widget.lineEdit->text().toStdString(); - } -} - -/* QPoissonRatioWidget */ -QPoissonRatioWidget::QPoissonRatioWidget(QWidget * parent, const char * name, sofa::core::objectmodel::Data *data) - :TDataWidget(parent,name,data) -{ - -} - - -bool QPoissonRatioWidget::createWidgets() -{ - QGridLayout* layout = new QGridLayout(this /*,2,3 */); - - lineEdit = new QLineEdit(this); - lineEdit->setText(QString("-1.0")); - lineEdit->setMaximumSize(lineEdit->size()); - lineEdit->setAlignment(Qt::AlignHCenter); - - lineEdit->setValidator(new QDoubleValidator(0.0,0.5,2,this)); - - layout->addWidget(lineEdit,0,1,Qt::AlignHCenter); - QLabel* min = new QLabel(this); - min->setText(QString("0.0")); - min->setMaximumSize( min->sizeHint() ); - layout->addWidget(min,1,0,Qt::AlignHCenter); - - slider = new QSlider(Qt::Horizontal, this); - slider->setRange(0,50); //max times 10 at the power 2 (2 digits after ".") - slider->setTickPosition(QSlider::TicksBelow); - slider->setTickInterval(5); - layout->addWidget(slider,1,1,Qt::AlignHCenter); - - QLabel* max = new QLabel(this); - max->setText(QString("0.5")); - max->setMaximumSize ( max->sizeHint() ); - - layout->addWidget(max,1,2,Qt::AlignHCenter); - - // synchronization between qslider and qlineedit - connect(slider, SIGNAL( valueChanged(int) ), this, SLOT ( changeLineEditValue() ) ); - connect(slider, SIGNAL( sliderReleased() ), this, SLOT ( changeLineEditValue() ) ); - connect(lineEdit, SIGNAL( textChanged(const QString&) ), this, SLOT (changeSliderValue() ) ); - - // synchronization between the widgets and the modify object dialog box - connect(lineEdit, SIGNAL( textChanged(const QString&) ), this, SLOT( setWidgetDirty() ) ); - connect(slider, SIGNAL( sliderReleased() ), this, SLOT ( setWidgetDirty() ) ); - connect(slider, SIGNAL( valueChanged(int) ), this, SLOT ( setWidgetDirty() ) ); - - - return true; -} - -void QPoissonRatioWidget::setDataReadOnly(bool readOnly) -{ - lineEdit->setReadOnly(readOnly); - slider->setEnabled(!readOnly); -} - -void QPoissonRatioWidget::readFromData() -{ - const double value = this->getData()->getValue(); - QString str; - str.setNum(value); - lineEdit->setText(str); - changeSliderValue(); -} - -void QPoissonRatioWidget::writeToData() -{ - bool ok; - const double d = lineEdit->text().toDouble(&ok); - if(ok) - { - this->getData()->setValue(d); - } -} - -void QPoissonRatioWidget::changeLineEditValue() -{ - const int v = slider->value(); - const double db = (double)v / 100.; - QString str; - str.setNum(db); - lineEdit->setText(str); -} - -void QPoissonRatioWidget::changeSliderValue() -{ - bool ok; - const double v = lineEdit->text().toDouble(&ok); - if(ok) - { - slider->setValue( (int)(v*100.) ); - } -} - -helper::Creator DWClass_Poissonratio("poissonRatio",false); - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.h deleted file mode 100644 index 4b47632a40b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayDataWidget.h +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "DataWidget.h" -#include "ModifyObject.h" - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -class DataWidget; -class QDisplayDataInfoWidget; -struct ModifyObjectFlags; - -class SOFA_GUI_QT_API QDisplayDataWidget : public QGroupBox -{ - Q_OBJECT -public: - QDisplayDataWidget(QWidget* parent, - core::objectmodel::BaseData* data, - const ModifyObjectFlags& flags); - unsigned int getNumWidgets() const { return numWidgets_;} - - ModifyObjectFlags flag() {return flags_;} - -public slots: - void UpdateData(); //QWidgets ---> BaseData - void UpdateWidgets(); //BaseData ---> QWidget -signals: - void WidgetDirty(bool); - void WidgetUpdate(); - void DataUpdate(); - void DataOwnerDirty(bool); - void dataValueChanged(QString); - -protected: - static QIcon& RefreshIcon() - { - static QIcon icon; - if(icon.isNull()) - { - std::string filename = "textures/refresh.png"; - sofa::helper::system::DataRepository.findFile(filename); - icon = QIcon(filename.c_str()); - } - return icon; - } - -protected: - core::objectmodel::BaseData* data_; - ModifyObjectFlags flags_; - QDisplayDataInfoWidget* datainfowidget_; - DataWidget* datawidget_; - unsigned int numWidgets_; - QGridLayout* gridLayout_; -}; - - - -class SOFA_GUI_QT_API QDataSimpleEdit : public DataWidget -{ - Q_OBJECT - typedef enum QEditType { TEXTEDIT, LINEEDIT } QEditType; - typedef union QEditWidgetPtr - { - QLineEdit* lineEdit; - QTextEdit* textEdit; - } QEditWidgetPtr; - - typedef struct QSimpleEdit - { - QEditType type; - QEditWidgetPtr widget; - } QSimpleEdit; -public : - QDataSimpleEdit(QWidget*, const char* name, core::objectmodel::BaseData*); - unsigned int numColumnWidget() override {return 3;} - unsigned int sizeWidget() override {return 6;} - bool createWidgets() override; - void setDataReadOnly(bool readOnly) override; -protected: - void readFromData() override; - void writeToData() override; - QSimpleEdit innerWidget_; -}; - -class SOFA_GUI_QT_API QPoissonRatioWidget : public TDataWidget -{ - Q_OBJECT -public : - QPoissonRatioWidget(QWidget*, const char*, core::objectmodel::Data*); - virtual bool createWidgets(); - virtual void setDataReadOnly(bool readOnly); - -protected slots : - void changeLineEditValue(); - void changeSliderValue(); - -protected: - virtual void readFromData(); - virtual void writeToData(); - QSlider* slider; - QLineEdit* lineEdit; - -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.cpp deleted file mode 100644 index 8eab2ab86cf..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QDisplayLinkWidget.h" -#include "ModifyObject.h" - -#include -#include -#include -#include -#include - -#define TEXTSIZE_THRESHOLD 45 - -namespace sofa::gui::qt -{ - -QDisplayLinkWidget::QDisplayLinkWidget(QWidget* parent, - BaseLink* link, - const ModifyObjectFlags& flags) - : QGroupBox(parent), - link_(link), - linkinfowidget_(nullptr), - linkwidget_(nullptr), - numWidgets_(0) -{ - if(link_ == nullptr) - { - return; - } - - gridLayout_ = new QHBoxLayout(); - this->setLayout(gridLayout_); - - parent->layout()->addWidget(this); - parent->setContentsMargins(0,0,0,0); - - setToolTip(QString::fromStdString(link->getHelp())); - - LinkWidget::CreatorArgument dwarg; - dwarg.name = link_->getName(); - dwarg.link = link_; - dwarg.parent = this; - dwarg.readOnly = (!link_->storePath() && flags.READONLY_FLAG); - - linkwidget_= LinkWidget::CreateLinkWidget(dwarg); - - if (linkwidget_ == nullptr) - { - linkwidget_ = new QLinkSimpleEdit(this,dwarg.link->getName().c_str(), dwarg.link); - linkwidget_->createWidgets(); - linkwidget_->setEnabled(!(dwarg.readOnly)); - assert(linkwidget_ != nullptr); - } - - if(linkwidget_->layout()) - { - linkwidget_->layout()->setAlignment(Qt::AlignCenter); - linkwidget_->layout()->setContentsMargins(2, 2, 2, 2); - } - - linkwidget_->setContentsMargins(0, 10, 0, 0); - linkwidget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - const std::string valuetype = link_->getValueTypeString(); - if (!valuetype.empty()) - linkwidget_->setToolTip(QString::fromStdString(valuetype)); - - numWidgets_ += linkwidget_->sizeWidget(); - connect(linkwidget_,SIGNAL(WidgetDirty(bool)), this, SIGNAL ( WidgetDirty(bool) ) ); - connect(this, SIGNAL( WidgetUpdate() ), linkwidget_, SLOT( updateWidgetValue() ) ); - connect(this, SIGNAL( LinkUpdate() ), linkwidget_, SLOT(setWidgetDirty() ) ); - connect(this, SIGNAL( LinkUpdate() ), linkwidget_, SLOT(updateLinkValue() ) ); - connect(linkwidget_,SIGNAL(LinkOwnerDirty(bool)),this,SIGNAL(LinkOwnerDirty(bool)) ); - - if(flags.PROPERTY_WIDGET_FLAG) - { - if(!dwarg.readOnly) - { - QWidget* refreshWidget = new QWidget(this); - refreshWidget->setFixedSize(QSize(16, 16)); - QPushButton *refresh = new QPushButton(RefreshIcon(), "", refreshWidget); - refresh->setHidden(true); - refresh->setFixedSize(QSize(16, 16)); - refresh->setContentsMargins(0, 0, 0, 0); - - ++numWidgets_; - - connect(linkwidget_,SIGNAL(LinkBeingChanged()), refresh, SLOT ( show() ) ); - connect(refresh, SIGNAL(clicked()), this, SLOT(UpdateLink())); - connect(refresh, SIGNAL(clicked(bool)), refresh, SLOT(setVisible(bool))); - } - - setStyleSheet("QGroupBox{border:0;}"); - setContentsMargins(0, 0, 0, 0); - } - else - { - setTitle(QString::fromStdString(link_->getName())); - setContentsMargins(2,2,4,4); - } - gridLayout_->addWidget(linkwidget_); -} - -void QDisplayLinkWidget::UpdateLink() -{ - emit LinkUpdate(); -} - -void QDisplayLinkWidget::UpdateWidgets() -{ - emit WidgetUpdate(); -} - -QLinkSimpleEdit::QLinkSimpleEdit(QWidget* parent, const char* name, BaseLink* link) - : LinkWidget(parent,name,link) -{ -} - -bool QLinkSimpleEdit::createWidgets() -{ - const QString str = QString::fromStdString(getBaseLink()->getValueString()); - QLayout* layout = new QHBoxLayout(this); - if( str.length() > TEXTSIZE_THRESHOLD ) - { - innerWidget_.type = TEXTEDIT; - innerWidget_.widget.textEdit = new QTextEdit(this); - innerWidget_.widget.textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - innerWidget_.widget.textEdit->setContentsMargins(0, 0, 0, 0); - innerWidget_.widget.textEdit->setText(str); - innerWidget_.widget.textEdit->setFixedHeight(60); - connect(innerWidget_.widget.textEdit , SIGNAL( textChanged() ), this, SIGNAL(LinkBeingChanged())); - connect(innerWidget_.widget.textEdit , SIGNAL( textChanged() ), this, SLOT(update())); - layout->addWidget(innerWidget_.widget.textEdit); - } - else - { - innerWidget_.type = LINEEDIT; - innerWidget_.widget.lineEdit = new QLineEdit(this); - innerWidget_.widget.lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - innerWidget_.widget.lineEdit->setContentsMargins(0, 0, 0, 0); - innerWidget_.widget.lineEdit->setText(str); - connect( innerWidget_.widget.lineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(LinkBeingChanged())); - connect( innerWidget_.widget.lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(update())); - layout->addWidget(innerWidget_.widget.lineEdit); - } - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - - return true; -} - -void QLinkSimpleEdit::readFromLink() -{ - const QString str = QString::fromStdString(getBaseLink()->getValueString()); - if(innerWidget_.type == TEXTEDIT) - { - innerWidget_.widget.textEdit->setText(str); - } - else if(innerWidget_.type == LINEEDIT) - { - innerWidget_.widget.lineEdit->setText(str); - } -} - -void QLinkSimpleEdit::writeToLink() -{ - if(!getBaseLink()) - return ; - - if(getBaseLink()->isReadOnly()) - return; - - std::string value; - if( innerWidget_.type == TEXTEDIT) - { - value = innerWidget_.widget.textEdit->toPlainText().toStdString(); - } - else if( innerWidget_.type == LINEEDIT) - { - value = innerWidget_.widget.lineEdit->text().toStdString(); - } - getBaseLink()->read(value); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.h deleted file mode 100644 index 9b24fcb98d8..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayLinkWidget.h +++ /dev/null @@ -1,108 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "LinkWidget.h" -#include "ModifyObject.h" - -#include -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -class LinkWidget; -class QDisplayLinkInfoWidget; -struct ModifyObjectFlags; - -class SOFA_GUI_QT_API QDisplayLinkWidget : public QGroupBox -{ - Q_OBJECT -public: - QDisplayLinkWidget(QWidget* parent, - core::objectmodel::BaseLink* link, - const ModifyObjectFlags& flags); - unsigned int getNumWidgets() const { return numWidgets_;}; - -public slots: - void UpdateLink(); //QWidgets ---> BaseLink - void UpdateWidgets(); //BaseLink ---> QWidget -signals: - void WidgetDirty(bool); - void WidgetUpdate(); - void LinkUpdate(); - void LinkOwnerDirty(bool); - -protected: - static QIcon& RefreshIcon() - { - static QIcon icon; - if(icon.isNull()) - { - std::string filename = "textures/refresh.png"; - sofa::helper::system::DataRepository.findFile(filename); - icon = QIcon(filename.c_str()); - } - return icon; - } - -protected: - core::objectmodel::BaseLink* link_; - QDisplayLinkInfoWidget* linkinfowidget_; - LinkWidget* linkwidget_; - unsigned int numWidgets_; - QHBoxLayout* gridLayout_; - -}; - - - -class SOFA_GUI_QT_API QLinkSimpleEdit : public LinkWidget -{ - Q_OBJECT - typedef enum QEditType { TEXTEDIT, LINEEDIT } QEditType; - typedef union QEditWidgetPtr - { - QLineEdit* lineEdit; - QTextEdit* textEdit; - } QEditWidgetPtr; - - typedef struct QSimpleEdit - { - QEditType type; - QEditWidgetPtr widget; - } QSimpleEdit; -public : - QLinkSimpleEdit(QWidget*, const char* name, core::objectmodel::BaseLink*); - unsigned int numColumnWidget() override {return 3;} - unsigned int sizeWidget() override {return 1;} - bool createWidgets() override; -protected: - void readFromLink() override; - void writeToLink() override; - QSimpleEdit innerWidget_; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.cpp deleted file mode 100644 index 5caa0d355fc..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "QDisplayPropertyWidget.h" -#include "ModifyObject.h" -#include "DataWidget.h" -#include "QDisplayDataWidget.h" -#include "QDisplayLinkWidget.h" -#include "QDataDescriptionWidget.h" -#include "QTabulationModifyObject.h" -#include - -#include -using sofa::helper::logging::Message ; - -namespace sofa::gui::qt -{ - -QDisplayTreeItemWidget::QDisplayTreeItemWidget(QWidget* parent, QTreeWidgetItem* item) : QWidget(parent) - , treeWidgetItem(item) -{ - -} - -QDisplayTreeItemWidget::~QDisplayTreeItemWidget() -{ - -} - -void QDisplayTreeItemWidget::updateDirtyWidget() -{ - const QObjectList& parentList = children(); - for(QObjectList::const_iterator itParent = parentList.begin(); itParent != parentList.end(); ++itParent) - { - QWidget* parentWidget = dynamic_cast(*itParent); - if(parentWidget) - { - const QObjectList& childList = parentWidget->children(); - for(QObjectList::const_iterator itChild = childList.begin(); itChild != childList.end(); ++itChild) - { - QWidget* childWidget = dynamic_cast(*itChild); - if(childWidget) - { - childWidget->adjustSize(); - childWidget->setHidden(false); - } - } - parentWidget->adjustSize(); - parentWidget->setHidden(false); - } - } - - adjustSize(); - setHidden(false); - treeWidgetItem->setHidden(false); -} - -QDisplayPropertyWidget::QDisplayPropertyWidget(const ModifyObjectFlags& modifyFlags, QWidget* parent) : QTreeWidget(parent) - , objects() - , pinIcon() - , modifyObjectFlags(modifyFlags) -{ - modifyObjectFlags.PROPERTY_WIDGET_FLAG = true; - - std::string filename = "textures/pin.png"; - sofa::helper::system::DataRepository.findFile(filename); - pinIcon = QIcon(QString::fromStdString(filename)); - - setColumnCount(2); - //setIndentation(10); - - headerItem()->setText(0, QString("Property")); - headerItem()->setText(1, QString("Value")); - setSelectionMode(QAbstractItemView::NoSelection); - //setSelectionBehavior(QAbstractItemView::SelectItems); - setDragEnabled(false); - setAcceptDrops(false); - setDropIndicatorShown(false); - //setDragDropMode(QAbstractItemView::InternalMove); - setIndentation(0); - - setFocusPolicy(Qt::NoFocus); - setAutoFillBackground(false); -} - -QDisplayPropertyWidget::~QDisplayPropertyWidget() -{ - -} - -void QDisplayPropertyWidget::addComponent(const QString& component, core::objectmodel::Base* base, QTreeWidgetItem* listItem, bool clear) -{ - if(clear) - this->clear(); - - // return now if the component to add is empty or if it is already in the tree - if(component.isEmpty() || !base || findComponent(component)) - return; - - const sofa::core::objectmodel::Base::VecData& fields = base->getDataFields(); - - // return now if the component has no field - if(fields.empty()) - return; - - // finally, add the group - QTreeWidgetItem *componentItem = new QTreeWidgetItem(this); - QFont *font = new QFont(); - font->setBold(true); - componentItem->setFont(0, *font); - componentItem->setText(0, component); - QPushButton* pin = new QPushButton(this); - pin->setFixedSize(QSize(18, 18)); - pin->setCheckable(true); - pin->setIcon(pinIcon); - setItemWidget(componentItem, 1, pin); - componentItem->setExpanded(true); - const QBrush *backgroundBrush = new QBrush(QColor(20, 20, 20)); - const QBrush *foregroundBrush = new QBrush(QColor(255, 255, 255)); - componentItem->setBackground(0, *backgroundBrush); - componentItem->setForeground(0, *foregroundBrush); - componentItem->setTextAlignment(0, Qt::AlignLeft); - componentItem->setBackground(1, *backgroundBrush); - componentItem->setForeground(1, *foregroundBrush); - componentItem->setTextAlignment(1, Qt::AlignRight); - - objects[componentItem] = std::pair(base, listItem); - - // add data - for(sofa::core::objectmodel::Base::VecData::const_iterator it = fields.begin(); it != fields.end(); ++it) - { - core::objectmodel::BaseData *data = *it; - - // ignore unnamed data - if(data->getName().empty()) - continue; - - // for each data of the current object we determine where it belongs - QString group = QString::fromStdString(data->getGroup()); - - // use the default group if data does not belong to any group - if(group.isEmpty()) - group = DefaultDataGroup(); - - // finally, add the data - addData(component, group, data); - } - - - // add links - const sofa::core::objectmodel::Base::VecLink& links = base->getLinks(); - for(sofa::core::objectmodel::Base::VecLink::const_iterator it = links.begin(); it != links.end(); ++it) - { - core::objectmodel::BaseLink *link = *it; - - // ignore unnamed link - if(link->getName().empty()) - continue; - - if(!link->storePath() && 0 == link->getSize()) - continue; - - // use the default link group - QString group = DefaultLinkGroup(); - - // finally, add the data - addLink(component, group, link); - } - - // add info - { - // use the default info group - const QString group = DefaultInfoGroup(); - - setDescription(component, group, base); - } - - const bool notImplementedYet = false; - if(!notImplementedYet) - // add console - { - // use the default info group - const QString group = DefaultLogGroup(); - - setConsoleOutput(component, group, base); - } -} - -void QDisplayPropertyWidget::addGroup(const QString& component, const QString& group) -{ - // return now if the component does not exist - QTreeWidgetItem *componentItem = nullptr; - componentItem = findComponent(component); - if(!componentItem) - return; - - // return now if the group component already exist - QTreeWidgetItem *groupItem = nullptr; - groupItem = findGroup(component, group); - if(groupItem) - return; - - // assign the default label if group is an empty string - QString groupLabel = group; - if(group.isEmpty()) - groupLabel = DefaultDataGroup(); - - // finally, add the group - groupItem = new QTreeWidgetItem(componentItem); - QFont *font = new QFont(); - font->setBold(true); - groupItem->setFont(0, *font); - groupItem->setText(0, groupLabel); - groupItem->setExpanded(true); - const QBrush *backgroundBrush = new QBrush(QColor(160, 160, 160)); - const QBrush *foregroundBrush = new QBrush(QColor(255, 255, 255)); - groupItem->setBackground(0, *backgroundBrush); - groupItem->setForeground(0, *foregroundBrush); - groupItem->setBackground(1, *backgroundBrush); - groupItem->setForeground(1, *foregroundBrush); -} - -void QDisplayPropertyWidget::addData(const QString& component, const QString& group, sofa::core::objectmodel::BaseData *data) -{ - if(!data || !data->isDisplayed()) - return; - - addGroup(component, group); - QTreeWidgetItem *groupItem = nullptr; - groupItem = findGroup(component, group); - - if(!groupItem) - return; - - QTreeWidgetItem *dataItem = new QTreeWidgetItem(groupItem); - const QBrush *brush = nullptr; - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - dataItem->setBackground(0, *brush); - dataItem->setBackground(1, *brush); - - data->setDisplayed(true); - - QDisplayTreeItemWidget *widget = new QDisplayTreeItemWidget(this, dataItem); - QHBoxLayout *layout = new QHBoxLayout(widget); - - dataItem->setText(0, QString::fromStdString(data->getName())); - dataItem->setToolTip(0, QString::fromStdString(data->getHelp())); - QDisplayDataWidget *displayDataWidget = new QDisplayDataWidget(widget, data, modifyObjectFlags); - layout->addWidget(displayDataWidget); - - connect(displayDataWidget, SIGNAL(WidgetDirty(bool)), widget, SLOT(updateDirtyWidget())); - - widget->setContentsMargins(0, 0, 0, 0); - if(widget->layout()) - { - widget->layout()->setContentsMargins(0, 0, 0, 0); - widget->layout()->setSpacing(0); - } - setItemWidget(dataItem, 1, widget); - dataItem->setToolTip(1, QString::fromStdString(data->getHelp())); -} - -void QDisplayPropertyWidget::addLink(const QString& component, const QString& group, sofa::core::objectmodel::BaseLink *link) -{ - if(!link) - return; - - addGroup(component, group); - QTreeWidgetItem *groupItem = nullptr; - groupItem = findGroup(component, group); - - if(!groupItem) - return; - - QTreeWidgetItem *linkItem = new QTreeWidgetItem(groupItem); - const QBrush *brush = nullptr; - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - linkItem->setBackground(0, *brush); - linkItem->setBackground(1, *brush); - - QDisplayTreeItemWidget *widget = new QDisplayTreeItemWidget(this, linkItem); - QHBoxLayout *layout = new QHBoxLayout(widget); - - ModifyObjectFlags linkFlags = modifyObjectFlags; - linkFlags.READONLY_FLAG = true; - - linkItem->setText(0, QString::fromStdString(link->getName())); - linkItem->setToolTip(0, QString::fromStdString(link->getHelp())); - QDisplayLinkWidget *displayLinkWidget = new QDisplayLinkWidget(widget, link, linkFlags); - layout->addWidget(displayLinkWidget); - - connect(displayLinkWidget, SIGNAL(WidgetDirty(bool)), widget, SLOT(updateDirtyWidget())); - - widget->setContentsMargins(0, 0, 0, 0); - if(widget->layout()) - { - widget->layout()->setContentsMargins(0, 0, 0, 0); - widget->layout()->setSpacing(0); - } - setItemWidget(linkItem, 1, widget); - linkItem->setToolTip(1, QString::fromStdString(link->getHelp())); -} - -void QDisplayPropertyWidget::setDescription(const QString& component, const QString& group, sofa::core::objectmodel::Base *base) -{ - if(!base) - return; - - addGroup(component, group); - QTreeWidgetItem *groupItem = nullptr; - groupItem = findGroup(component, group); - - if(!groupItem) - return; - - const QBrush *brush = nullptr; - QFont categoryFont; - categoryFont.setBold(true); - - // Instance - QTreeWidgetItem *instanceItem = new QTreeWidgetItem(groupItem); - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - - instanceItem->setBackground(0, *brush); - instanceItem->setBackground(1, *brush); - - instanceItem->setText(0, "Instance"); - instanceItem->setFont(0, categoryFont); - - { - addDescriptionItem(groupItem, "Name", QString::fromStdString(base->getName())); - - addDescriptionItem(groupItem, "Class", QString::fromStdString(base->getClassName())); - - const std::string namespacename = sofa::helper::NameDecoder::decodeNamespaceName(typeid(*base)); - if (!namespacename.empty()) - addDescriptionItem(groupItem, "Namespace", QString::fromStdString(namespacename)); - - if (!base->getTemplateName().empty()) - addDescriptionItem(groupItem, "Template", QString::fromStdString(base->getTemplateName())); - } - - // Class - core::ObjectFactory::ClassEntry entry = core::ObjectFactory::getInstance()->getEntry(base->getClassName()); - if(!entry.creatorMap.empty()) - { - QTreeWidgetItem *classItem = new QTreeWidgetItem(groupItem); - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - - classItem->setBackground(0, *brush); - classItem->setBackground(1, *brush); - - classItem->setText(0, "Class"); - classItem->setFont(0, categoryFont); - - if(!entry.description.empty() && std::string("TODO") != entry.description) - addDescriptionItem(groupItem, "Description", QString::fromStdString(entry.description)); - - const core::ObjectFactory::CreatorMap::iterator it = entry.creatorMap.find(base->getTemplateName()); - if(entry.creatorMap.end() != it && *it->second->getTarget()) - addDescriptionItem(groupItem, "Provided by", QString(it->second->getTarget())); - - if(!entry.authors.empty() && std::string("TODO") != entry.authors) - addDescriptionItem(groupItem, "Authors", QString::fromStdString(entry.authors)); - - if(!entry.license.empty() && std::string("TODO") != entry.license) - addDescriptionItem(groupItem, "License", QString::fromStdString(entry.license)); - } -} - -void QDisplayPropertyWidget::addDescriptionItem(QTreeWidgetItem *groupItem, const QString& name, const QString& description) -{ - QTreeWidgetItem *descriptionItem = new QTreeWidgetItem(groupItem); - - const QBrush *brush = nullptr; - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - - descriptionItem->setBackground(0, *brush); - descriptionItem->setBackground(1, *brush); - - descriptionItem->setText(0, name); - - QDisplayTreeItemWidget *widget = new QDisplayTreeItemWidget(this, descriptionItem); - new QLabel(description, widget); - setItemWidget(descriptionItem, 1, widget); -} - -void QDisplayPropertyWidget::setConsoleOutput(const QString& component, const QString& group, sofa::core::objectmodel::Base *base) -{ - if(base==nullptr) - return; - - const std::string warnings = base->getLoggedMessagesAsString( { Message::Warning, - Message::Error, - Message::Fatal } ); - - const std::string infos = base->getLoggedMessagesAsString( { Message::Info, - Message::Advice, - Message::Deprecated } ); - - if((infos.empty() && warnings.empty())) - return; - - addGroup(component, group); - QTreeWidgetItem *groupItem = nullptr; - groupItem = findGroup(component, group); - - if(!groupItem) - return; - - // log outputs - if(!infos.empty()) - { - QTreeWidgetItem *consoleItem = new QTreeWidgetItem(groupItem); - const QBrush *brush = nullptr; - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - consoleItem->setBackground(0, *brush); - consoleItem->setBackground(1, *brush); - - QDisplayTreeItemWidget *clearWidget = new QDisplayTreeItemWidget(this, consoleItem); - QVBoxLayout *clearLayout = new QVBoxLayout(clearWidget); - - QPushButton* clearButton = new QPushButton("Clear output", clearWidget); - clearButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - clearButton->setFixedHeight(200); -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - clearButton->setProperty("base", qVariantFromValue((void*) base)); -#else - clearButton->setProperty("base", QVariant::fromValue((void*) base)); -#endif - clearLayout->addWidget(clearButton); - - clearWidget->setContentsMargins(0, 0, 0, 0); - clearLayout->setContentsMargins(0, 0, 0, 0); - clearLayout->setSpacing(0); - - QDisplayTreeItemWidget *logWidget = new QDisplayTreeItemWidget(this, consoleItem); - QVBoxLayout *logLayout = new QVBoxLayout(logWidget); - - QTextEdit* textEdit = new QTextEdit(QString::fromStdString(infos), logWidget); - textEdit->setText(QString::fromStdString(infos)); - textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - textEdit->setFixedHeight(200); - textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); - textEdit->ensureCursorVisible(); - logLayout->addWidget(textEdit); - - logWidget->setContentsMargins(0, 0, 0, 0); - logLayout->setContentsMargins(0, 0, 0, 0); - logLayout->setSpacing(0); - - connect(clearButton, SIGNAL(clicked()), textEdit, SLOT(clear())); - connect(clearButton, SIGNAL(clicked()), this, SLOT(clearComponentOutput())); - - setItemWidget(consoleItem, 0, clearWidget); - setItemWidget(consoleItem, 1, logWidget); - } - - // warnings output - if(!warnings.empty()) - { - QTreeWidgetItem *consoleItem = new QTreeWidgetItem(groupItem); - const QBrush *brush = nullptr; - if(groupItem->childCount() % 2 == 0) - brush = new QBrush(QColor(255, 255, 191)); - else - brush = new QBrush(QColor(255, 255, 222)); - consoleItem->setBackground(0, *brush); - consoleItem->setBackground(1, *brush); - - QDisplayTreeItemWidget *clearWidget = new QDisplayTreeItemWidget(this, consoleItem); - QVBoxLayout *clearLayout = new QVBoxLayout(clearWidget); - - QPushButton* clearButton = new QPushButton("Clear warning", clearWidget); - clearButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - clearButton->setFixedHeight(200); -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - clearButton->setProperty("base", qVariantFromValue((void*) base)); -#else - clearButton->setProperty("base", QVariant::fromValue((void*) base)); -#endif - clearLayout->addWidget(clearButton); - - clearWidget->setContentsMargins(0, 0, 0, 0); - clearLayout->setContentsMargins(0, 0, 0, 0); - clearLayout->setSpacing(0); - - QDisplayTreeItemWidget *logWidget = new QDisplayTreeItemWidget(this, consoleItem); - QVBoxLayout *logLayout = new QVBoxLayout(logWidget); - - QTextEdit* textEdit = new QTextEdit(logWidget); - textEdit->setText(QString::fromStdString(warnings)); - textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - textEdit->setFixedHeight(200); - textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); - textEdit->ensureCursorVisible(); - logLayout->addWidget(textEdit); - - logWidget->setContentsMargins(0, 0, 0, 0); - logLayout->setContentsMargins(0, 0, 0, 0); - logLayout->setSpacing(0); - - connect(clearButton, SIGNAL(clicked()), textEdit, SLOT(clear())); - connect(clearButton, SIGNAL(clicked()), this, SLOT(clearComponentWarning())); - - setItemWidget(consoleItem, 0, clearWidget); - setItemWidget(consoleItem, 1, logWidget); - } -} - -void QDisplayPropertyWidget::clear() -{ - QTreeWidgetItem *item = nullptr; - const QPushButton* pin = nullptr; - for(unsigned int i = 0; (item = topLevelItem(i));) - { - pin = static_cast(itemWidget(item, 1)); - if(pin && !pin->isChecked()) - { - objects.erase(objects.find(item)); - takeTopLevelItem(i); - } - else - ++i; - } -} - -void QDisplayPropertyWidget::clearAll() -{ - QTreeWidget::clear(); -} - -void QDisplayPropertyWidget::clearComponentOutput() -{ - const QObject* signalEmitter = sender(); - if(nullptr == signalEmitter) - return; - - const QVariant variant = signalEmitter->property("base"); - const sofa::core::objectmodel::Base* base = static_cast(variant.value()); - if(base) - base->clearLoggedMessages(); -} - -void QDisplayPropertyWidget::clearComponentWarning() -{ - const QObject* signalEmitter = sender(); - if(nullptr == signalEmitter) - return; - - const QVariant variant = signalEmitter->property("base"); - const sofa::core::objectmodel::Base* base = static_cast(variant.value()); - if(base) - base->clearLoggedMessages(); -} - -QTreeWidgetItem* QDisplayPropertyWidget::findComponent(const QString& component) const -{ - QTreeWidgetItem *componentItem = nullptr; - for(unsigned int i = 0; (componentItem = topLevelItem(i)); ++i) - if(componentItem->text(0) == component) - break; - - return componentItem; -} - -QTreeWidgetItem* QDisplayPropertyWidget::findGroup(const QString& component, const QString& group) const -{ - const QTreeWidgetItem *componentItem = nullptr; - componentItem = findComponent(component); - if(!componentItem) - return nullptr; - - QTreeWidgetItem *groupItem = nullptr; - for(unsigned int i = 0; (groupItem = componentItem->child(i)); ++i) - if(groupItem->text(0) == group) - break; - - return groupItem; -} - -/*void QDisplayPropertyWidget::dragEnterEvent(QDragEnterEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if(!index.isValid() && !index.parent().isValid()) - return; - - std::cout << index.row() << " - " << index.column() << std::endl; - QTreeWidgetItem* source = itemFromIndex(index); - if(source->checkState(0) == Qt::Unchecked) - return; - - QTreeWidget::dragEnterEvent(event); -} - -void QDisplayPropertyWidget::dropEvent(QDropEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if(!index.isValid() && !index.parent().isValid()) - return; - - std::cout << index.row() << " - " << index.column() << std::endl; - QTreeWidgetItem* target = itemFromIndex(index); - if(target->checkState(0) == Qt::Unchecked) - return; - - QTreeWidget::dropEvent(event); -}*/ - -/*void QDisplayPropertyWidget::dragMoveEvent(QDragMoveEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - QTreeWidgetItem* source = itemFromIndex(index); - if(source->checkState(0) == Qt::Checked) - event->accept(); -} - -void QDisplayPropertyWidget::dragLeaveEvent(QDragLeaveEvent *event) -{ -// QModelIndex index = indexAt(event->pos()); -// QTreeWidgetItem* source = itemFromIndex(index); -// if(source->checkState(0) == Qt::Checked) -// event->accept(); -} - -Qt::DropActions QDisplayPropertyWidget::supportedDropActions() const -{ - return Qt::CopyAction | Qt::MoveAction; -}*/ - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.h deleted file mode 100644 index 7ed192622a6..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QDisplayPropertyWidget.h +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include - -#include -#include -#include -#include -#if SOFA_GUI_QT_HAVE_QT_CHARTS -#include -#endif -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QDisplayTreeItemWidget : public QWidget -{ - Q_OBJECT - -public: - // constructor / destructor - QDisplayTreeItemWidget(QWidget* parent=nullptr, QTreeWidgetItem* item=nullptr); - ~QDisplayTreeItemWidget() override; - -protected slots: - // resize the corresponding TreeItem when the Widget size changes - void updateDirtyWidget(); - -private: - QTreeWidgetItem* treeWidgetItem; -}; - -// QDisplayPropertyWidget describe a widget where you can view and edit every properties of Sofa components -class SOFA_GUI_QT_API QDisplayPropertyWidget : public QTreeWidget -{ - Q_OBJECT - - friend class GraphHistoryManager; - friend class LinkComponent; - -public: - // constructor / destructor - QDisplayPropertyWidget(const ModifyObjectFlags& modifyFlags, QWidget* parent=nullptr); - ~QDisplayPropertyWidget() override; - - // add a component in the tree in order to show / change its data and compare them with other component data - void addComponent(const QString& component, core::objectmodel::Base* base, QTreeWidgetItem* listItem, bool clear = true); - - // add a data / link group - void addGroup(const QString& component, const QString& group); - - // add a component data to show / change its value - void addData(const QString& component, const QString& group, sofa::core::objectmodel::BaseData *data); - - // add a component link to show / change its value - void addLink(const QString& component, const QString& group, sofa::core::objectmodel::BaseLink *link); - - // set a component description - void setDescription(const QString& component, const QString& group, sofa::core::objectmodel::Base *base); - - // set a component console output - void setConsoleOutput(const QString& component, const QString& group, sofa::core::objectmodel::Base *base); - -protected: - // add a description item - void addDescriptionItem(QTreeWidgetItem *groupItem, const QString& name, const QString& description); - -public: - // clear non-pinned components, theirs groups, data and links - void clear(); - - // clear everything, even pinned components - void clearAll(); - - // name of the default property group - static QString DefaultDataGroup() {return "Property";} - static QString DefaultLinkGroup() {return "Link";} - static QString DefaultInfoGroup() {return "Info";} - static QString DefaultLogGroup() {return "Log";} - -protected slots: - // retrieve the component stored as a property in the signal emitter and clear its output messages - void clearComponentOutput(); - - // retrieve the component stored as a property in the signal emitter and clear its warning messages - void clearComponentWarning(); - -protected: - // find a component by name - QTreeWidgetItem* findComponent(const QString& component) const; - - // find a group by name - QTreeWidgetItem* findGroup(const QString& component, const QString& group) const; - - /*void dragEnterEvent(QDragEnterEvent *event); - //void dragMoveEvent(QDragMoveEvent *event); - //void dragLeaveEvent(QDragLeaveEvent *event); - void dropEvent(QDropEvent *event); - Qt::DropActions supportedDropActions() const;*/ - -private: - - // remember the Base Object and its item in the scene graph list view for each component registered in this property view - std::map > objects; - QIcon pinIcon; - ModifyObjectFlags modifyObjectFlags; - -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.cpp deleted file mode 100644 index a22f1f68a9e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include -#include -#include - -#include - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -using namespace QtCharts; -#endif - -namespace sofa::gui::qt -{ - -QEnergyStatWidget::QEnergyStatWidget( QWidget* parent, simulation::Node* node ) - : QGraphStatWidget( parent, node, "Energy", 3, 500 ) -{ - setCurve( 0, "Kinetic", Qt::red ); - setCurve( 1, "Potential", Qt::green ); - setCurve( 2, "Mechanical", Qt::blue ); - - m_energyVisitor = new sofa::simulation::mechanicalvisitor::MechanicalComputeEnergyVisitor(core::mechanicalparams::defaultInstance()); -} - -QEnergyStatWidget::~QEnergyStatWidget() -{ - delete m_energyVisitor; -} - -void QEnergyStatWidget::stepImpl() -{ - if (m_curves.size() != 3) { - msg_warning("QEnergyStatWidget") << "Wrong number of curves: " << m_curves.size() << ", should be 3."; - return; - } - m_energyVisitor->execute(m_node->getContext() ); - - // Update series - const SReal time = m_node->getTime(); - const SReal kinectic = m_energyVisitor->getKineticEnergy(); - const SReal potential = m_energyVisitor->getPotentialEnergy(); - - m_curves[0]->append(time, kinectic); - m_curves[1]->append(time, potential); - //Add Mechanical Energy - m_curves[2]->append(time, kinectic + potential); - - // update maxY - updateYAxisBounds(kinectic + potential); - - // update minY - if (kinectic < potential) - updateYAxisBounds(kinectic); - else - updateYAxisBounds(potential); -} - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.h deleted file mode 100644 index 94cada38460..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QEnergyStatWidget.h +++ /dev/null @@ -1,53 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -namespace sofa::simulation::mechanicalvisitor -{ - class MechanicalComputeEnergyVisitor; -} - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QEnergyStatWidget : public QGraphStatWidget -{ - - Q_OBJECT - - sofa::simulation::mechanicalvisitor::MechanicalComputeEnergyVisitor *m_energyVisitor { nullptr }; - - -public: - - QEnergyStatWidget( QWidget* parent, simulation::Node* node ); - - ~QEnergyStatWidget(); - - void stepImpl() override; - -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.cpp deleted file mode 100644 index b806ba88793..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include - -namespace sofa::gui::qt -{ - -QGraphStatWidget::QGraphStatWidget( QWidget* parent, simulation::Node* node, const QString& title, unsigned numberOfCurves, int bufferSize) - : QWidget( parent ) - , m_node( node ) - , m_bufferSize(bufferSize) - , m_yMin(10000) - , m_yMax(-10000) - , m_lastTime(0.0) - , m_cptStep(0) -{ - QVBoxLayout *layout = new QVBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(1); - layout->setObjectName(QString( "tabStats" ) + title); - - m_chart = new QChart(); - QFont font; - font.setPixelSize(18); - m_chart->setTitleFont(font); - m_chart->setTitle(title); - - m_axisX = new QValueAxis(); - m_axisX->setRange(0, m_node->getDt()*m_bufferSize); - m_axisX->setTitleText("Time (ms)"); - - m_axisY = new QValueAxis(); - m_axisY->setTitleText("Value"); - - m_chart->addAxis(m_axisX, Qt::AlignBottom); - m_chart->addAxis(m_axisY, Qt::AlignLeft); - m_chart->legend()->setAlignment(Qt::AlignBottom); - - QChartView* chartView = new QChartView(m_chart, this); - layout->addWidget(chartView); - - m_curves.resize(numberOfCurves); - -} - -QGraphStatWidget::~QGraphStatWidget() -{ - -} - -void QGraphStatWidget::step() -{ - const SReal time = m_node->getTime(); - if (time <= m_lastTime) - return; - - // call internal method to add Data into series - stepImpl(); - - if (m_cptStep > m_bufferSize) // start swipping the Xaxis - { - const qreal min = m_axisX->min() + m_node->getDt(); - m_axisX->setRange(min, time); - - // flush series data not anymore display for memory storage - if ((m_cptStep% m_bufferSize * 2) == 0) - { - flushSeries(); - } - } - - if ((m_cptStep% m_bufferSize) == 0) - { - if (m_axisY->max() > m_yMax) - m_axisY->setMax(m_yMax*1.01); - - if (m_axisY->min() < m_yMin) - m_axisY->setMin(m_yMin*0.99); - - m_yMax = -10000; - m_yMin = 10000; - } - - m_lastTime = time; - m_cptStep++; -} - - -void QGraphStatWidget::flushSeries() -{ - for (const auto serie : m_curves) - { - if (serie->count() >= m_bufferSize) { - serie->removePoints(0, m_bufferSize); - } - } -} - - -void QGraphStatWidget::setCurve( unsigned index, const QString& name, const QColor& color ) -{ - if (index >= m_curves.size()) - { - m_curves.resize(index+1); - } - - m_curves[index] = new QLineSeries(); - m_curves[index]->setName(name); - m_curves[index]->setPen(QPen(color)); - - m_chart->addSeries(m_curves[index]); - - m_curves[index]->attachAxis(m_axisY); - m_curves[index]->attachAxis(m_axisX); -} - - -void QGraphStatWidget::updateYAxisBounds(SReal value) -{ - if (value > m_axisY->max()) - { - m_axisY->setMax(value*1.01); - } - if (value < m_axisY->min()) - { - m_axisY->setMin(value*0.99); - } - - // for record - if (value > m_yMax) - { - m_yMax = value; - } - - if (value < m_yMin) - { - m_yMin = value; - } -} - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.h deleted file mode 100644 index 9026a1e58a2..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QGraphStatWidget.h +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -using namespace QtCharts; -#endif - -namespace sofa::gui::qt -{ - -/// Base class to make graphes in the stat tab of the node widget -/// TODO add gnuplot export -class QGraphStatWidget : public QWidget -{ - Q_OBJECT - -public: - QGraphStatWidget( QWidget* parent, simulation::Node* node, const QString& title, unsigned numberOfCurves, int bufferSize ); - virtual ~QGraphStatWidget(); - - /// Main method called to update the graph - virtual void step() final; - - /// the only function that should be overloaded - virtual void stepImpl() = 0; - -protected: - /// set the index-th curve (index must be < _numberOfCurves) - void setCurve( unsigned index, const QString& name, const QColor& color ); - - /// Method to update Y axis scale - void updateYAxisBounds(SReal value); - - /// flush data from series not anymore displayed - void flushSeries(); - - /// pointer to the node monitored - simulation::Node *m_node; - - /// size of the buffers to stored - int m_bufferSize; - - /// Pointer to the chart Data - QChart *m_chart; - - /// vector of series to be plotted - std::vector< QLineSeries *> m_curves; - - /// x axis pointer - QValueAxis* m_axisX; - /// y axis pointer - QValueAxis* m_axisY; - - /// min y axis value stored - SReal m_yMin; - /// max y axis value stored - SReal m_yMax; - /// last timestep monitored - SReal m_lastTime; - /// step counter monitored - int m_cptStep; -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.cpp deleted file mode 100644 index b587aeeec0e..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "QMenuFilesRecentlyOpened.h" - -#include -#include -#include - - -namespace sofa::gui::qt -{ - -void QMenuFilesRecentlyOpened::updateWidget() -{ - //Clear the current widget - menuRecentlyOpenedFiles->clear(); - //while (menuRecentlyOpenedFiles->actions().count()) - // menuRecentlyOpenedFiles->removeAction(menuRecentlyOpenedFiles->actions()[0]); - //Add the content of files - for (unsigned int i=0; iaddAction(QString(files[i].c_str())); -} - -QMenu *QMenuFilesRecentlyOpened::createWidget(QWidget *parent, const std::string &name) -{ - menuRecentlyOpenedFiles = new QMenu(QString(name.c_str()), parent); - menuRecentlyOpenedFiles->setTearOffEnabled(true); - - updateWidget(); - return menuRecentlyOpenedFiles; -} - -void QMenuFilesRecentlyOpened::openFile(const std::string &file) -{ - FilesRecentlyOpenedManager::openFile(file); - updateWidget(); - writeFiles(); -} - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.h deleted file mode 100644 index 127fc981f1b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMenuFilesRecentlyOpened.h +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -#include - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QMenuFilesRecentlyOpened: public common::FilesRecentlyOpenedManager -{ -public: - QMenuFilesRecentlyOpened(const std::string &configFile):common::FilesRecentlyOpenedManager(configFile),menuRecentlyOpenedFiles(nullptr) {} - ~QMenuFilesRecentlyOpened() override {if (menuRecentlyOpenedFiles) delete menuRecentlyOpenedFiles;} - void openFile(const std::string &file) override; - - QMenu *createWidget(QWidget *parent, const std::string& =std::string("Recently Opened Files ...")); - QMenu *getMenu() {return menuRecentlyOpenedFiles;} - -protected: - void updateWidget(); - QMenu *menuRecentlyOpenedFiles; - - -}; - - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableDataContainer.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableDataContainer.h deleted file mode 100644 index 3745cdc13e7..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableDataContainer.h +++ /dev/null @@ -1,751 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "SimpleDataWidget.h" -#include "StructDataWidget.h" -#include - -#include "QMouseWheelAdjustementGuard.h" -#include "QModelViewTableUpdater.h" -#include "QDisplayDataWidget.h" - -#include -#include -#include - -#include - -namespace sofa::gui::qt -{ - -enum -{ - TYPE_SINGLE = 0, - TYPE_VECTOR = 1, - TYPE_STRUCT = 2, -}; - -template -class flat_data_trait; - -template -class default_flat_data_trait : public flat_data_trait< T, ( (struct_data_trait::NVAR >1 ) ? TYPE_STRUCT : ( (vector_data_trait::NDIM > 0) ? TYPE_VECTOR : TYPE_SINGLE ) ) > {}; - - - -template inline std::string toString(const T& v) -{ - std::ostringstream o; - o << v; - return o.str(); -} - -inline std::string toString(const std::string& s) -{ - return s; -} - -template inline void fromString(const std::string& s, T& v) -{ - std::istringstream i(s); - i >> v; -} - -inline void fromString(const std::string& s, std::string& v) -{ - v = s; -} - -template -class flat_data_trait -{ -public: - enum { is_struct = 0 }; - enum { is_vector = 0 }; - enum { is_single = 1 }; - typedef T data_type; - typedef T value_type; - static int size() { return 1; } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, int /*i*/ = 0) { return &d; } - static void set(const value_type& v, data_type& d, int /*i*/ = 0) { d = v; } - static void setS(const std::string& v, data_type& d, int /*i*/ = 0) - { - fromString(v, d); - } -}; - -template::NVAR> -class flat_struct_data_trait -{ -public: - enum { is_struct = 1 }; - enum { is_vector = 0 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR > 1) ? 1 : 0) }; - typedef T data_type; - typedef std::string value_type; - typedef struct_data_trait shelper; - typedef struct_data_trait_var vhelper; - typedef typename vhelper::value_type vtype; - typedef default_flat_data_trait vtrait; - typedef typename vtrait::value_type iotype; - typedef flat_struct_data_trait prev; - static int size() { return prev::size() + vtrait::size(); } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& d, int i = 0) - { - const int s = prev::size(); - if (i < s) - return prev::header(d, i); - else - { - const char* h1 = vhelper::shortname(); - const char* h2 = vtrait::header(*vhelper::get(d), i-s); - if (h2 == nullptr) return h1; - else if (h1 == nullptr) return h2; - else - { - static std::string t; - t = h1; - t += " "; - t += h2; - return t.c_str(); - } - } - } - static value_type* get(const data_type& d, int i = 0) - { - const int s = prev::size(); - if (i < s) - return prev::get(d, i); - else - { - static std::string t; - t = toString(*vtrait::get(*vhelper::get(d), i-s)); - return &t; - } - } - static void setS(const std::string& v, data_type& d, int i = 0) - { - const int s = prev::size(); - if (i < s) - prev::setS(v, d, i); - else - { - vtype var = *vhelper::get(d); - vtrait::setS(v, var,i-s); - vhelper::set(var, d); - } - } - static void set(const value_type& v, data_type& d, int i = 0) - { - setS(v, d, i); - } -}; - -template -class flat_struct_data_trait -{ -public: - enum { is_struct = 1 }; - enum { is_vector = 0 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR > 1) ? 1 : 0) }; - typedef T data_type; - typedef std::string value_type; - typedef struct_data_trait shelper; - static int size() { return 0; } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return nullptr; - } - static value_type* get(const data_type& /*d*/, int /*i*/ = 0) - { - return nullptr; - } - static void setS(const std::string& /*v*/, data_type& /*d*/, int /*i*/ = 0) - { - } - static void set(const value_type& /*v*/, data_type& /*d*/, int /*i*/ = 0) - { - } -}; - -template -class flat_data_trait : public flat_struct_data_trait -{ -}; - -template -class flat_vector_data_trait -{ -public: - enum { is_struct = 0 }; - enum { is_vector = 1 }; - enum { is_single = 0 }; - enum { is_default = ((struct_data_trait::NVAR == 1 && vector_data_trait::NDIM >= 1) ? 1 : 0) }; - typedef T data_type; - typedef vector_data_trait vhelper; - typedef typename vhelper::value_type vtype; - typedef default_flat_data_trait vtrait; - typedef typename vtrait::value_type value_type; - static int size() { return vhelper::SIZE * vtrait::size(); } - static int size(const data_type&) { return size(); } - static const char* header(const data_type& d, int i = 0) - { - const int s = vtrait::size(); - int j = i / s; - i = i % s; - const char* h1 = vhelper::header(d, j); - const char* h2 = vtrait::header(*vhelper::get(d, j), i); - if (h2 == nullptr) return h1; - else if (h1 == nullptr) return h2; - else - { - static std::string t; - t = h1; - t += " "; - t += h2; - return t.c_str(); - } - } - static const value_type* get(const data_type& d, int i = 0) - { - const int s = vtrait::size(); - int j = i / s; - i = i % s; - return vtrait::get(*vhelper::get(d, j), i); - } - static void set(const value_type& v, data_type& d, int i = 0) - { - const int s = vtrait::size(); - int j = i / s; - i = i % s; - vtype t = *vhelper::get(d, j); - vtrait::set(v, t, i); - vhelper::set(t, d, j); - } - static void setS(const std::string& v, data_type& d, int i = 0) - { - const int s = vtrait::size(); - int j = i / s; - i = i % s; - vtype t = *vhelper::get(d, j); - vtrait::setS(v, t, i); - vhelper::set(t, d, j); - } -}; - -template -class flat_data_trait : public flat_vector_data_trait -{ -}; - -enum -{ - TABLE_NORMAL = 0, - TABLE_HORIZONTAL = 1 << 0, - TABLE_FIXEDSIZE = 1 << 1, -}; - - - -template -class table_data_widget_container -{ -public: - typedef T data_type; - typedef vector_data_trait rhelper; - typedef typename rhelper::value_type row_type; - typedef default_flat_data_trait vhelper; - typedef typename vhelper::value_type value_type; - typedef QVBoxLayout Layout; - - QSpinBox* wSize; - QTableViewUpdater* wTableView; - QTableModelUpdater* wTableModel; - QPushButtonUpdater* wDisplay; - DataWidget * widget; - Layout* container_layout; - - int rows; - int cols; - - table_data_widget_container() : wSize(nullptr), wTableView(nullptr), wDisplay(nullptr), widget(nullptr), container_layout(nullptr) {} - - bool createLayout( DataWidget* parent ) - { - if( parent->layout() != nullptr || container_layout != nullptr) return false; - container_layout = new Layout(parent); - return true; - } - - bool createLayout( QLayout* layout) - { - if ( container_layout != nullptr ) return false; - container_layout = new Layout(); - layout->addItem(container_layout); - return true; - } - - void setCellText(int r, int c, const std::string& s) - { - if (FLAGS & TABLE_HORIZONTAL) - { - QStandardItem* item= wTableModel->item(c,r); - if (!item) wTableModel->setItem(c, r, new QStandardItem(QString(s.c_str()))); - else item->setText(QString(s.c_str())); - } - else - { - QStandardItem* item= wTableModel->item(r,c); - if (!item) wTableModel->setItem(r, c, new QStandardItem(QString(s.c_str()))); - else item->setText(QString(s.c_str())); - } - } - std::string getCellText(int r, int c) - { - QStandardItem *item; - QString text; - if (FLAGS & TABLE_HORIZONTAL) - item=wTableModel->item(c,r); - else - item=wTableModel->item(r,c); - - if (item) - { - text=item->text(); - - if (!text.isNull()) - return std::string(text.toStdString()); - } - return std::string(""); - } - - template - void setCell(int r, int c, const V& v) - { - std::ostringstream o; - o << v; - setCellText(r,c, o.str()); - } - void setCell(int r, int c, const std::string& s) - { - setCellText(r, c, s); - } - template - void getCell(int r, int c, V& v) - { - std::istringstream i(getCellText(r,c)); - i >> v; - } - void getCell(int r, int c, const std::string& s) - { - s = getCellText(r,c); - } - - bool createWidgets(DataWidget* parent, const data_type& d, bool readOnly) - { - rows = 0; - const int dataRows = rhelper::size(d); - - wSize = new QSpinBox(parent); - wSize->setMinimum(0); - wSize->setMaximum(INT_MAX); - wSize->setSingleStep(1); - wSize->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - /// Activates the scrolling only when the widget is selected and not when it is - /// hovering. - wSize->setFocusPolicy(Qt::StrongFocus); - - wSize->installEventFilter(new QMouseWheelAdjustmentGuard(wSize)); - - wDisplay = new QPushButtonUpdater( QString("Display the values"), parent); - wDisplay->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - - if (dataRows > 0) - cols = vhelper::size(*rhelper::get(d,0)); - else - cols = vhelper::size(row_type()); - - if (FLAGS & TABLE_HORIZONTAL) - wTableModel = new QTableModelUpdater(cols,dataRows,parent); - else - wTableModel = new QTableModelUpdater(dataRows,cols,parent); - - wTableView = new QTableViewUpdater(parent); - wTableView->setModel(wTableModel); - - widget=parent; - - wDisplay->setCheckable(true); - QWidget* parentWidget = parent; - if(parentWidget) - parentWidget = static_cast(parentWidget->parent()); - bool propertyWidgetFlagOn = false; - QDisplayDataWidget* displayDataWidget = dynamic_cast(parentWidget); - if(displayDataWidget) - propertyWidgetFlagOn = displayDataWidget->flag().PROPERTY_WIDGET_FLAG; - - parent->setFilled(false); - rows = dataRows; - - wSize->setValue(dataRows); - - wTableView->setDisplayed(isDisplayed()); - - if (readOnly) - { - wSize->setEnabled(false); - wTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - } - else - { - if (!(FLAGS & TABLE_FIXEDSIZE)) - { - parent->connect(wSize, SIGNAL( valueChanged(int) ), parent, SLOT( setWidgetDirty() )); - - if( FLAGS & TABLE_HORIZONTAL) - parent->connect(wSize, SIGNAL( valueChanged(int) ), wTableModel, SLOT(resizeTableH(int) ) ); - else - parent->connect(wSize, SIGNAL( valueChanged(int) ), wTableModel, SLOT(resizeTableV(int) ) ); - } - else - { - wSize->setEnabled(false); - } - } - parent->connect(wDisplay, SIGNAL( toggled(bool) ), wTableView, SLOT(setDisplayed(bool))); - parent->connect(wDisplay, SIGNAL( toggled(bool) ), wDisplay, SLOT(setDisplayed(bool))); - parent->connect(wDisplay, SIGNAL( toggled(bool) ), parent, SLOT(fillFromData() )); - - if (!propertyWidgetFlagOn) - wDisplay->setChecked(dataRows < MAX_NUM_ELEM && dataRows != 0); - else - wDisplay->setChecked(false); - - wDisplay->setAutoDefault(false); - - return true; - } - - - void setReadOnly(bool readOnly) - { - wSize->setEnabled(!readOnly); - if (readOnly) - { - wTableModel->setReadOnly(true); - wTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - QObject::disconnect(wTableView, SIGNAL( activated(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - QObject::disconnect(wTableView, SIGNAL( pressed(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - QObject::disconnect(wTableView, SIGNAL( clicked(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - }else{ - QObject::connect(wTableView, SIGNAL( activated(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - QObject::connect(wTableView, SIGNAL( pressed(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - QObject::connect(wTableView, SIGNAL( clicked(QModelIndex) ) , widget, SLOT(setWidgetDirty()) ); - } - } - - bool isDisplayed() - { - return (wDisplay->isChecked()); - } - - - void readFromData(const data_type& d) - { - if (isDisplayed()) - { - processTableModifications(d); - fillTable(d); - } - } - void writeToData(data_type& d) - { - rows = wSize->value(); - if (!(FLAGS & TABLE_FIXEDSIZE)) - { - const int oldrows = rhelper::size(d); - if( rows != oldrows) - { - rhelper::resize(rows,d); - } - const int newrows = rhelper::size(d); - if( rows != newrows) - { - wSize->setValue(newrows); - rows = newrows; - if (FLAGS & TABLE_HORIZONTAL) - wTableModel->setColumnCount(newrows); - else - wTableModel->setRowCount(newrows); - } - } - - processTableModifications(d); - - if (isDisplayed()) - { - for (int y=0; ycolumnCount(); - else - currentTableNumRows=wTableModel->rowCount(); - const int rowSize = wSize->value(); - - QStringList horizontalHeaders; - QStringList verticalHeaders; - - for (int x=0; x 0) ? vhelper::header(*rhelper::get(d,0),x) : vhelper::header(row_type(),x); - - if (h && *h) - horizontalHeaders << h; - else - horizontalHeaders << QString::number(x); - } - - if (FLAGS & TABLE_HORIZONTAL) - wTableModel->setVerticalHeaderLabels(horizontalHeaders); - else - wTableModel->setHorizontalHeaderLabels(horizontalHeaders); - - - for (int y=0; ysetHorizontalHeaderLabels(verticalHeaders); - else - wTableModel->setVerticalHeaderLabels(verticalHeaders); - - if (rowSize == currentTableNumRows) - { - return; - } - - - if (FLAGS & TABLE_HORIZONTAL) - wTableModel->setColumnCount(rowSize); - else - wTableModel->setRowCount(rowSize); - - for (int y=currentTableNumRows; ysetHorizontalHeaderLabels(verticalHeaders); - else - wTableModel->setVerticalHeaderLabels(verticalHeaders); - - } - - void fillTable(const data_type &d) - { - int currentNum; - const int dsize = (int)d.size(); - if (FLAGS & TABLE_HORIZONTAL) - currentNum=wTableModel->columnCount() > dsize ? dsize : wTableModel->columnCount(); - else - currentNum=wTableModel->rowCount() > dsize ? dsize : wTableModel->rowCount(); - - for (int y=0; yaddWidget(wSize); - container_layout->addWidget(wTableView); - container_layout->addWidget(wDisplay); - } -}; - -//////////////////////////////////////////////////////////////// -/// variable-sized vectors support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < std::vector > -{ -public: - typedef std::vector data_type; - typedef T value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, int i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize( int s, data_type& d) - { - d.resize(s); - } -}; - - - - -template -class vector_data_trait < sofa::type::vector > : public vector_data_trait< std::vector > -{ -}; - - -//////////////////////////////////////////////////////////////// -/// std::map from strings support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < std::map > -{ -public: - typedef std::map data_type; - typedef T value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& d, int i = 0) - { - typename data_type::const_iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) return it->first.c_str(); - else return nullptr; - } - static const value_type* get(const data_type& d, int i = 0) - { - typename data_type::const_iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) return &(it->second); - else return nullptr; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - typename data_type::iterator it = d.begin(); - while (i > 0 && it != d.end()) - { - ++it; - --i; - } - if (i == 0) it->second = v; - } - static void resize( int /*s*/, data_type& /*d*/) - { - //d.resize(s); - } -}; - - - -//////////////////////////////////////////////////////////////// -/// dequeues support -//////////////////////////////////////////////////////////////// - -template -class vector_data_trait < std::deque > -{ -public: - typedef std::deque data_type; - typedef T value_type; - enum { NDIM = 1 }; - static int size(const data_type& d) { return d.size(); } - static const char* header(const data_type& /*d*/, int /*i*/ = 0) - { - return nullptr; - } - static const value_type* get(const data_type& d, int i = 0) - { - return ((unsigned)i < (unsigned)size(d)) ? &(d[i]) : nullptr; - } - static void set( const value_type& v, data_type& d, int i = 0) - { - if ((unsigned)i < (unsigned)size(d)) - d[i] = v; - } - static void resize(int s, data_type& d) - { - d.resize(s); - } -}; - - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.cpp deleted file mode 100644 index be4678c7edf..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "QModelViewTableUpdater.h" - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -QTableViewUpdater::QTableViewUpdater(QWidget * parent ) - : QTableView(parent) -{ - setAutoFillBackground(true); -} - -void QTableViewUpdater::setDisplayed(bool b) -{ - this->setVisible(b); -} - - -QTableModelUpdater::QTableModelUpdater ( int numRows, int numCols, QWidget * parent , const char * /*name*/ ): - QStandardItemModel(numRows, numCols, parent) -{} - -Qt::ItemFlags QTableModelUpdater::flags(const QModelIndex&) const -{ - if(m_isReadOnly) - return (Qt::ItemIsSelectable) ; - return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ; -} - -QVariant QTableModelUpdater::data(const QModelIndex &index, int role) const -{ - if(m_isReadOnly){ - switch(role){ - case Qt::BackgroundRole: -#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) - return QApplication::palette().color(QPalette::Disabled, QPalette::Background) ; -#else - return QApplication::palette().color(QPalette::Disabled, QPalette::Window) ; -#endif - case Qt::ForegroundRole: - return QApplication::palette().color(QPalette::Disabled, QPalette::Text); - } - } - return QStandardItemModel::data(index,role) ; -} - -void QTableModelUpdater::setReadOnly(const bool isReadOnly) -{ - m_isReadOnly=isReadOnly; -} - -void QTableModelUpdater::resizeTableV( int number ) -{ - const QSpinBox *spinBox = (QSpinBox *) sender(); - QString header; - if( spinBox == nullptr) - { - return; - } - if (number != rowCount()) - { - const int previousRows=rowCount(); - setRowCount(number); - if (number > previousRows) - { - for (int i=previousRows; isetText(QString::number(i)); - } - } - } -} - -void QTableModelUpdater::resizeTableH( int number ) -{ - const QSpinBox *spinBox = (QSpinBox *) sender(); - QString header; - if( spinBox == nullptr) - { - return; - } - if (number != columnCount()) - { - const int previousColumns=columnCount(); - setColumnCount(number); - if (number > previousColumns) - { - for (int i=previousColumns; isetText(QString::number(i)); - } - } - } -} - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.h deleted file mode 100644 index 6bf003e9c51..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QModelViewTableUpdater.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once -#include - -#include -#include -#include -#include - - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QTableViewUpdater : public QTableView -{ - Q_OBJECT - -public: - QTableViewUpdater (QWidget * parent = nullptr); - -public slots: - void setDisplayed(bool b); - -}; - -class SOFA_GUI_QT_API QTableModelUpdater : public QStandardItemModel -{ - Q_OBJECT - bool m_isReadOnly ; -public: - QTableModelUpdater ( int numRows, int numCols, QWidget * parent = nullptr, const char * /*name*/ = nullptr ); - - Qt::ItemFlags flags(const QModelIndex&) const override ; - QVariant data(const QModelIndex &index, int role) const override; - - void setReadOnly(const bool isReadOnly) ; - -public slots: - void resizeTableV( int number ); - - void resizeTableH( int number ); -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.cpp deleted file mode 100644 index 690122b4d05..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include -#include -#include -#include -#include - -namespace sofa::gui::qt -{ - -QMomentumStatWidget::QMomentumStatWidget( QWidget* parent, simulation::Node* node ) : QGraphStatWidget( parent, node, "Momenta", 6, 500 ) -{ - setCurve( 0, "Linear X", Qt::red ); - setCurve( 1, "Linear Y", Qt::green ); - setCurve( 2, "Linear Z", Qt::blue ); - setCurve( 3, "Angular X", Qt::cyan ); - setCurve( 4, "Angular Y", Qt::magenta ); - setCurve( 5, "Angular Z", Qt::yellow ); - - m_momentumVisitor = new simulation::mechanicalvisitor::MechanicalGetMomentumVisitor(core::mechanicalparams::defaultInstance()); -} - -QMomentumStatWidget::~QMomentumStatWidget() -{ - delete m_momentumVisitor; -} - -void QMomentumStatWidget::stepImpl() -{ - if (m_curves.size() != 6) { - msg_warning("QMomentumStatWidget") << "Wrong number of curves: " << m_curves.size() << ", should be 3."; - return; - } - - m_momentumVisitor->execute( m_node->getContext() ); - - const type::Vec6& momenta = m_momentumVisitor->getMomentum(); - - // Update series - const SReal time = m_node->getTime(); - SReal min = 100000; - SReal max = -100000; - for (unsigned i = 0; i < 6; ++i) - { - m_curves[i]->append(time, momenta[i]); - if (momenta[i] < min) - min = momenta[i]; - if (momenta[i] > max) - max = momenta[i]; - } - - // update minY - updateYAxisBounds(min); - // update maxY - updateYAxisBounds(max); -} - - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.h deleted file mode 100644 index df22b6f3c88..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMomentumStatWidget.h +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -namespace sofa::simulation::mechanicalvisitor -{ -class MechanicalGetMomentumVisitor; -} - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QMomentumStatWidget : public QGraphStatWidget -{ - - Q_OBJECT - - - simulation::mechanicalvisitor::MechanicalGetMomentumVisitor *m_momentumVisitor; - -public: - - QMomentumStatWidget( QWidget* parent, simulation::Node* node ); - - virtual ~QMomentumStatWidget(); - - void stepImpl() override; -}; - - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.cpp deleted file mode 100644 index 8d54e1f7244..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#include "QMouseOperations.h" -#include "QDisplayDataWidget.h" -#include "DataWidget.h" - -#include -#include - -#include -#include -#include -#include - -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ - -DataWidget *QMouseOperation::createWidgetFromData(sofa::core::objectmodel::BaseData* data) -{ - DataWidget::CreatorArgument arg; - arg.data = data; - arg.name = arg.data->getName(); - arg.parent = this; - arg.readOnly = arg.data->isReadOnly(); - DataWidget *widget = DataWidget::CreateDataWidget(arg); - connect(widget, SIGNAL(WidgetDirty(bool)), this, SLOT(WidgetDirty(bool))); - return widget; -} - -void QMouseOperation::WidgetDirty(bool b) -{ - if (b) - { - DataWidget *dataW=(DataWidget*) sender(); - - dataW->updateDataValue(); - } -} - - -//******************************************************************************************* -QAttachOperation::QAttachOperation() -{ - //Building the GUI for the Attach Operation - - QHBoxLayout *layout=new QHBoxLayout(this); - QLabel *label=new QLabel(QString("Stiffness"), this); - stiffnessWidget = createWidgetFromData(&(setting->d_stiffness)); - - QLabel *labelSize=new QLabel(QString("Arrow Size"), this); - arrowSizeWidget = createWidgetFromData(&(setting->d_arrowSize)); - - QLabel *labelShowFactor=new QLabel(QString("Show Factor Size"), this); - showSizeFactorWidget = createWidgetFromData(&(setting->d_showFactorSize)); - - layout->addWidget(label); - layout->addWidget(stiffnessWidget); - - layout->addWidget(labelSize); - layout->addWidget(arrowSizeWidget); - - layout->addWidget(labelShowFactor); - layout->addWidget(showSizeFactorWidget); -} - - -void QAttachOperation::configure(PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) -{ - if (const sofa::gui::component::AttachBodyButtonSetting* attachSetting=dynamic_cast(button)) - { - AttachOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); - setting->d_stiffness.copyValueFrom(&(attachSetting->d_stiffness)); - setting->d_arrowSize.copyValueFrom(&(attachSetting->d_arrowSize) ); - setting->d_showFactorSize.copyValueFrom(&( attachSetting->d_showFactorSize) ) ; - - stiffnessWidget->updateWidgetValue(); - arrowSizeWidget->updateWidgetValue(); - } - else AttachOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); -} -//******************************************************************************************* - - -//******************************************************************************************* -QAddRecordedCameraOperation::QAddRecordedCameraOperation() -{} - -void QAddRecordedCameraOperation::configure(PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) -{ - if (dynamic_cast(button)) - { - AddRecordedCameraOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); - } - else AddRecordedCameraOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); -} - -//******************************************************************************************* - - -//******************************************************************************************* -QStartNavigationOperation::QStartNavigationOperation() -{} - -void QStartNavigationOperation::configure(PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) -{ - if (dynamic_cast(button)) - { - StartNavigationOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); - } - else StartNavigationOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); -} - -//******************************************************************************************* - - -//******************************************************************************************* -QFixOperation::QFixOperation() -{ - //Building the GUI for the Fix Operation - QHBoxLayout *layout=new QHBoxLayout(this); - QLabel *label=new QLabel(QString("Fixation"), this); - stiffnessWidget = createWidgetFromData(&setting->stiffness); - - layout->addWidget(label); - layout->addWidget(stiffnessWidget); -} - -void QFixOperation::configure(PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) -{ - if (const auto* fixSetting=dynamic_cast(button)) - { - FixOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId() )) ; - setting->stiffness.setValue(fixSetting->stiffness.getValue()); - - stiffnessWidget->updateWidgetValue(); - } - else FixOperation::configure(picker,GetMouseId(button->d_button.getValue().getSelectedId())); -} - -//******************************************************************************************* - -//******************************************************************************************* -QInciseOperation::QInciseOperation() - : finishIncision(false) - , keepPoint(false) -{ - //Building the GUI for the Injection Operation - QVBoxLayout *layout=new QVBoxLayout(this); - - // First group box for incision method choice - incisionMethodChoiceGroup = new QGroupBox(tr("Incision method choice"),this); - QVBoxLayout *vbox1 = new QVBoxLayout(incisionMethodChoiceGroup); - - method1 = new QRadioButton(tr("&Through segment: Incise from click to click."), incisionMethodChoiceGroup); - method2 = new QRadioButton(tr("&Continually: Incise continually from first click localization."), incisionMethodChoiceGroup); - method1->setChecked (true); - - vbox1->addWidget(method1); - vbox1->addWidget(method2); - - // Second group box for easy use - advancedOperations = new QGroupBox(tr("Advanced operations"),this); - QVBoxLayout *vbox2 = new QVBoxLayout(advancedOperations); - - // on push button and one check box with labels - finishCut = new QCheckBox(QString("Complete incision"),advancedOperations); - storeLastPoint = new QCheckBox (QString("Keep in memory last incision point."),advancedOperations); - - vbox2->addWidget(finishCut); - vbox2->addWidget(storeLastPoint); - - - // Third group box for advanced settings (only snping % value for the moment) - advancedOptions = new QGroupBox(tr("Advanced settings"),this); - QVBoxLayout *vbox3 = new QVBoxLayout(advancedOptions); - - // first slider for border snapping - QHBoxLayout *slider1=new QHBoxLayout(); - QLabel *label1=new QLabel(QString("Distance to snap from border (in %)"), this); - snapingBorderSlider=new QSlider(Qt::Horizontal, this); - snapingBorderValue=new QSpinBox(this); - snapingBorderValue->setMinimum(0); - snapingBorderValue->setMaximum(100); - snapingBorderValue->setSingleStep(1); - snapingBorderValue->setEnabled(true); - - slider1->addWidget (label1); - slider1->addWidget (snapingBorderSlider); - slider1->addWidget (snapingBorderValue); - vbox3->addLayout (slider1); - - // second slider for along path snapping - QHBoxLayout *slider2=new QHBoxLayout(); - QLabel *label2=new QLabel(QString("Distance to snap along path (in %)"), this); - snapingSlider=new QSlider(Qt::Horizontal, this); - snapingValue=new QSpinBox(this); - snapingBorderValue->setMinimum(0); - snapingBorderValue->setMaximum(100); - snapingBorderValue->setSingleStep(1); - snapingValue->setEnabled(true); - snapingBorderValue->setValue(0); - - slider2->addWidget (label2); - slider2->addWidget (snapingSlider); - slider2->addWidget (snapingValue); - vbox3->addLayout (slider2); - - // Creating UI - layout->addWidget(incisionMethodChoiceGroup); - layout->addWidget(advancedOperations); - layout->addWidget(advancedOptions); - - connect(finishCut, SIGNAL(toggled(bool)), this, SLOT(setFinishIncision(bool))); - connect(storeLastPoint, SIGNAL(toggled(bool)), this, SLOT(setkeepPoint(bool))); - - connect(snapingBorderSlider,SIGNAL(valueChanged(int)), snapingBorderValue, SLOT(setValue(int))); - connect(snapingBorderValue,SIGNAL(valueChanged(int)), snapingBorderSlider, SLOT(setValue(int))); - - connect(snapingSlider,SIGNAL(valueChanged(int)), snapingValue, SLOT(setValue(int))); - connect(snapingValue,SIGNAL(valueChanged(int)), snapingSlider, SLOT(setValue(int))); - - connect(method1, SIGNAL(toggled(bool)), this, SLOT(setEnableBox(bool))); - - if ( method1->isChecked()) - snapingBorderValue->setValue(50); - - advancedOptions->setHidden(false); -} - -void QInciseOperation::setEnableBox(bool i) -{ - advancedOptions->setVisible(i); -} - -void QInciseOperation::setFinishIncision(bool i) -{ - finishIncision = i; -} - -void QInciseOperation::setkeepPoint(bool i) -{ - keepPoint = i; -} - - - -int QInciseOperation::getIncisionMethod() const -{ - if (method2->isChecked()) - return 1; - else - return 0; -} - -int QInciseOperation::getSnapingBorderValue() const -{ - return snapingBorderValue->value(); -} - -int QInciseOperation::getSnapingValue() const -{ - return snapingValue->value(); -} - -//******************************************************************************************* - - - -//******************************************************************************************* -QTopologyOperation::QTopologyOperation() -{ - //Building the GUI for Topological Operation - - QVBoxLayout *layout=new QVBoxLayout(this); - - // First part: selection of topological operation: - QHBoxLayout *HLayout1 = new QHBoxLayout(); - QLabel *label1=new QLabel(QString("Topological operation: "), this); - operationChoice = new QComboBox(this); - operationChoice->addItem("Remove one element"); - operationChoice->addItem("Remove a zone of elements"); - - HLayout1->addWidget (label1); - HLayout1->addWidget (operationChoice); - - - // Second part: advanced settings - advancedOptions = new QGroupBox(tr("Advanced settings"),this); - QVBoxLayout *VLayout1 = new QVBoxLayout(advancedOptions); - - // First setting: type of mesh, either surface or volume - QHBoxLayout *HLayout2 = new QHBoxLayout(); - - QLabel *label2 = new QLabel(QString("Remove area type: "), this); - meshType1 = new QRadioButton(tr("&Surface"), advancedOptions); - meshType2 = new QRadioButton(tr("&Volume"), advancedOptions); - meshType1->setChecked (true); - - HLayout2->addWidget (label2); - HLayout2->addWidget (meshType1); - HLayout2->addWidget (meshType2); - VLayout1->addLayout (HLayout2); - - // Second setting: selector scale - QHBoxLayout *HLayout3 = new QHBoxLayout(); - - QLabel *label3=new QLabel(QString("Selector scale: "), this); - scaleSlider = new QSlider (Qt::Horizontal, this); - scaleValue = new QSpinBox(this); - scaleValue->setMinimum(0); - scaleValue->setMaximum(100); - scaleValue->setSingleStep(1); - scaleValue->setEnabled(true); - - HLayout3->addWidget (label3); - HLayout3->addWidget (scaleSlider); - HLayout3->addWidget (scaleValue); - VLayout1->addLayout (HLayout3); - - - // Creating UI - layout->addLayout (HLayout1); - layout->addWidget(advancedOptions); - - connect(scaleSlider,SIGNAL(valueChanged(int)), scaleValue, SLOT(setValue(int))); - connect(scaleValue,SIGNAL(valueChanged(int)), scaleSlider, SLOT(setValue(int))); - connect(operationChoice, SIGNAL(activated(int)), this, SLOT(setEnableBox(int))); - - scaleValue->setValue(0); - advancedOptions->setHidden(true); - -} - - -double QTopologyOperation::getScale() const -{ - return scaleValue->value(); -} - -int QTopologyOperation::getTopologicalOperation() const -{ - return operationChoice->currentIndex(); -} - -bool QTopologyOperation::getVolumicMesh() const -{ - return meshType2->isChecked(); -} - -void QTopologyOperation::setEnableBox(int i) -{ - switch (i) - { - case 0: - advancedOptions->setHidden(true); - break; - case 1: - advancedOptions->setHidden(false); - break; - default: - break; - } -} - -//******************************************************************************************* - - -//******************************************************************************************* -QAddSutureOperation::QAddSutureOperation() -{ - //Building the GUI for the Suture Operation - QVBoxLayout *layout=new QVBoxLayout(this); - - QHBoxLayout *option1=new QHBoxLayout(); - QLabel *label1=new QLabel(QString("Spring stiffness"), this); - stiffness = new QLineEdit(QString("10.0"), this); - option1->addWidget(label1); - option1->addWidget(stiffness); - - QHBoxLayout *option2=new QHBoxLayout(); - QLabel *label2=new QLabel(QString("Spring damping"), this); - damping = new QLineEdit(QString("1.0"), this); - option1->addWidget(label2); - option1->addWidget(damping); - - layout->addLayout(option1); - layout->addLayout(option2); -} - -double QAddSutureOperation::getStiffness() const -{ - return stiffness->displayText().toDouble(); - //return atof(stiffness->displayText().toStdString().c_str()); -} - -double QAddSutureOperation::getDamping() const -{ - return damping->displayText().toDouble(); - //return atof(damping->displayText().toStdString()); -} - -//******************************************************************************************* - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.h deleted file mode 100644 index 303c9693b94..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseOperations.h +++ /dev/null @@ -1,190 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include -#include "SofaMouseManager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace sofa::gui::qt -{ -class DataWidget; - -class SOFA_GUI_QT_API QMouseOperation : public QWidget -{ - Q_OBJECT -public: - DataWidget *createWidgetFromData(sofa::core::objectmodel::BaseData* data); - -public slots: - void WidgetDirty(bool); -}; - -class QAttachOperation : public QMouseOperation, public common::AttachOperation -{ - Q_OBJECT -public: - QAttachOperation(); - void configure(common::PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) override; - -protected: - DataWidget *stiffnessWidget; - DataWidget *arrowSizeWidget; - DataWidget *showSizeFactorWidget; -}; - -class QAddRecordedCameraOperation : public QMouseOperation, public common::AddRecordedCameraOperation -{ - Q_OBJECT -public: - QAddRecordedCameraOperation(); - void configure(common::PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) override; -}; - -class QStartNavigationOperation : public QMouseOperation, public common::StartNavigationOperation -{ - Q_OBJECT -public: - QStartNavigationOperation(); - void configure(common::PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) override; -}; - -class QFixOperation : public QMouseOperation, public common::FixOperation -{ - Q_OBJECT -public: - QFixOperation(); - void configure(common::PickHandler *picker, sofa::component::setting::MouseButtonSetting* button) override; - -protected: - DataWidget *stiffnessWidget; -}; - - - - -class QInciseOperation : public QWidget, public common::InciseOperation -{ - Q_OBJECT -public: - QInciseOperation(); - int getIncisionMethod() const override; - int getSnapingBorderValue() const override; - int getSnapingValue() const override; - - bool getCompleteIncision () override {return finishIncision;} - bool getKeepPoint () override {return keepPoint;} - - void configure(common::PickHandler *picker, common::MOUSE_BUTTON b) override - { - InciseOperation::configure(picker, b); - } - - bool finishIncision; - bool keepPoint; - -public slots: - void setEnableBox (bool i); - void setFinishIncision (bool i); - void setkeepPoint (bool i); - - -protected: - QGroupBox* incisionMethodChoiceGroup; - QRadioButton* method1; - QRadioButton* method2; - - QGroupBox *advancedOperations; - QCheckBox *finishCut; - QCheckBox *storeLastPoint; - - QGroupBox* advancedOptions; - QSlider *snapingBorderSlider; - QSpinBox *snapingBorderValue; - QSlider *snapingSlider; - QSpinBox *snapingValue; -}; - - - - -class QTopologyOperation : public QWidget, public common::TopologyOperation -{ - Q_OBJECT -public: - QTopologyOperation(); - double getScale() const override; - int getTopologicalOperation() const override; - bool getVolumicMesh() const override; - - - - void configure(common::PickHandler *picker, common::MOUSE_BUTTON b) override - { - common::TopologyOperation::configure(picker, b); - } - -public slots: - void setEnableBox (int i); - -protected: - - QComboBox *operationChoice; - QRadioButton *meshType1; - QRadioButton *meshType2; - - QGroupBox *advancedOptions; - QSlider *scaleSlider; - QSpinBox *scaleValue; -}; - - -class QAddSutureOperation : public QWidget, public common::AddSutureOperation -{ - Q_OBJECT -public: - QAddSutureOperation(); - double getStiffness() const override; - double getDamping() const override; - - void configure(common::PickHandler *picker, common::MOUSE_BUTTON b) override - { - common::AddSutureOperation::configure(picker, b); - } - -protected: - QLineEdit *stiffness; - QLineEdit *damping; -}; - -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.cpp deleted file mode 100644 index 7e906e12302..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include -#include "QMouseWheelAdjustementGuard.h" - -namespace sofa::gui::qt -{ - -QMouseWheelAdjustmentGuard::QMouseWheelAdjustmentGuard(QObject *parent) : QObject(parent) -{ -} - -bool QMouseWheelAdjustmentGuard::eventFilter(QObject *o, QEvent *e) -{ - const QWidget* widget = static_cast(o); - if (e->type() == QEvent::Wheel && widget && !widget->hasFocus()) - { - e->ignore(); - return true; - } - - return QObject::eventFilter(o, e); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.h deleted file mode 100644 index 72252dbaf9b..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QMouseWheelAdjustementGuard.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include -#include - -namespace sofa::gui::qt -{ - -/// @brief Filter qt events to allows wheel event to only be accepted when the widget has focus. -/// -/// To use it you need to do: -/// myWidget->setFocusPolicy(Qt::StrongFocus); -/// myWidget->installEventFilter(new MouseWheelWidgetAdjustmentGuard(ui.comboBox)); -/// -/// This code is grabbed from: -/// https://stackoverflow.com/questions/5821802/qspinbox-inside-a-qscrollarea-how-to-prevent-spin-box-from-stealing-focus-when -class SOFA_GUI_QT_API QMouseWheelAdjustmentGuard : public QObject -{ -public: - explicit QMouseWheelAdjustmentGuard(QObject *parent); - -protected: - bool eventFilter(QObject* o, QEvent* e) override; -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.cpp deleted file mode 100644 index 8148021a158..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include -#include "QRGBAColorPicker.h" - -namespace sofa::gui::qt::qrgbacolorpicker_h -{ - -QRGBAColorPicker::QRGBAColorPicker(QWidget* parent) : QWidget(parent) -{ - _r = new QLineEdit(this); - _r->setValidator(new QIntValidator(0,255,this)); - _g = new QLineEdit(this); - _g->setValidator(new QIntValidator(0,255,this)); - _b = new QLineEdit(this); - _b->setValidator(new QIntValidator(0,255,this)); - _a = new QLineEdit(this); - _a->setValidator(new QIntValidator(0,255,this)); - _colorButton = new QPushButton(this); - QHBoxLayout* layout = new QHBoxLayout(this); - layout->addWidget(_colorButton); - layout->addWidget(new QLabel("r",this)); - layout->addWidget(_r); - layout->addWidget(new QLabel("g",this)); - layout->addWidget(_g); - layout->addWidget(new QLabel("b",this)); - layout->addWidget(_b); - layout->addWidget(new QLabel("a",this)); - layout->addWidget(_a); - connect( _r , SIGNAL( textChanged(const QString & ) ) ,this , SIGNAL( hasChanged() ) ); - connect( _g , SIGNAL( textChanged(const QString & ) ) ,this , SIGNAL( hasChanged() ) ); - connect( _b , SIGNAL( textChanged(const QString & ) ) ,this , SIGNAL( hasChanged() ) ); - connect( _a , SIGNAL( textChanged(const QString & ) ) ,this , SIGNAL( hasChanged() ) ); - connect( _r , SIGNAL( returnPressed() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _g , SIGNAL( returnPressed() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _b , SIGNAL( returnPressed() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _a , SIGNAL( returnPressed() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _r , SIGNAL( editingFinished() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _g , SIGNAL( editingFinished() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _b , SIGNAL( editingFinished() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _a , SIGNAL( editingFinished() ) ,this , SLOT( updateRGBAColor() ) ); - connect( _colorButton, SIGNAL( clicked() ), this, SLOT( raiseQColorDialog() ) ); -} - -type::RGBAColor QRGBAColorPicker::getColor() const -{ - typedef unsigned char uchar; - constexpr uchar max = std::numeric_limits::max(); - type::RGBAColor color; - float r = _r->text().toFloat(); - float g = _g->text().toFloat(); - float b = _b->text().toFloat(); - float a = _a->text().toFloat(); - r /= max; - g /= max; - b /= max; - a /= max; - - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = a; - return color; -} - -void QRGBAColorPicker::updateRGBAColor() -{ - typedef unsigned char uchar; - - const uchar r = _r->text().toInt(); - const uchar g = _g->text().toInt(); - const uchar b = _b->text().toInt(); - const uchar a = _a->text().toInt(); - _rgba = qRgba(r,g,b,a); - redrawColorButton(); -} - -void QRGBAColorPicker::setColor(const type::RGBAColor& color) -{ - typedef unsigned char uchar; - constexpr uchar max = std::numeric_limits::max(); - const uchar r = uchar(max * color[0]); - const uchar g = uchar(max * color[1]); - const uchar b = uchar(max * color[2]); - const uchar a = uchar(max * color[3]); - QString str; - str.setNum(r); - _r->setText(str); - str.setNum(g); - _g->setText(str); - str.setNum(b); - _b->setText(str); - str.setNum(a); - _a->setText(str); - _rgba = qRgba(r, g, b, a); - - redrawColorButton(); -} - -void QRGBAColorPicker::setColor(const Vec4f& color) -{ - setColor(type::RGBAColor{color[0], color[1] , color[2] ,color[3]}); -} - -void QRGBAColorPicker::redrawColorButton() -{ - const int w=_colorButton->width(); - const int h=_colorButton->height(); - - QPixmap *pix=new QPixmap(25,20); - pix->fill(QColor(qRed(_rgba), - qGreen(_rgba), - qBlue(_rgba))); - _colorButton->setIcon(QIcon(*pix)); - - _colorButton->resize(w,h); -} - -void QRGBAColorPicker::raiseQColorDialog() -{ - typedef unsigned char uchar; - const uchar max = std::numeric_limits::max(); - int r,g,b,a; - - Vec4f color; -#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0)) - bool ok; - QColor qcolor = QColorDialog::getRgba(_rgba,&ok,this); - if( ok ) -#else - QColor qcolor = QColorDialog::getColor(_rgba, this); - if( qcolor.isValid() ) -#endif - { - const QRgb rgba=qcolor.rgb(); - r=qRed(rgba); - g=qGreen(rgba); - b=qBlue(rgba); - a=qAlpha(rgba); - color[0] = (float)r / max; - color[1] = (float)g / max; - color[2] = (float)b / max; - color[3] = (float)a / max; - setColor(color); - emit hasChanged(); - } -} - -} // namespace sofa::gui::qt::qrgbacolorpicker_h diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.h deleted file mode 100644 index 684bae13677..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QRGBAColorPicker.h +++ /dev/null @@ -1,85 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include "DataWidget.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/// Private namespace -namespace sofa::gui::qt::qrgbacolorpicker_h -{ - -using sofa::type::Vec4f ; - -/** - @class QRGBAColorPicker - Implement a widget to select a color either using a color wheel or by three values. -*/ -class QRGBAColorPicker : public QWidget -{ - Q_OBJECT - -signals: - void hasChanged(); - -public: - QRGBAColorPicker(QWidget* parent); - void setColor(const type::RGBAColor& color); - - void setColor( const Vec4f& color ); - type::RGBAColor getColor() const; - -protected: - QRgb _rgba; - QLineEdit* _r; - QLineEdit* _g; - QLineEdit* _b; - QLineEdit* _a; - QPushButton* _colorButton; - -protected slots: - void updateRGBAColor(); - void redrawColorButton(); - void raiseQColorDialog(); -}; - -} // namespace sofa::gui::qt::qrgbacolorpicker_h - -namespace sofa::gui::qt -{ - using sofa::gui::qt::qrgbacolorpicker_h::QRGBAColorPicker; -} // namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.cpp deleted file mode 100644 index d6cd100fa38..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QSofaListView.h" -#include "QDisplayPropertyWidget.h" -#include "GraphListenerQListView.h" -#include "ModifyObject.h" -#include "GenGraphForm.h" -#include "RealGUI.h" -#include -#include -#include -#include -#include -#include -#include -#include // version macro -#include -#include - -#include -#include -#include -#include -#include - -using namespace sofa::simulation; -using namespace sofa::core::objectmodel; -using namespace sofa::gui::common; - -namespace sofa::gui::qt -{ - -QSofaListView::QSofaListView(const SofaListViewAttribute& attribute, - QWidget* parent, - const char* name, - Qt::WindowFlags f): - SofaSceneGraphWidget(parent), - graphListener_(nullptr), - AddObjectDialog_(nullptr), - attribute_(attribute), - propertyWidget(nullptr) -{ - this->setObjectName(name); - this->setWindowFlags(f); - //List of objects - //Read the object.txt that contains the information about the objects which can be added to the scenes within a given BoundingBox and scale range - std::string object ( "config/object.txt" ); - - if( sofa::helper::system::DataRepository.findFile ( object ) ) - { - list_object.clear(); - std::ifstream end(object.c_str()); - std::string s; - while( end >> s ) - { - list_object.push_back(s); - } - end.close(); - } - - this->setColumnCount(2); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - header()->setResizeMode(0, QHeaderView::Interactive); - header()->setResizeMode(1, QHeaderView::Stretch); -#else - header()->setSectionResizeMode(0, QHeaderView::Interactive); - header()->setSectionResizeMode(1, QHeaderView::Stretch); -#endif // SOFA_QT5 - QStringList headerLabels; - headerLabels << "Name" << "Class"; - this->setHeaderLabels(headerLabels); - - setRootIsDecorated(true); - setIndentation(8); - - graphListener_ = new GraphListenerQListView(this); - - this->setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, &QSofaListView::customContextMenuRequested ,this, &QSofaListView::RunSofaRightClicked); - connect(this, &QSofaListView::itemDoubleClicked, this, &QSofaListView::RunSofaDoubleClicked); - connect(this, &QSofaListView::itemClicked, this, [&](QTreeWidgetItem *item, int){ updateMatchingObjectmodel(item); }); -} - -QSofaListView::~QSofaListView() -{ - delete graphListener_; -} - - -void QSofaListView::Clear(Node* /*rootNode*/) -{ - /* - if(graphListener_ != nullptr) - { - delete graphListener_; - } - - CloseAllDialogs(); - clear(); - graphListener_ = new GraphListenerQListView(this); - - this->setSortingEnabled(false); - - rootNode->addListener(graphListener_); - update(); - - std::map::iterator graph_iterator; - for (graph_iterator = graphListener_->items.begin(); - graph_iterator != graphListener_->items.end(); - ++graph_iterator) - { - Node* node = dynamic_cast< Node* >(graph_iterator->first); - if (node!=nullptr && !node->isActive()) - { - object_.ptr.Node = node; - object_.type = typeNode; - emit RequestActivation(object_.ptr.Node, node->isActive()); - } - } - */ -} - -void QSofaListView::CloseAllDialogs() -{ - emit Close(); - assert( map_modifyObjectWindow.empty() ); - assert( map_modifyDialogOpened.empty() ); - -} - -void QSofaListView::modifyUnlock(void* Id) -{ - map_modifyDialogOpened.erase( Id ); - map_modifyObjectWindow.erase( Id ); -} - -/// Traverse the item tree and retrieve the item that are expanded. The path of the node -/// that are expanded are stored in the pathes std::vector::std::string>. -void QSofaListView::getExpandedNodes(QTreeWidgetItem* item, std::vector& pathes) -{ - if(!item) - return; - - /// We have reached a leaf of the hierarchy or it is closed...so we save the path - if( !item->isExpanded() && graphListener_->findObject(item)->toBaseNode() != nullptr ) - return; - - const BaseNode* parentNode = graphListener_->findObject(item)->toBaseNode() ; - if(parentNode == nullptr) - return; - - const std::string path = parentNode->getPathName(); - pathes.push_back(path); - - for(int i=0 ; ichildCount() ; i++) - { - QTreeWidgetItem* child = item->child(i); - const BaseNode* childNode = graphListener_->findObject(child)->toBaseNode() ; - - if(childNode==nullptr) - continue; - - if( childNode->getParents()[0] == parentNode ) - getExpandedNodes(child, pathes) ; - } - - return ; -} - -void QSofaListView::getExpandedNodes(std::vector& pathes) -{ - LockContextManager lock(this, true); - QTreeWidgetItem* rootitem = this->topLevelItem(0) ; - getExpandedNodes(rootitem,pathes) ; -} - -void QSofaListView::collapseNode() -{ - collapseNode(currentItem()); -} - -void QSofaListView::collapseNode(QTreeWidgetItem* item) -{ - if (!item) return; - - LockContextManager lock(this, true); - for(int i=0 ; ichildCount() ; i++) - { - QTreeWidgetItem* child = item->child(i); - child->setExpanded(false); - } - item->setExpanded ( true ); -} - -void QSofaListView::expandPath(const std::string& path) -{ - if(path.empty()) - return; - - if(path.data()[0] != '/') - return; - - Node* match = down_cast( graphListener_->findObject(this->topLevelItem(0))->toBaseNode() ); - - QStringList tokens = QString::fromStdString(path).split('/') ; - - for(int i=1;igetChild(tokens[i].toStdString()); - - if(match == nullptr) - return; - - if(graphListener_->items.find(match) != graphListener_->items.end()) - { - QTreeWidgetItem* item = graphListener_->items[match] ; - item->setExpanded ( true ); - } - } -} - -void QSofaListView::expandPathFrom(const std::vector& pathes) -{ - LockContextManager lock(this, true); - for(auto& path : pathes) - { - expandPath(path) ; - } -} - - -void QSofaListView::expandNode() -{ - expandNode(currentItem()); -} - -void QSofaListView::expandNode(QTreeWidgetItem* item) -{ - if (!item) - return; - - LockContextManager lock(this, true); - item->setExpanded ( true ); - - for(int i=0 ; ichildCount() ; i++) - { - QTreeWidgetItem* child = item->child(i); - child->setExpanded(true); - expandNode(child); - } - -} - -void QSofaListView::setRoot(Node* root) -{ - if(!root) - return; - - CloseAllDialogs(); - clear(); - - if(graphListener_) - delete graphListener_; - graphListener_ = new GraphListenerQListView(this); - - setSortingEnabled(false); - - const bool lockStatus = m_isLocked; - m_isLocked=false; - root->addListener(graphListener_); - graphListener_->onBeginAddChild(nullptr, root); - m_isLocked=lockStatus; - m_isDirty=false; - - emit dirtynessChanged(m_isDirty); -} - -void QSofaListView::update() -{ - if(!m_isDirty) - return; - - m_isDirty=false; - - if(!graphListener_ || !this->topLevelItem(0)) - { - emit dirtynessChanged(m_isDirty); - return; - } - emit dirtynessChanged(m_isDirty); -} - -void QSofaListView::updateMatchingObjectmodel(QTreeWidgetItem* item, int) -{ - updateMatchingObjectmodel(item); -} - -void QSofaListView::updateMatchingObjectmodel(QTreeWidgetItem* item) -{ - BaseData* data = nullptr; - Base* base = nullptr; - BaseObject* object = nullptr; - BaseNode* basenode = nullptr; - if(item == nullptr) - { - object_.ptr.Node = nullptr; - } - else - { - base = graphListener_->findObject(item); - if(base == nullptr) - { - data = graphListener_->findData(item); - assert(data); - object_.ptr.Data = data; - object_.type = typeData; - return; - } - basenode = base->toBaseNode(); - if( basenode == nullptr) - { - object = dynamic_cast(base); - object_.ptr.Object = object; - object_.type = typeObject; - } - else - { - object_.ptr.Node = down_cast(basenode); - object_.type = typeNode; - } - } - - addInPropertyWidget(item, true); -} - -void QSofaListView::addInPropertyWidget(QTreeWidgetItem *item, bool clear) -{ - if(!item) - return; - - Base* object = graphListener_->findObject(item); - if(object == nullptr) - return; - - if(propertyWidget) - { - propertyWidget->addComponent(object->getName().c_str(), object, item, clear); - - propertyWidget->show(); - } -} - -void QSofaListView::contextMenuEvent(QContextMenuEvent *event) -{ - event->accept(); -} - -void QSofaListView::focusObject() -{ - if( object_.isObject()) - emit( focusChanged(object_.ptr.Object)); - -} - -void QSofaListView::focusNode() -{ - if( object_.isNode()) - emit( focusChanged(object_.ptr.Node)); -} - -/*****************************************************************************************************************/ -void QSofaListView::RunSofaRightClicked( const QPoint& point) -{ - QTreeWidgetItem *item = this->itemAt( point ); - - if( item == nullptr) return; - - updateMatchingObjectmodel(item); - - QAction* act; - QMenu *contextMenu = new QMenu ( this ); - contextMenu->setObjectName( "ContextMenu"); - if( object_.isNode() ) - { - act = contextMenu->addAction("Focus", this,SLOT(focusNode())); - const bool enable = object_.ptr.Node->f_bbox.getValue().isValid() && !object_.ptr.Node->f_bbox.getValue().isFlat(); - act->setEnabled(enable); - } - if( object_.isObject() ) - { - act = contextMenu->addAction("Focus", this,SLOT(focusObject())); - const bool enable = object_.ptr.Object->f_bbox.getValue().isValid() && !object_.ptr.Object->f_bbox.getValue().isFlat() ; - act->setEnabled(enable); - } - - contextMenu->addSeparator(); - - //Creation of the context Menu - if ( object_.type == typeNode) - { - act = contextMenu->addAction("Collapse", this,SLOT(collapseNode())); - act = contextMenu->addAction("Expand", this,SLOT(expandNode())); - contextMenu->addSeparator(); - /*****************************************************************************************************************/ - if (object_.ptr.Node->isActive()) - { - act = contextMenu->addAction("Deactivate", this,SLOT(DeactivateNode())); - } - else - { - act = contextMenu->addAction("Activate", this,SLOT(ActivateNode())); - } - if (object_.ptr.Node->isSleeping()) - { - act = contextMenu->addAction("Wake up", this,SLOT(WakeUpNode())); - } - else - { - act = contextMenu->addAction("Put to sleep", this,SLOT(PutNodeToSleep())); - } - contextMenu->addSeparator(); - /*****************************************************************************************************************/ - act = contextMenu->addAction("Save Node", this,SLOT(SaveNode())); - act = contextMenu->addAction("Export OBJ", this,SLOT(exportOBJ())); - - if ( attribute_ == SIMULATION) - { - act = contextMenu->addAction("Remove Node", this,SLOT(RemoveNode())); - //If one of the elements or child of the current node is beeing modified, you cannot allow the user to erase the node - if ( !isNodeErasable ( object_.ptr.Node ) ) - { - act->setEnabled(false); - } - } - } - act = contextMenu->addAction("Modify", this,SLOT(Modify())); - - if( object_.isBase() ) - { - contextMenu->addSeparator(); - act = contextMenu->addAction("Go to Scene...", this, SLOT(openInstanciation())); - act->setEnabled(object_.asBase()->getInstanciationSourceFileName() != ""); - act = contextMenu->addAction("Go to Implementation...", this, SLOT(openImplementation())); - act->setEnabled(object_.asBase()->getDefinitionSourceFileName() != ""); - } - - contextMenu->addSeparator(); - act = contextMenu->addAction("Copy file path", this,SLOT(copyFilePathToClipBoard())); - act = contextMenu->addAction("Open file in editor", this,SLOT(openInEditor())); - - contextMenu->exec ( this->mapToGlobal(point) /*, index */); -} - -void QSofaListView::RunSofaDoubleClicked(QTreeWidgetItem* item, int /*index*/) -{ - if(item == nullptr) - { - return; - } - - item->setExpanded( !item->isExpanded()); - Modify(); -} - -/*****************************************************************************************************************/ -void QSofaListView::nodeNameModification(simulation::Node* node) -{ - QTreeWidgetItem *item=graphListener_->items[node]; - - const QString nameToUse(node->getName().c_str()); - item->setText(0,nameToUse); - - typedef std::multimap::iterator ItemIterator; - const std::pair range=graphListener_->nodeWithMultipleParents.equal_range(item); - - for (ItemIterator it=range.first; it!=range.second; ++it) it->second->setText(0,nameToUse); -} - - -void QSofaListView::DeactivateNode() -{ - emit RequestActivation(object_.ptr.Node,false); - currentItem()->setExpanded(false); - -} - -void QSofaListView::ActivateNode() -{ - emit RequestActivation(object_.ptr.Node,true); -} - -void QSofaListView::PutNodeToSleep() -{ - emit RequestSleeping(object_.ptr.Node, true); -} - -void QSofaListView::WakeUpNode() -{ - emit RequestSleeping(object_.ptr.Node, false); -} - -void QSofaListView::SaveNode() -{ - if( object_.ptr.Node != nullptr) - { - LockContextManager lock(this, true); - Node * node = object_.ptr.Node; - emit RequestSaving(node); - } -} -void QSofaListView::exportOBJ() -{ - if( object_.ptr.Node != nullptr) - { - LockContextManager lock(this, true); - Node * node = object_.ptr.Node; - emit RequestExportOBJ(node,true); - } -} - -void QSofaListView::RemoveNode() -{ - if( object_.type == typeNode) - { - LockContextManager lock(this, true); - const Node::SPtr node = object_.ptr.Node; - if ( node == node->getRoot() ) - { - if ( QMessageBox::warning ( this, "Removing root", "root node cannot be removed" ) ) - return; - } - else - { - node->detachFromGraph(); - node->execute(sofa::core::execparams::defaultInstance()); - emit NodeRemoved(); - } - } -} - -void QSofaListView::Modify() -{ - void *current_Id_modifyDialog = nullptr; - LockContextManager lock(this, true); - if ( currentItem() != nullptr ) - { - ModifyObjectFlags dialogFlags = ModifyObjectFlags(); - dialogFlags.setFlagsForSofa(); - ModifyObject* dialogModifyObject = nullptr; - - if (object_.type == typeData) //user clicked on a data - { - current_Id_modifyDialog = object_.ptr.Data; - } - if (object_.type == typeNode) - { - current_Id_modifyDialog = object_.ptr.Node; - } - if(object_.type == typeObject) - { - current_Id_modifyDialog = object_.ptr.Object; - } - assert(current_Id_modifyDialog != nullptr); - - //Opening of a dialog window automatically created - - const std::map< void*, QDialog* >::iterator testWindow = map_modifyObjectWindow.find( current_Id_modifyDialog); - if ( testWindow != map_modifyObjectWindow.end()) - { - //Object already being modified: no need to open a new window - (*testWindow).second->raise(); - return; - } - - dialogModifyObject = new ModifyObject(current_Id_modifyDialog,currentItem(),this,dialogFlags,currentItem()->text(0).toStdString().c_str()); - if(object_.type == typeData) - dialogModifyObject->createDialog(object_.ptr.Data); - if(object_.type == typeNode) - dialogModifyObject->createDialog(dynamic_cast(object_.ptr.Node)); - if(object_.type == typeObject) - dialogModifyObject->createDialog(dynamic_cast(object_.ptr.Object)); - - map_modifyDialogOpened.insert( std::make_pair ( current_Id_modifyDialog, currentItem()) ); - map_modifyObjectWindow.insert( std::make_pair(current_Id_modifyDialog, dialogModifyObject)); - connect ( dialogModifyObject, &ModifyObject::objectUpdated, this, &QSofaListView::Updated ); - connect ( this, &QSofaListView::Close, dialogModifyObject, &ModifyObject::closeNow ); - connect ( dialogModifyObject, &ModifyObject::dialogClosed, this, &QSofaListView::modifyUnlock ); - connect ( dialogModifyObject, &ModifyObject::nodeNameModification, this, &QSofaListView::nodeNameModification ); - connect ( dialogModifyObject, &ModifyObject::dataModified, this, &QSofaListView::dataModified ); - dialogModifyObject->show(); - dialogModifyObject->raise(); - } -} - -void QSofaListView::UpdateOpenedDialogs() -{ - std::map::const_iterator iter; - for(iter = map_modifyObjectWindow.begin(); iter != map_modifyObjectWindow.end() ; ++iter) - { - ModifyObject* modify = reinterpret_cast(iter->second); - modify->updateTables(); - } -} - -void QSofaListView::ExpandRootNodeOnly() -{ - this->expandToDepth(0); -} - -/// @brief Open a file at given path and line number using an external editor. -/// -/// The external editor is defined in a QSettings with the following entries: -/// [General] -/// ExternalEditor=qtcreator -/// ExternalEditorParams=-client ${filename}:${fileno} -/// where ${filename} is expanded with the full path to the file -/// where ${fileno} is expanded with the line number to open at. -void openInExternalEditor(const std::string filename, const int fileloc) -{ - const QFileInfo f(filename.c_str()); - - const std::string settingsFile = BaseGUI::getConfigDirectoryPath() + "/QSettings.ini"; - QSettings settings(settingsFile.c_str(), QSettings::IniFormat); - - /// In case the setting file does not contains the needed entries, let's put default ones - /// based on qtcreator. - if(!settings.contains("ExternalEditor")) - settings.setValue("ExternalEditor", "qtcreator"); - if(!settings.contains("ExternalEditorParams")) - settings.setValue("ExternalEditorParams", "-client ${filename}:${fileno}"); - - const QString editor = settings.value("ExternalEditor").toString(); - QString params = settings.value("ExternalEditorParams").toString(); - - params.replace("${filename}", f.absoluteFilePath()); - params.replace("${fileno}", QString::number(fileloc)); - const QStringList paramsAsList = params.split(QRegularExpression("(\\ )")); - if ( QProcess::execute(editor, paramsAsList) != 0 ) - { - msg_warning("QSofaListView") << "Unable to execute \"" << editor.toStdString() << " " - << params.toStdString() << "\"" << msgendl - << " The file will NOT be opened at the right line." << msgendl - << " Set your preferred editor in: " << settingsFile << msgendl - << " Falling back to your system default editor."; - - QDesktopServices::openUrl(QUrl::fromLocalFile( f.absoluteFilePath() )); - } -} - -void QSofaListView::openInstanciation() -{ - if(object_.isBase()) - { - openInExternalEditor(object_.asBase()->getInstanciationSourceFileName(), - object_.asBase()->getInstanciationSourceFilePos()); - } -} - -void QSofaListView::openImplementation() -{ - if(object_.isBase()) - { - openInExternalEditor(object_.asBase()->getDefinitionSourceFileName(), - object_.asBase()->getDefinitionSourceFilePos()); - } -} - - -void QSofaListView::openInEditor() -{ - const QFileInfo finfo(QApplication::activeWindow()->windowFilePath()); - QDesktopServices::openUrl(QUrl::fromLocalFile(finfo.absoluteFilePath())); -} - -void QSofaListView::copyFilePathToClipBoard() -{ - const QFileInfo finfo(QApplication::activeWindow()->windowFilePath()); - QApplication::clipboard()->setText(finfo.absoluteFilePath()) ; -} - -/*****************************************************************************************************************/ -// Test if a node can be erased in the graph : the condition is that none of its children has a menu modify opened -bool QSofaListView::isNodeErasable ( BaseNode* node) -{ - const QTreeWidgetItem* item = graphListener_->items[node]; - if(item == nullptr) - { - return false; - } - // check if there is already a dialog opened for that item in the graph - std::map< void*, QTreeWidgetItem*>::iterator it; - for (it = map_modifyDialogOpened.begin(); it != map_modifyDialogOpened.end(); ++it) - { - if (it->second == item) return false; - } - - //check the item childs - for(int i=0 ; ichildCount() ; i++) - { - const QTreeWidgetItem *child = item->child(i); - for( it = map_modifyDialogOpened.begin(); it != map_modifyDialogOpened.end(); ++it) - { - if( it->second == child) return false; - } - } - - return true; - -} - -void QSofaListView::Export() -{ - Node* root = down_cast( graphListener_->findObject(this->topLevelItem(0))->toBaseNode() ); - GenGraphForm* form = new sofa::gui::qt::GenGraphForm(this); - form->setScene ( root ); - std::string gname(((RealGUI*) (QApplication::topLevelWidgets()[0]))->windowFilePath().toStdString()); - const std::size_t gpath = gname.find_last_of("/\\"); - const std::size_t gext = gname.rfind('.'); - if (gext != std::string::npos && (gpath == std::string::npos || gext > gpath)) - gname = gname.substr(0,gext); - form->filename->setText(gname.c_str()); - form->show(); -} - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.h b/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.h deleted file mode 100644 index bb1b5f1e66d..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaListView.h +++ /dev/null @@ -1,174 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#pragma once -#include - -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include - -#include - -namespace sofa::gui::qt -{ - -class SOFA_GUI_QT_API QSofaListView : public SofaSceneGraphWidget -{ - Q_OBJECT -public: - class LockContextManager - { - public: - QSofaListView* self{nullptr}; - bool state{true}; - - LockContextManager(QSofaListView* view, bool isLocked) - { - self = view; - state = view->isLocked(); - if(isLocked) - view->lock(); - else - view->unLock(); - } - - ~LockContextManager() - { - if(state) - self->lock(); - else - self->unLock(); - } - }; - - QSofaListView(const SofaListViewAttribute& attribute, - QWidget* parent = nullptr, - const char* name = nullptr, - Qt::WindowFlags f = Qt::WindowType::Widget ); - ~QSofaListView() override; - - GraphListenerQListView* getListener() const { return graphListener_; } - - void setPropertyWidget(QDisplayPropertyWidget* propertyWid) {propertyWidget = propertyWid;} - void addInPropertyWidget(QTreeWidgetItem *item, bool clear); - - void Clear(sofa::simulation::Node* rootNode); - - /// Updates the view so it is synchronized with the simulation graph. - /// The view can be visually de-synchronized with the simulation graph. This happens - /// when the view is "frozen" for performance reason. In that case, use isDirty to - /// get current view state or the dirtynessChanged() signal. - /// To resynchronize the view call the update method. - void update(); - void setRoot(sofa::simulation::Node*); - - SofaListViewAttribute getAttribute() const { return attribute_; } - - void contextMenuEvent(QContextMenuEvent *event) override; - - void expandPathFrom(const std::vector& pathes); - void getExpandedNodes(std::vector&); - - void loadObject ( std::string path, double dx, double dy, double dz, double rx, double ry, double rz,double scale ) = delete; - -public Q_SLOTS: - void Export(); - void CloseAllDialogs(); - void UpdateOpenedDialogs(); - void ExpandRootNodeOnly(); - -Q_SIGNALS: - void Close(); - void Lock(bool); - void RequestSaving(sofa::simulation::Node*); - void RequestExportOBJ(sofa::simulation::Node* node, bool exportMTL); - void RequestActivation(sofa::simulation::Node*,bool); - void RequestSleeping(sofa::simulation::Node*, bool); - void RootNodeChanged(sofa::simulation::Node* newroot, const char* newpath); - void NodeRemoved(); - void Updated(); - void NodeAdded(); - void focusChanged(sofa::core::objectmodel::BaseObject*); - void focusChanged(sofa::core::objectmodel::BaseNode*); - void dataModified( QString ); - - -protected Q_SLOTS: - void SaveNode(); - void exportOBJ(); - void collapseNode(); - void expandNode(); - void modifyUnlock(void* Id); - void RemoveNode(); - void Modify(); - void openInEditor(); - void openInstanciation(); - void openImplementation(); - void copyFilePathToClipBoard(); - void DeactivateNode(); - void ActivateNode(); - void PutNodeToSleep(); - void WakeUpNode(); - - void updateMatchingObjectmodel(QTreeWidgetItem* item, int); - void updateMatchingObjectmodel(QTreeWidgetItem* item); - - void RunSofaRightClicked(const QPoint& point); - void RunSofaDoubleClicked( QTreeWidgetItem* item, int index); - - void nodeNameModification( simulation::Node*); - void focusObject(); - void focusNode(); - -protected: - void expandPath(const std::string& path) ; - void getExpandedNodes(QTreeWidgetItem* item, std::vector&) ; - void collapseNode(QTreeWidgetItem* item); - void expandNode(QTreeWidgetItem* item); - - void transformObject ( sofa::simulation::Node *node, double dx, double dy, double dz, double rx, double ry, double rz, double scale ) = delete; - - bool isNodeErasable( core::objectmodel::BaseNode* node); - - std::list collectNodesToChange(core::objectmodel::BaseNode* node); - std::map< void*, QTreeWidgetItem* > map_modifyDialogOpened; - std::map< void*, QDialog* > map_modifyObjectWindow; - GraphListenerQListView* graphListener_; - std::vector< std::string > list_object; - AddObject* AddObjectDialog_; - ObjectModel object_; - SofaListViewAttribute attribute_; - QDisplayPropertyWidget* propertyWidget; - - -}; - -} //namespace sofa::gui::qt diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.cpp deleted file mode 100644 index e88631b6768..00000000000 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/QSofaStatWidget.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU General Public License as published by the Free * -* Software Foundation; either version 2 of the License, or (at your option) * -* any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * -* more details. * -* * -* You should have received a copy of the GNU General Public License along * -* with this program. If not, see . * -******************************************************************************* -* Authors: The SOFA Team and external contributors (see Authors.txt) * -* * -* Contact information: contact@sofa-framework.org * -******************************************************************************/ -#include "QSofaStatWidget.h" -#include "GraphListenerQListView.h" -#include -#include -#include -#include - - -#include -#include -#include - -using namespace sofa::simulation; -using namespace sofa::core::objectmodel; - -namespace sofa::gui::qt -{ - -QSofaStatWidget::QSofaStatWidget(QWidget* parent) - : QWidget(parent) -{ - QVBoxLayout* layout = new QVBoxLayout(this); - statsLabel = new QLabel(this); - statsLabel->setText(QString("Collision Elements present :")); - statsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - statsLabel->setWordWrap(false); - - layout->addWidget(statsLabel); - - statsCounter = new QTreeWidget(this); - statsCounter->setHeaderLabels(QStringList() << "Name" << "Type" << "Size" << "Groups"); - - layout->addWidget(statsCounter); - -} - -void QSofaStatWidget::CreateStats(Node* root) -{ - sofa::type::vector< sofa::core::CollisionModel* > list_collisionModels; - root->get< sofa::core::CollisionModel >( &list_collisionModels, BaseContext::SearchDown); - - if (items_stats.size() != 0) - { - delete items_stats[0].second; - items_stats.clear(); - } - - for(int i=0 ; itopLevelItemCount() ; i++) - delete statsCounter->takeTopLevelItem(i); - - - addCollisionModelsStat(list_collisionModels); - - addSummary(); - - -} - -void QSofaStatWidget::addCollisionModelsStat(const sofa::type::vector< sofa::core::CollisionModel* >& v) -{ - std::map< BaseContext*, QTreeWidgetItem* > listStats; - for (unsigned int i=0; iisActive()) continue; - std::map< BaseContext*, QTreeWidgetItem* >::iterator it = listStats.find(v[i]->getContext()); - QTreeWidgetItem *item; - if (it != listStats.end()) - { - item = new QTreeWidgetItem((*it).second); - } - else - { - QTreeWidgetItem *node = new QTreeWidgetItem(statsCounter); - node->setText(0,QString(v[i]->getContext()->getName().c_str())); - const QPixmap* pix = getPixmap(v[i]->getContext(), false,false,false); - if (pix) node->setIcon(0, QIcon(*pix)); - listStats.insert(std::make_pair(v[i]->getContext(), node)); - item = new QTreeWidgetItem(node); - node->setExpanded(true); - } - assert(item); - item->setText(0,v[i]->getName().c_str()); - item->setText(1,QString(v[i]->getClassName().c_str())); - item->setText(0,v[i]->getName().c_str()); - item->setText(2,QString::number(v[i]->getSize())); - { - const std::set& groups = v[i]->getGroups(); - QString groupString; - std::set::const_iterator it = groups.begin(), itend = groups.end(); - for( ; it != itend ; ++it ) groupString += QString::number(*it) + ", "; - item->setText(3,groupString); - } - items_stats.push_back(std::make_pair(v[i], item)); - } -} - -void QSofaStatWidget::addSummary() -{ - std::set< std::string > nameElement; - std::map< std::string, int > mapElement; - for (unsigned int i=0; i < items_stats.size(); i++) - nameElement.insert(items_stats[i].first->getClassName()); - - - for (unsigned int i=0; i < items_stats.size(); i++) - mapElement[items_stats[i].first->getClassName()] += (items_stats[i].second->text(2).toInt()); - - - std::string textStats("