[
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  WebKit\nAccessModifierOffset: -4\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Left\nAlignOperands:   true\nAlignTrailingComments: false\nAllowAllParametersOfDeclarationOnNextLine: false\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: Inline\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: true\nBinPackArguments: false\nBinPackParameters: false\nBraceWrapping:\n  AfterClass:      true\n  AfterControlStatement: false\n  AfterEnum:       true\n  AfterFunction:   true\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     true\n  AfterUnion:      false\n  BeforeCatch:     true\n  BeforeElse:      true\n  IndentBraces:    false\n  SplitEmptyFunction: false\n  SplitEmptyRecord: false\n  SplitEmptyNamespace: false\nBreakBeforeBinaryOperators: NonAssignment\nBreakBeforeBraces: Custom\nBreakBeforeInheritanceComma: true\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: true\nBreakConstructorInitializers: BeforeComma\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:   80\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDerivePointerAlignment: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks: Preserve\nIncludeCategories:\n  - Regex:           '^\"(llvm|llvm-c|clang|clang-c)/'\n    Priority:        2\n  - Regex:           '^(<|\"(gtest|gmock|isl|json)/)'\n    Priority:        3\n  - Regex:           '.*'\n    Priority:        1\nIncludeIsMainRegex: '(Test)?$'\nIndentCaseLabels: true\nIndentWidth:     4\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: true\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: All\nObjCBlockIndentWidth: 4\nObjCSpaceAfterProperty: true\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakAssignment: 2\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Left\nReflowComments:  true\nSortIncludes:    true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: true\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles:  false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard:        Cpp11\nTabWidth:        4\nUseTab:          Never\n...\n"
  },
  {
    "path": ".docker/Dockerfile",
    "content": "ARG from=diegoferigo/gym-ignition:pypi-master\nFROM ${from}\n\n# Install the PyPI package in a virtualenv\nARG pip_options=\"\"\nRUN virtualenv -p $(which python3) ${VIRTUAL_ENV} &&\\\n    python -m pip install --upgrade pip &&\\\n    pip install ${pip_options} gym-ignition &&\\\n    rm -r $HOME/.cache/pip\n\n# Clone the repository\nWORKDIR /github\nARG branch=\"master\"\nRUN git clone -b ${branch} https://github.com/robotology/gym-ignition /github\n\n# Reset the entrypoint\nENTRYPOINT [\"\"]\n\nCMD [\"bash\"]\n"
  },
  {
    "path": ".docker/base.Dockerfile",
    "content": "ARG from=ubuntu:focal\nFROM ${from}\n\nSHELL [\"/bin/bash\", \"-c\"]\n\n# Setup locales and timezone\nARG TZ=Europe/Rome\nARG DEBIAN_FRONTEND=noninteractive\nRUN rm -f /etc/localtime &&\\\n    ln -s /usr/share/zoneinfo/\"${TZ}\" /etc/localtime &&\\\n    apt-get update &&\\\n    apt-get install -y --no-install-recommends locales locales-all tzdata &&\\\n    rm -rf /var/lib/apt/lists/*\n\n# Install tools and toolchain\nRUN apt-get update &&\\\n    apt-get install -y --no-install-recommends \\\n        wget \\\n        software-properties-common \\\n        apt-transport-https \\\n        apt-utils \\\n        gnupg2 \\\n        nano \\\n        rename \\\n        source-highlight \\\n        &&\\\n    wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | apt-key add - && \\\n    apt-add-repository \"deb https://apt.kitware.com/ubuntu/ `lsb_release -cs` main\" &&\\\n    add-apt-repository ppa:deadsnakes/ppa &&\\\n    wget -nv -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - &&\\\n    apt-add-repository -y \"deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-10 main\" &&\\\n    apt-get update &&\\\n    apt-get install -y --no-install-recommends \\\n        build-essential \\\n        clang-10 \\\n        git \\\n        cmake \\\n        cmake-curses-gui \\\n        ninja-build \\\n        valgrind \\\n        libgflags-dev \\\n        python3-pip \\\n        python3-wheel \\\n        python3.8 \\\n        python3.8-dev \\\n        libpython3.8-dev \\\n        virtualenv \\\n        swig \\\n        &&\\\n    rm -rf /var/lib/apt/lists/*\n\n# Update git (required by actions/checkout)\nRUN add-apt-repository ppa:git-core/ppa &&\\\n    apt-get update &&\\\n    apt-get install -y --no-install-recommends git &&\\\n    rm -rf /var/lib/apt/lists/*\n\n# Common virtualenv properties\nENV VIRTUAL_ENV=/venv\nENV PATH=$VIRTUAL_ENV/bin:$PATH\n\nCMD [\"bash\"]\n"
  },
  {
    "path": ".docker/cicd-devel.Dockerfile",
    "content": "ARG from=diegoferigo/gym-ignition:base\nFROM ${from}\n\nRUN pip3 install vcstool colcon-common-extensions &&\\\n    rm -r $HOME/.cache/pip\n\nARG CMAKE_BUILD_TYPE=\"Release\"\nARG ignition_codename=\"fortress\"\nARG IGNITION_DEFAULT_CHANNEL=\"stable\"\n\nRUN echo \"deb http://packages.osrfoundation.org/gazebo/ubuntu-${IGNITION_DEFAULT_CHANNEL} `lsb_release -cs` main\" > \\\n        /etc/apt/sources.list.d/gazebo-${IGNITION_DEFAULT_CHANNEL}.list &&\\\n    wget http://packages.osrfoundation.org/gazebo.key -O - | apt-key add - &&\\\n    apt-get update &&\\\n    mkdir -p /workspace/src &&\\\n    cd /workspace/src &&\\\n    wget https://raw.githubusercontent.com/ignition-tooling/gazebodistro/master/collection-${ignition_codename}.yaml &&\\\n    vcs import < collection-${ignition_codename}.yaml &&\\\n    apt -y install --no-install-recommends \\\n        $(sort -u $(find . -iname 'packages-'$(lsb_release -cs)'.apt' -o -iname 'packages.apt') | grep -v -E \"dart|^libignition|^libsdformat\" | tr '\\n' ' ') &&\\\n    rm -rf /var/lib/apt/lists/* &&\\\n    cd /workspace &&\\\n    colcon graph &&\\\n    colcon build \\\n        --cmake-args \\\n            -GNinja \\\n            -DBUILD_TESTING:BOOL=OFF \\\n            -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \\\n        --merge-install \\\n        &&\\\n    find build/ -type f -not -name 'CMakeCache.txt' -delete &&\\\n    echo \"source /workspace/install/setup.bash\" >> /etc/bash.bashrc\n\n# Source /etc/bash.bashrc before each command\nSHELL [\"/bin/bash\", \"-i\", \"-c\"]\n\nCOPY entrypoint.sh /entrypoint.sh\nCOPY setup_virtualenv.sh /setup_virtualenv.sh\nRUN chmod 755 /entrypoint.sh\nRUN chmod 755 /setup_virtualenv.sh\nENTRYPOINT [\"/entrypoint.sh\"]\nCMD [\"bash\"]\n"
  },
  {
    "path": ".docker/cicd-master.Dockerfile",
    "content": "ARG from=diegoferigo/gym-ignition:base\nFROM ${from}\n\n# Install ignition gazebo\nARG ignition_codename=\"fortress\"\nRUN echo \"deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main\" \\\n        > /etc/apt/sources.list.d/gazebo-stable.list &&\\\n    wget http://packages.osrfoundation.org/gazebo.key -O - | apt-key add - &&\\\n    apt-get update &&\\\n    apt-get install -y --no-install-recommends ignition-${ignition_codename} &&\\\n    rm -rf /var/lib/apt/lists/*\n\nCOPY entrypoint.sh /entrypoint.sh\nCOPY setup_virtualenv.sh /setup_virtualenv.sh\nRUN chmod 755 /entrypoint.sh\nRUN chmod 755 /setup_virtualenv.sh\nENTRYPOINT [\"/entrypoint.sh\"]\nCMD [\"bash\"]\n"
  },
  {
    "path": ".docker/docker-compose.yml",
    "content": "version: '3.0'\n\nservices:\n\n  base:\n    build:\n      args:\n        from: ubuntu:focal\n      context: .\n      dockerfile: base.Dockerfile\n    image: diegoferigo/gym-ignition:base\n\n  # ======\n  # MASTER\n  # ======\n\n  ci-master:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:base\n        ignition_codename: dome\n      context: .\n      dockerfile: cicd-master.Dockerfile\n    image: diegoferigo/gym-ignition:ci-master\n\n  pypi-master:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:base\n        ignition_codename: dome\n      context: .\n      dockerfile: cicd-master.Dockerfile\n    image: diegoferigo/gym-ignition:pypi-master\n\n  # =====\n  # DEVEL\n  # =====\n\n  ci-devel:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:base\n        ignition_codename: fortress\n        CMAKE_BUILD_TYPE: Debug\n      context: .\n      dockerfile: cicd-devel.Dockerfile\n    image: diegoferigo/gym-ignition:ci-devel\n\n  pypi-devel:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:base\n        ignition_codename: fortress\n        CMAKE_BUILD_TYPE: Release\n      context: .\n      dockerfile: cicd-devel.Dockerfile\n    image: diegoferigo/gym-ignition:pypi-devel\n\n  # ====\n  # DEMO\n  # ====\n\n  latest:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:pypi-master\n        branch: master\n      context: .\n      dockerfile: Dockerfile\n    image: diegoferigo/gym-ignition:latest\n\n  nightly:\n    build:\n      args:\n        from: diegoferigo/gym-ignition:ci-devel\n        branch: devel\n        pip_options: --pre\n      context: .\n      dockerfile: Dockerfile\n    image: diegoferigo/gym-ignition:nightly\n"
  },
  {
    "path": ".docker/entrypoint.sh",
    "content": "#!/bin/bash\nset -e\n\nif [ ! -x \"/setup_virtualenv.sh\" ] ; then\n    echo \"File '/setup_virtualenv.sh' not found.\"\n    exit 1\nfi\n\n# Setup the python virtualenv\nbash /setup_virtualenv.sh\n\n# If a CMD is passed, execute it\nexec \"$@\"\n"
  },
  {
    "path": ".docker/setup_virtualenv.sh",
    "content": "#!/bin/bash\nset -eu\n\n# Read the env variable if exists, otherwise fall back to python3\nPYTHON_EXE=python${PYTHON_VERSION:-3}\n\nif [ ! -x $(type -P ${PYTHON_EXE}) ] ; then\n    echo \"Failed to find ${PYTHON_EXE} in PATH\"\n    exit 1\nfi\n\n# Create an empty virtualenv and enable it by default\nvirtualenv -p $PYTHON_EXE ${VIRTUAL_ENV}\n\n# Install pytest in the virtual environment\n${VIRTUAL_ENV}/bin/pip3 install pytest\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Default owners\n*       @diegoferigo\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Report a bug\nlabels: issue::type::bug\n---\n\n<!-- Remove this warning before posting the issue -->\n\n⚠️ If you're not sure whether your problem is a bug, please ask a question in [Discussions][Discussions] instead.\n\n<!-- Make sure you already checked the existing documentation and mark all the checks -->\n\n- [ ] I've read the [FAQ][FAQ]\n- [ ] I've read the [Support Policy][Support Policy]\n- [ ] I've already searched similar [issues][Issues] and [discussions][Discussions]\n- [ ] I've already updated to the most recent supported [release][Releases] (either Stable or Nightly)\n\n[Issues]: https://github.com/robotology/gym-ignition/issues\n[Releases]: https://github.com/robotology/gym-ignition/releases\n[FAQ]: https://robotology.github.io/gym-ignition/master/info/faq.html\n[Discussions]: https://github.com/robotology/gym-ignition/discussions\n[Support Policy]: https://robotology.github.io/gym-ignition/master/installation/support_policy.html\n    \n## Description:\n\nA clear and concise description of the bug and what should be the expected behavior.\n\n## Steps to reproduce\n\n1.\n1.\n1.\n\nor\n\n```python\n# Insert some code\n```\n\n## Additional context\n\n<!-- Screenshots, console logs, backtraces, ... -->\n\n<details>\n<summary>Title</summary>\n\nContent\n\n</details>\n\n## Environment\n\n- OS: <!-- Insert the distribution, e.g. Ubuntu 20.04 -->\n- GPU: <!-- Insert your GPU, e.g. Intel XXX integrated -->    \n- Python: <!-- Insert the active Python version and provider, e.g. 3.8.X from virtualenv -->\n- Version: <!-- Insert the installed version of gym-ignition and scenario, e.g. v1.2.0 -->\n- Channel:\n  - [ ] Stable\n  - [ ] Nightly\n- Installation type:\n  - [ ] User\n  - [ ] Developer\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Request a new feature\nlabels: issue::type::enhancement\n---\n\n<!-- Remove this warning before posting the issue -->\n\n⚠️ If you're not sure on the specifics of the feature or would like a broader discussion, please consider posting a proposal to [Discussions][Discussions] instead.\n\n[Discussions]: https://github.com/robotology/gym-ignition/discussions\n\n## Summary\n\nDescribe what this new feature is about and the context you would find it useful.\n\n## Implementation suggestion\n\nProvide a suggestion on how to implement this feature, which could help us to speed up the implementation.\n\n## Additional context\n\nScreenshots, videos, links, sketches, ...\n"
  },
  {
    "path": ".github/release.yml",
    "content": "changelog:\n  exclude:\n    labels:\n      - pr::changelog::ignore\n    authors: [ ]\n  categories:\n    - title: Bug fixing and new features\n      labels:\n        - pr::changelog::bugfix\n        - pr::changelog::release\n        - pr::changelog::feature\n    - title: Documentation, CI/CD, tests\n      labels:\n        - pr::changelog::docs\n        - pr::changelog::cicd\n        - pr::changelog::tests\n    - title: Other changes\n      labels:\n        - pr::changelog::other\n    - title: No category\n      labels: [ \"*\" ]\n"
  },
  {
    "path": ".github/workflows/cicd.yml",
    "content": "name: CI/CD\n\non:\n  push:\n    branches: [\"**\"]\n    tags-ignore: [\"**\"]\n  pull_request:\n  workflow_dispatch:\n  release:\n    types: [published]\n\njobs:\n\n# =============\n  build-colcon:\n# =============\n    name: 'colcon@${{ matrix.ignition }}'\n    if: |\n      (github.event_name == 'push' && github.ref != 'refs/heads/master') ||\n      (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'master')\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        ignition:\n          # - dome\n          # - edifice\n          - fortress\n    env:\n      CCACHE_DIR: ${{ github.workspace }}/.ccache\n    steps:\n\n      - name: '🔍️ Inspect Environment'\n        run: |\n          env | grep ^GITHUB\n          echo \"\"\n          cat ${GITHUB_EVENT_PATH}\n          echo \"\"\n          env\n\n      - name: '⬇️️ Install dependencies'\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y --no-install-recommends \\\n            lz4 \\\n            git \\\n            wget \\\n            gpg-agent \\\n            ninja-build \\\n            build-essential \\\n            software-properties-common\n\n      - name: '🐍 Initialize Python'\n        uses: actions/setup-python@v2\n        with:\n          python-version: 3.8\n\n      - name: '🚚 Compilation cache'\n        uses: actions/cache@v2\n        with:\n          path: ${{ env.CCACHE_DIR }}\n          # We include the commit sha in the cache key, as new cache entries are\n          # only created if there is no existing entry for the key yet.\n          key: ${{ runner.os }}-ccache-${{ matrix.ignition }}-${{ github.sha }}\n          # Restore any ccache cache entry, if none for the key above exists\n          restore-keys: ${{ runner.os }}-ccache-${{ matrix.ignition }}\n\n      - name: '🚚 Enable ccache'\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y ccache\n          echo \"/usr/lib/ccache\" >> $GITHUB_PATH\n          ccache --set-config=max_size=5.0G\n          ccache --set-config=sloppiness=file_macro,locale,time_macros\n          ccache -p\n          ccache -s\n\n      - name: '⚙️ Add osrf ppa'\n        run: |\n          sudo sh -c 'echo \"deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main\" >\\\n            /etc/apt/sources.list.d/gazebo-stable.list'\n          wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -\n          sudo apt-get update\n\n      - name: '⚙️ Prepare colcon workspace'\n        run: |\n          pip install vcstool colcon-common-extensions\n          sudo mkdir -p /workspace/src /workspace/install\n          sudo chmod -R a+rw /workspace\n          cd /workspace/src\n          wget -O - ${TAGS_YAML} | vcs import\n          echo $(sort -u $(find . -iname 'packages-'$(lsb_release -cs)'.apt' -o -iname 'packages.apt') | grep -v -E \"^libignition|^libsdformat\" | tr '\\n' ' ') \\\n            > /workspace/install/pkg.txt\n          xargs -a /workspace/install/pkg.txt sudo apt-get install -y --no-install-recommends\n        env:\n          TAGS_YAML: https://raw.githubusercontent.com/ignition-tooling/gazebodistro/master/collection-${{ matrix.ignition }}.yaml\n\n      - name: '🏗️ Build colcon workspace'\n        run: |\n          cd /workspace\n          colcon graph\n          colcon build \\\n              --cmake-args \\\n                  -GNinja \\\n                  -DBUILD_TESTING:BOOL=OFF \\\n                  -DCMAKE_BUILD_TYPE=Debug \\\n              --merge-install\n\n      - name: '📈 Ccache stats'\n        run: ccache --show-stats\n\n      - name: '📦️ Compress the workspace'\n        run: tar -I lz4 -cf /tmp/workspace_install.tar.lz4 /workspace/install\n      - name: '⬆️ Upload the workspace'\n        uses: actions/upload-artifact@v2\n        with:\n          path: /tmp/workspace_install.tar.lz4\n          name: workspace-${{ matrix.ignition }}\n          retention-days: 1\n\n# ===============\n  build-and-test:\n# ===============\n    name: 'Build and Test [${{matrix.type}}|${{matrix.ignition}}|${{matrix.python}}]'\n    if: always()\n    needs: [ build-colcon ]\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          - ubuntu-latest\n        type:\n          - User\n          - Developer\n        ignition:\n          # - dome\n          # - edifice\n          - fortress\n        python:\n          - 3.8\n          - 3.9\n    steps:\n\n      - name: '🔍 Inspect Environment'\n        run: |\n          env | grep ^GITHUB\n          echo \"\"\n          cat ${GITHUB_EVENT_PATH}\n          echo \"\"\n          env\n\n      - name: '⬇️ Install build dependencies'\n        if: contains(matrix.os, 'ubuntu')\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y --no-install-recommends \\\n            lz4 \\\n            git \\\n            wget \\\n            cmake \\\n            gpg-agent \\\n            ninja-build \\\n            build-essential \\\n            software-properties-common\n\n      - name: '🐍 Initialize Python'\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python }}\n\n      - name: '🔀 Clone repository'\n        uses: actions/checkout@master\n      - name: '🔀 Download all refs'\n        run: git fetch --prune --unshallow\n\n      # ================\n      # Install Ignition\n      # ================\n\n      - name: '⚙️ Add osrf ppa'\n        if: contains(matrix.os, 'ubuntu')\n        run: |\n          sudo sh -c 'echo \"deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main\" >\\\n            /etc/apt/sources.list.d/gazebo-stable.list'\n          wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -\n          sudo apt-get update\n      - name: '[🔒️|stable] Install Ignition from ppa'\n        if: |\n          contains(matrix.os, 'ubuntu') && (\n            github.event_name == 'release' ||\n            github.ref == 'refs/heads/master' ||\n            (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'master')\n          )\n        run: sudo apt-get install -y --no-install-recommends ignition-${{ matrix.ignition }}\n\n      - name: '[🧪|nightly] Download pre-built colcon workspace'\n        uses: actions/download-artifact@v2\n        if: |\n          contains(matrix.os, 'ubuntu') && (\n            (github.event_name == 'push' && github.ref != 'refs/heads/master') ||\n            (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'master')\n          )\n        with:\n          path: /tmp\n          name: workspace-${{ matrix.ignition }}\n      - name: '[🧪|nightly] Setup colcon workspace'\n        if: |\n          contains(matrix.os, 'ubuntu') && (\n            (github.event_name == 'push' && github.ref != 'refs/heads/master') ||\n            (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'master')\n          )\n        run: |\n          sudo tar -I lz4 -xf /tmp/workspace_install.tar.lz4 -C /\n          xargs -a /workspace/install/pkg.txt sudo apt-get install -y --no-install-recommends\n          echo \"source /workspace/install/setup.bash\" | sudo tee -a /etc/bash.bashrc\n\n      # =============\n      # Build project\n      # =============\n\n      # This is required because ScenarIO needs to import the iDynTree targets\n      - name: '⬇️ Install iDynTree dependencies'\n        if: contains(matrix.os, 'ubuntu')\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y --no-install-recommends \\\n            libxml2-dev coinor-libipopt-dev libeigen3-dev libassimp-dev swig\n      - name: '🤖 Install iDynTree'\n        run: |\n          pip install idyntree\n          IDYNTREE_PYTHON_PKG=$(python3 -c 'import idyntree, pathlib; print(pathlib.Path(idyntree.__file__).parent)')\n          echo \"CMAKE_PREFIX_PATH=$IDYNTREE_PYTHON_PKG\" >> $GITHUB_ENV\n\n      # Note: In order to execute the setup.sh script, the file /etc/bash.bashrc must be sourced.\n      #       To do that, we change the shell to a bash interactive session with 'bash -i -e'.\n\n      # Developer installation\n      - name: '[👷|developer] Build and Install C++ ScenarIO'\n        if: matrix.type == 'Developer'\n        shell: bash -i -e {0}\n        run: |\n          env\n          cmake -S . -B build/ \\\n            -GNinja \\\n            -DCMAKE_BUILD_TYPE=Debug \\\n            -DIGNITION_DISTRIBUTION=$(python3 -c \"print('${{ matrix.ignition }}'.capitalize())\")\n          sudo cmake --build build/ --target install\n      - name: '[👷|developer] Install Python ScenarIO'\n        if: matrix.type == 'Developer'\n        run: pip install -e ./scenario\n\n      # User installation\n      - name: '[👤|user] Create wheel (default ignition)'\n        if: matrix.type == 'User' && matrix.ignition == 'fortress'\n        shell: bash -i -e {0}\n        run: pip wheel --use-feature=in-tree-build -v -w dist/ ./scenario\n      # Note: Calling \"pip wheel\" with \"--global-option\" forces all dependencies to be built from their sdist.\n      #       Since it's very slow, we create the wheel from setup.py without isolation (requires system deps).\n      - name: '[👤|user] Create wheel (custom ignition)'\n        if: matrix.type == 'User' && matrix.ignition != 'fortress'\n        shell: bash -i -e {0}\n        run: |\n          pip install wheel setuptools-scm cmake-build-extension\n          python3 ./scenario/setup.py bdist_wheel \\\n            build_ext -DIGNITION_DISTRIBUTION=$(python3 -c \"print('${{ matrix.ignition }}'.capitalize())\")\n      - name: '[👤|user] Install local wheel'\n        if: matrix.type == 'User'\n        run: pip install -v dist/scenario-*.whl\n\n      - name: '🔍️ Inspect installed ScenarIO package'\n        if: matrix.type == 'User' && contains(matrix.os, 'ubuntu')\n        run: |\n          sudo apt-get install -y --no-install-recommends tree\n          tree $(python3 -c \"import scenario, pathlib; print(pathlib.Path(scenario.__file__).parent)\")\n\n      # ====================\n      # Install gym-ignition\n      # ====================\n\n      - name: '🐍 Install gym-ignition'\n        run: pip install wheel && pip install .[all]\n\n      # ============\n      # Test project\n      # ============\n\n      - name: '🔍 Inspect installed versions'\n        run: pip list | grep -E \"^scenario|^gym-ignition\"\n\n      - name: '[🐍|scenario] Python Tests'\n        shell: bash -i -e {0}\n        run: pytest -m \"scenario\"\n\n      - name: '[🚨|scenario] Python Tests with Valgrind'\n        shell: bash -i -e {0}\n        if: failure()\n        run: |\n          sudo apt-get install -y --no-install-recommends valgrind\n          pip install colour-valgrind\n          valgrind --log-file=/tmp/valgrind.log pytest -m \"scenario\" || colour-valgrind -t /tmp/valgrind.log\n\n      - name: '[🐍|gym-ignition] Python Tests'\n        shell: bash -i -e {0}\n        run: pytest -m \"gym_ignition\"\n\n      - name: '[🚨|gym-ignition] Python Tests with Valgrind'\n        shell: bash -i -e {0}\n        if: failure()\n        run: |\n          sudo apt-get install -y --no-install-recommends valgrind\n          pip install colour-valgrind\n          valgrind --log-file=/tmp/valgrind.log pytest -m \"gym_ignition\" || colour-valgrind -t /tmp/valgrind.log\n\n      # ============================\n      # Upload artifacts (only User)\n      # ============================\n\n      - name: '🗑️ Remove external wheels'\n        if: matrix.type == 'User'\n        run: find dist/ -type f -not -name 'scenario-*' -delete -print\n\n      # We have to trick PyPI that our wheels are manylinux2014 even if they are not.\n      # Unfortunately we cannot create self-contained wheels (neither the PEP600 perennial)\n      # due to the Ignition architecture.\n      - name: '📝 Rename scenario wheel'\n        if: matrix.type == 'User' && contains(matrix.os, 'ubuntu')\n        run: |\n          ls dist/\n          find dist/ -type f -name \"*.whl\" -exec rename.ul linux manylinux2014 {} +\n          ls dist/\n\n      - name: '🔍 Inspect dist folder'\n        if: matrix.type == 'User'\n        run: ls -lah dist/\n\n      - name: '⬆️ Upload artifacts'\n        uses: actions/upload-artifact@v2\n        if: matrix.type == 'User' && matrix.ignition == 'fortress'\n        with:\n          path: dist/*\n          name: dist\n\n      # =======\n      # Website\n      # =======\n\n      - name: '⬇️ Install website dependencies'\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y doxygen texlive-font-utils\n\n      - name: '🔍 Inspect metadata'\n        run: sphinx-multiversion --dump-metadata docs/sphinx/ build/\n\n      # This is necessary because otherwise the check for uncommitted apidoc\n      # only detects additions, not removals.\n      - name: '🗑️ Remove apidoc folder'\n        run: rm -r docs/sphinx/apidoc\n\n      - name: '🏗️ Build sphinx website'\n        shell: bash -i -e {0}\n        run: |\n          [[ -d build ]] && sudo chown -R $(id -u):$(id -g) build/\n          cmake -S . -B build/ -DBUILD_DOCS:BOOL=ON\n          cmake --build build/ --target sphinx\n\n      - name: '🔍 Check new uncommitted apidoc'\n        run: test $(git status --porcelain | wc -l) -eq 0\n\n      - name: '🔍 git status'\n        if: ${{ failure() }}\n        run: |\n          git status\n          git diff\n\n      - name: '⬆️ Upload website folder'\n        uses: actions/upload-artifact@v2\n        if: matrix.type == 'User' && matrix.ignition == 'fortress' && contains(matrix.os, 'ubuntu')\n        with:\n          path: build/html\n          name: website\n          retention-days: 1\n\n# ===================\n  website-deployment:\n# ===================\n    name: 'Website Deployment'\n    if: always() && needs.build-and-test.result == 'success'\n    needs: [ build-and-test ]\n    runs-on: ubuntu-latest\n    steps:\n\n      - name: '⬇️ Download website folder'\n        uses: actions/download-artifact@v2\n        with:\n          path: build/html\n          name: website\n\n      - name: '🔍 Inspect html folder'\n        run: ls -lah build/html\n\n      - name: '🚀 Deploy'\n        uses: JamesIves/github-pages-deploy-action@releases/v3\n        if: |\n          github.event_name == 'push' &&\n          github.repository == 'robotology/gym-ignition' &&\n          (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/devel')\n        with:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          BRANCH: gh-pages\n          FOLDER: build/html\n          CLEAN: true\n          CLEAN_EXCLUDE: '[\".gitignore\", \".nojekyll\"]'\n\n# =================\n  python-packaging:\n# =================\n    name: 'Python packaging'\n    if: always() && needs.build-and-test.result == 'success'\n    needs: [ build-and-test ]\n    runs-on: ubuntu-latest\n    steps:\n\n      - name: '🔍️ Inspect Environment'\n        run: |\n          env | grep ^GITHUB\n          echo \"\"\n          cat ${GITHUB_EVENT_PATH}\n          echo \"\"\n          env\n\n      # Any Python3 version is ok in this job\n      - name: '🐍 Initialize Python'\n        uses: actions/setup-python@v2\n        with:\n          python-version: 3.8\n\n      - name: '🔀 Clone repository'\n        uses: actions/checkout@master\n      - name: '🔀 Download all refs'\n        run: git fetch --prune --unshallow\n\n      # ===============\n      # Download wheels\n      # ===============\n\n      - name: '⬇️ Download scenario wheels'\n        uses: actions/download-artifact@v2\n        with:\n          path: dist\n          name: dist\n\n      - name: '🔍 Inspect dist folder'\n        run: ls -lah dist/\n\n      # ===============\n      # Create packages\n      # ===============\n\n      # We use build to create sdist. Also pipx would work.\n      # https://github.com/pypa/build\n      # Compared to calling setup.py, the advantage of these tools is that\n      # they automatically handle the build dependencies.\n      - name: '🐍️️ Install dependencies'\n        run: pip install build\n\n      - name: '[📦|scenario]️ Create sdist'\n        run: python -m build --sdist scenario/ -o dist/\n\n      - name: '[📦|gym-ignition]️ Create sdist and wheel'\n        run: python -m build .\n\n      # ================\n      # Upload artifacts\n      # ================\n\n      - name: '🗑️ Remove external packages'\n        run: find dist/ -type f -not \\( -name '*scenario-*' -o -name '*gym_ignition-*' \\) -delete -print\n\n      - name: '🔍 Check packages'\n        run: pipx run twine check dist/*\n\n      - name: '🔍 Inspect dist folder'\n        run: ls -lah dist/\n\n      - name: '⬆️ Upload artifacts'\n        uses: actions/upload-artifact@v2\n        with:\n          path: dist/*\n          name: dist\n\n# ============\n  upload_pypi:\n# ============\n    name: Publish to PyPI\n    if: always() && needs.build-and-test.result == 'success' && needs.python-packaging.result == 'success'\n    needs:\n      - build-and-test\n      - python-packaging\n    runs-on: ubuntu-latest\n    # Devel branch produces pre-releases.\n    # GitHub releases produce stable releases.\n\n    steps:\n\n      # Needed only to extract from the git repo the last revision\n      - name: '🔀 Clone repository'\n        uses: actions/checkout@master\n      - name: '🔀 Download all refs'\n        run: git fetch --prune --unshallow\n\n      - name: '⬇️ Download Python packages'\n        uses: actions/download-artifact@v2\n        with:\n          path: dist\n          name: dist\n\n      - name: '🔍 Inspect dist folder'\n        run: ls -lah dist/\n\n      # Validate the last tag accordingly to PEP440\n      # From https://stackoverflow.com/a/37972030/12150968\n      - name: '📌 Check PEP440 compliance'\n        if: github.event_name == 'release'\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y source-highlight\n          last_tag_with_v=\"$(git describe --abbrev=0 --tags)\"\n          last_tag=${last_tag_with_v#v}\n          rel_regexp='^(\\d+!)?(\\d+)(\\.\\d+)+([\\.\\-\\_])?((a(lpha)?|b(eta)?|c|r(c|ev)?|pre(view)?)\\d*)?(\\.?(post|dev)\\d*)?$'\n          echo \"\"\n          echo $last_tag\n          echo \"\"\n          check-regexp ${rel_regexp} ${last_tag}\n          match=$(check-regexp ${rel_regexp} ${last_tag} | grep matches | cut -d ' ' -f 5)\n          test $match -eq 1 && true\n\n      - name: '⬆️ Publish packages to PyPI'\n        if: |\n          github.repository == 'robotology/gym-ignition' &&\n          ((github.event_name == 'release' && github.event.action == 'published') ||\n           (github.event_name == 'push' && github.ref == 'refs/heads/devel'))\n        uses: pypa/gh-action-pypi-publish@master\n        with:\n          user: __token__\n          password: ${{ secrets.PYPI_TOKEN }}\n          skip_existing: true\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "content": "name: Docker Images\n\non:\n  push:\n    paths:\n      - \".docker/*\"\n      - \".github/workflows/docker.yml\"\n    branches: [\"**\"]\n    tags-ignore: [\"**\"]\n  pull_request:\n    paths:\n      - \".docker/*\"\n      - \".github/workflows/docker.yml\"\n  workflow_dispatch:\n  schedule:\n    # Execute a weekly build on Monday at 2AM UTC\n    - cron:  '0 2 * * 1'\n\njobs:\n  docker:\n    name: 'diegoferigo/gym-ignition:${{ matrix.tag }}'\n    runs-on: ubuntu-latest\n    strategy:\n      max-parallel: 1\n      matrix:\n        baseimage: ['ubuntu:bionic']\n        tag:\n          - base\n          - ci-master\n          - ci-devel\n          - pypi-master\n          - pypi-devel\n          #- latest\n          - nightly\n\n    steps:\n\n      # Use the branch that triggered the workflow for push and pull_request events\n      - uses: actions/checkout@master\n        if: github.event_name != 'schedule'\n\n      # Use devel branch for scheduled builds\n      - uses: actions/checkout@master\n        with:\n          ref: 'refs/heads/devel'\n        if: github.event_name == 'schedule'\n\n      - name: Build\n        env:\n          TAG: ${{ matrix.tag }}\n        run: |\n          cd .docker\n          docker-compose build ${TAG}\n\n      - name: Login\n        if: |\n          github.repository == 'robotology/gym-ignition' &&\n          github.event_name != 'pull_request' &&\n          (github.event_name == 'schedule' || github.ref == 'refs/heads/devel')\n        env:\n          DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}\n          DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}\n        run: echo ${DOCKER_PASSWORD} | docker login --username ${DOCKER_USERNAME} --password-stdin\n\n      - name: Push\n        if: |\n          github.repository == 'robotology/gym-ignition' &&\n          github.event_name != 'pull_request' &&\n          (github.event_name == 'schedule' || github.ref == 'refs/heads/devel')\n        run: docker push diegoferigo/gym-ignition:${{ matrix.tag }}\n"
  },
  {
    "path": ".github/workflows/style.yml",
    "content": "name: Code Style\n\non:\n  push:\n    branches: [\"**\"]\n    tags-ignore: [\"**\"]\n  pull_request:\n  workflow_dispatch:\n\njobs:\n\n  clang-format:\n\n    name: clang-format\n    runs-on: ubuntu-latest\n\n    steps:\n\n      - name: \"🔀 Checkout repository\"\n        uses: actions/checkout@v2\n\n      - name: \"⬇️️ Install dependencies\"\n        run: sudo apt-get install -y --no-install-recommends colordiff\n\n      - name: \"📝 Format C++\"\n        uses: diegoferigo/gh-action-clang-format@main\n        id: format\n        with:\n          style: file\n          pattern: |\n            *.h\n            *.cpp\n\n      - name: \"🔍️ Inspect style diff\"\n        if: failure()\n        run: printf \"${{ steps.format.outputs.diff }}\" | colordiff\n\n  black:\n\n    name: black\n    runs-on: ubuntu-latest\n\n    steps:\n\n      - name: \"🔀 Checkout repository\"\n        uses: actions/checkout@v2\n\n      - name: '🐍 Initialize Python'\n        uses: actions/setup-python@v2\n        with:\n          python-version: \"3.8\"\n\n      - name: \"📝 Black Code Formatter\"\n        uses: psf/black@stable\n        with:\n          options: --check --diff --color\n\n  isort:\n\n    name: isort\n    runs-on: ubuntu-latest\n\n    steps:\n\n      - name: \"🔀 Checkout repository\"\n        uses: actions/checkout@v2\n\n      - name: '🐍 Initialize Python'\n        uses: actions/setup-python@v2\n        with:\n          python-version: \"3.8\"\n\n      - name: \"📝 isort\"\n        uses: isort/isort-action@master\n        with:\n          configuration: --check --diff --color\n"
  },
  {
    "path": ".gitignore",
    "content": "*.mexa64\n*.mexmaci64\n*.autosave\n*.original\n*~\n.DS_Store\nbuild*\n*.bak\n*.old\nCMakeLists.txt.*\nCopy_of_*\n__pycache__\n*.egg-info\n*.cache\n.idea*\n**/dist/*\n.egg*\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# This file is here only to allow build systems to find the\n# real CMake project that is stored in the scenario/ folder.\ncmake_minimum_required(VERSION 3.16)\nproject(scenario)\nadd_subdirectory(scenario)\n\n# The uninstall target resource must be included in the top-level CMakeLists\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scenario/cmake)\ninclude(AddUninstallTarget)\n\n# =============\n# DOCUMENTATION\n# =============\n\nif(BUILD_DOCS)\n    add_subdirectory(docs)\nendif()\n"
  },
  {
    "path": "LICENSE",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<h1 align=\"center\">gym-ignition</h1>\n</p>\n\n<div align=\"center\">\n<table>\n    <tbody>\n         <tr>\n            <td align=\"center\">\n                <a href=\"https://github.com/robotology/gym-ignition/actions\">\n                <img src=\"https://github.com/robotology/gym-ignition/workflows/CI/CD/badge.svg\" alt=\"CICD\" />\n                </a>\n                <a href=\"https://github.com/robotology/gym-ignition/actions\">\n                <img src=\"https://github.com/robotology/gym-ignition/workflows/Docker%20Images/badge.svg\" alt=\"Docker Images\" />\n                </a>\n                <a href=\"https://www.codacy.com/gh/robotology/gym-ignition/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=robotology/gym-ignition&amp;utm_campaign=Badge_Grade\">\n                <img src=\"https://api.codacy.com/project/badge/Grade/5536b05f8be94483b64ee883e7170a39\" alt=\"Codacy Badge\" />\n                </a>\n            </td>\n        </tr>   \n        <tr>\n            <td align=\"center\">\n                <a href=\"https://pypi.org/project/gym-ignition/\">\n                <img src=\"https://img.shields.io/pypi/v/gym-ignition.svg\" />\n                </a>\n                <a href=\"https://pypi.org/project/gym-ignition/\">\n                <img src=\"https://img.shields.io/pypi/pyversions/gym-ignition.svg\" />\n                </a>\n                <a href=\"https://pypi.org/project/gym-ignition/\">\n                <img src=\"https://img.shields.io/pypi/status/gym-ignition.svg\" />\n                </a>\n                <a href=\"https://pypi.org/project/gym-ignition/\">\n                <img src=\"https://img.shields.io/pypi/format/gym-ignition.svg\" />\n                </a>\n                <a href=\"https://pypi.org/project/gym-ignition/\">\n                <img src=\"https://img.shields.io/pypi/l/gym-ignition.svg\" />\n                </a>\n            </td>\n        </tr>\n    </tbody>\n</table>\n</div>\n\n> ⚠️ **Warning** ⚠️\n>\n> This project is no longer actively maintained, and development has stalled.\n> For an in-depth description of the current status and actionable steps to revive development, please consult [robotology/gym-ignition#430]([url](https://github.com/robotology/gym-ignition/issues/430)).\n\n||||\n|:---:|:---:|:---:|\n| ![][pendulum] | ![][panda] | ![][icub] |\n\n[icub]: https://user-images.githubusercontent.com/469199/99262746-9e021a80-281e-11eb-9df1-d70134b0801a.png\n[panda]: https://user-images.githubusercontent.com/469199/99263111-0cdf7380-281f-11eb-9cfe-338b2aae0503.png\n[pendulum]: https://user-images.githubusercontent.com/469199/99262383-321fb200-281e-11eb-89cc-cc31f590daa3.png\n\n## Description\n\n**gym-ignition** is a framework to create **reproducible robotics environments** for reinforcement learning research.\n\nIt is based on the [ScenarIO](scenario/) project which provides the low-level APIs to interface with the Ignition Gazebo simulator.\nBy default, RL environments share a lot of boilerplate code, e.g. for initializing the simulator or structuring the classes\nto expose the `gym.Env` interface.\nGym-ignition provides the [`Task`](python/gym_ignition/base/task.py) and [`Runtime`](python/gym_ignition/base/runtime.py)\nabstractions that help you focusing on the development of the decision-making logic rather than engineering.\nIt includes [randomizers](python/gym_ignition/randomizers) to simplify the implementation of domain randomization\nof models, physics, and tasks.\nGym-ignition also provides powerful dynamics algorithms compatible with both fixed-base and floating-based robots by\nexploiting [robotology/idyntree](https://github.com/robotology/idyntree/) and exposing\n[high-level functionalities](python/gym_ignition/rbd/idyntree).\n\nGym-ignition does not provide out-of-the-box environments ready to be used.\nRather, its aim is simplifying and streamlining their development.\nNonetheless, for illustrative purpose, it includes canonical examples in the\n[`gym_ignition_environments`](python/gym_ignition_environments) package.\n\nVisit the [website][website] for more information about the project.\n\n[website]: https://robotology.github.io/gym-ignition\n\n## Installation\n\n1. First, follow the installation instructions of [ScenarIO](scenario/).\n2. `pip install gym-ignition`, preferably in a [virtual environment](https://docs.python.org/3.8/tutorial/venv.html).\n\n## Contributing\n\nYou can visit our community forum hosted in [GitHub Discussions](https://github.com/robotology/gym-ignition/discussions).\nEven without coding skills, replying user's questions is a great way of contributing.\nIf you use gym-ignition in your application and want to show it off, visit the\n[Show and tell](https://github.com/robotology/gym-ignition/discussions/categories/show-and-tell) section!\nYou can advertise there your environments created with gym-ignition.\n\nPull requests are welcome.\n\nFor major changes, please open a [discussion](https://github.com/robotology/gym-ignition/discussions)\nfirst to propose what you would like to change.\n\n## Citation\n\n```bibtex\n@INPROCEEDINGS{ferigo2020gymignition,\n    title={Gym-Ignition: Reproducible Robotic Simulations for Reinforcement Learning},\n    author={D. {Ferigo} and S. {Traversaro} and G. {Metta} and D. {Pucci}},\n    booktitle={2020 IEEE/SICE International Symposium on System Integration (SII)},\n    year={2020},\n    pages={885-890},\n    doi={10.1109/SII46433.2020.9025951}\n} \n```\n\n## License\n\n[LGPL v2.1](https://choosealicense.com/licenses/lgpl-2.1/) or any later version.\n\n---\n\n**Disclaimer:** Gym-ignition is an independent project and is not related by any means to OpenAI and Open Robotics.\n"
  },
  {
    "path": "docs/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# This variable is filled from the doxygen/ folder.\n# Defined here empty to remember that it exists in this scope.\nset(DOXYGEN_OUTPUT_DIRECTORY \"\")\n\nadd_subdirectory(doxygen)\nadd_subdirectory(sphinx)\n"
  },
  {
    "path": "docs/doxygen/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfind_package(Doxygen REQUIRED)\n\nset(DOXYGEN_GENERATE_XML YES)\nset(DOXYGEN_GENERATE_HTML NO)\nset(DOXYGEN_GENERATE_LATEX YES)\nset(DOXYGEN_FILE_PATTERNS \"*.h\")\nset(DOXYGEN_BUILTIN_STL_SUPPORT YES)\nset(DOXYGEN_EXCLUDE_PATTERNS\n    */components/* */plugins/* */details/* */private/*\n    */examples/* */tests/* */gympp/*)\n\ndoxygen_add_docs(\n    doxygen\n    ${PROJECT_SOURCE_DIR}\n    COMMENT \"Generate man pages\"\n)\n\n# This is required by Sphinx to find Doxygen XMLs\nset(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)\n"
  },
  {
    "path": "docs/sphinx/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Useful folders:\n#\n# 1. The folder containing the Python packages\n# 2. The folder containing the bindings Python modules\n#\nset(PYTHON_PACKAGES_DIR \"${CMAKE_SOURCE_DIR}/python\")\nset(BINDINGS_MODULES_DIR \"${PROJECT_BINARY_DIR}/scenario/bindings\")\n\n# =============\n# APIDOC TARGET\n# =============\n\n# This target generates the apidoc files of the Python modules and stores\n# them in the docs/sphinx/ source folder.\n# In order to make the multiversion website work, they need to be committed\n# when they change.\n#\n# The files in the following folders are replaced:\n#\n# - docs/sphinx/scenario\n# - docs/sphinx/gym_ignition\n# - docs/sphinx/gym_ignition_environments\n\nif (NOT TARGET ScenarioSwig::Core)\n    message(FATAL_ERROR \"Target ScenarioSwig::Core not found\")\nendif()\n\nif (NOT TARGET ScenarioSwig::Gazebo)\n    message(FATAL_ERROR \"Target ScenarioSwig::Gazebo not found\")\nendif()\n\nfind_package(SphinxApidoc REQUIRED)\nadd_custom_target(apidoc ALL DEPENDS\n    doxygen ScenarioSwig::Core ScenarioSwig::Gazebo)\n\nadd_custom_command(\n    TARGET apidoc POST_BUILD\n    COMMAND\n    ${SPHINX_APIDOC_EXECUTABLE} --force\n    --no-toc --module-first --maxdepth 4\n    -t ${CMAKE_CURRENT_SOURCE_DIR}/_templates\n    -o ${CMAKE_CURRENT_SOURCE_DIR}/apidoc/gym-ignition\n    ${PYTHON_PACKAGES_DIR}/gym_ignition\n    COMMENT \"Building <gym-ignition> apidoc\")\n\nadd_custom_command(\n    TARGET apidoc POST_BUILD\n    COMMAND\n    ${SPHINX_APIDOC_EXECUTABLE} --force\n    --no-toc --module-first --maxdepth 4\n    -t ${CMAKE_CURRENT_SOURCE_DIR}/_templates\n    -o ${CMAKE_CURRENT_SOURCE_DIR}/apidoc/gym-ignition-environments\n    ${PYTHON_PACKAGES_DIR}/gym_ignition_environments\n    COMMENT \"Building <gym-ignition-environments> apidoc\")\n\nadd_custom_command(\n    TARGET apidoc POST_BUILD\n    COMMAND\n    ${SPHINX_APIDOC_EXECUTABLE} --force\n    --no-toc --module-first --maxdepth 4\n    -t ${CMAKE_CURRENT_SOURCE_DIR}/_templates\n    -o ${CMAKE_CURRENT_SOURCE_DIR}/apidoc/scenario\n    ${BINDINGS_MODULES_DIR}\n    COMMENT \"Building <scenario> apidoc\")\n\n# =============\n# SPHINX TARGET\n# =============\n\nfind_package(Sphinx REQUIRED)\nfind_package(SphinxMultiVersion REQUIRED)\n\nif(${DOXYGEN_OUTPUT_DIRECTORY} STREQUAL \"\")\n    message(FATAL_ERROR \"Doxygen was not configured properly\")\nendif()\n\nset(SPHINX_BUILD ${CMAKE_BINARY_DIR}/html)\nset(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})\n\n# Extend the Python path including before generating the website\nset(SPHINX_CMD export PYTHONPATH=\"${PYTHON_PACKAGES_DIR}:${BINDINGS_MODULES_DIR}:$ENV{PYTHONPATH}\" &&)\n\n# Sphinx build command\nlist(APPEND SPHINX_CMD\n    ${SPHINX_MULTIVERSION_EXECUTABLE}\n    ${SPHINX_SOURCE} ${SPHINX_BUILD}\n    -D breathe_projects.scenario=\"${DOXYGEN_OUTPUT_DIRECTORY}/xml\")\n\n# Generate the website\nadd_custom_target(sphinx ALL\n    DEPENDS apidoc\n    COMMAND ${SPHINX_CMD}\n    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n    COMMENT \"Generating documentation with Sphinx\")\n\n# Disable GitHub pages autogeneration\nadd_custom_command(\n    TARGET sphinx POST_BUILD\n    COMMAND ${CMAKE_COMMAND} -E touch \"${SPHINX_BUILD}/.nojekyll\"\n    COMMENT \"Disabling Jekyll in html folder\")\n\n# Handle redirect\nadd_custom_command(\n    TARGET sphinx POST_BUILD\n    COMMAND ${CMAKE_COMMAND} -E copy \"${CMAKE_CURRENT_SOURCE_DIR}/index.html\" \"${SPHINX_BUILD}\"\n    COMMENT \"Copying html redirect to html folder\")\n"
  },
  {
    "path": "docs/sphinx/_templates/module.rst_t",
    "content": "{%- if show_headings %}\n{{- [basename, \"module\"] | join(' ') | e | heading }}\n\n{% endif -%}\n.. automodule:: {{ qualname }}\n{%- for option in automodule_options %}\n   :{{ option }}:\n{%- endfor %}\n"
  },
  {
    "path": "docs/sphinx/_templates/package.rst_t",
    "content": "{%- macro automodule(modname, options) -%}\n.. automodule:: {{ modname }}\n{%- for option in options %}\n   :{{ option }}:\n{%- endfor %}\n{%- endmacro %}\n\n{%- macro toctree(docnames) -%}\n.. toctree::\n   :maxdepth: {{ maxdepth }}\n{% for docname in docnames %}\n   {{ docname }}\n{%- endfor %}\n{%- endmacro %}\n\n{%- if is_namespace %}\n{{- [pkgname, \"namespace\"] | join(\" \") | e | heading }}\n{% else %}\n{{- pkgname | e | heading }}\n{% endif %}\n\n{%- if modulefirst and not is_namespace %}\n{{ automodule(pkgname, automodule_options) }}\n{% endif %}\n\n{%- if subpackages %}\n\n{{ toctree(subpackages) }}\n{% endif %}\n\n{%- if submodules %}\n{% if separatemodules %}\n{{ toctree(submodules) }}\n{% else %}\n{%- for submodule in submodules %}\n{% if show_headings %}\n{{- submodule | e | heading(2) }}\n{% endif %}\n{{ automodule(submodule, automodule_options) }}\n{% endfor %}\n{%- endif %}\n{%- endif %}\n\n{%- if not modulefirst and not is_namespace %}\nModule contents\n---------------\n\n{{ automodule(pkgname, automodule_options) }}\n{% endif %}\n"
  },
  {
    "path": "docs/sphinx/_templates/toc.rst_t",
    "content": "{{ header | heading }}\n\n.. toctree::\n   :maxdepth: {{ maxdepth }}\n{% for docname in docnames %}\n   {{ docname }}\n{%- endfor %}\n"
  },
  {
    "path": "docs/sphinx/_templates/versioning.html",
    "content": "{% if versions %}\n<nav id=\"bd-docs-nav\" class=\"bd-links\" aria-label=\"Versions navigation\">\n  <div class=\"bd-toc-item active\">\n    <p class=\"caption\">\n      <span class=\"caption-text\">{{ _('Doc Versions') }}</span>\n    </p>\n    <ul class=\"nav bd-sidenav\">\n      {%- for item in versions %}\n      <li class=\"toctree-l1\"><a class=\"reference internal\" href=\"{{ item.url }}\">{{ item.name }}</a></li>\n      {%- endfor %}\n    </ul>\n  </div>\n</nav>\n{% endif %}\n"
  },
  {
    "path": "docs/sphinx/_templates/versions.html",
    "content": "{%- if current_version %}\n<div class=\"rst-versions\" data-toggle=\"rst-versions\" role=\"note\" aria-label=\"versions\">\n  <span class=\"rst-current-version\" data-toggle=\"rst-current-version\">\n    <span class=\"fa fa-book\"> Other Versions</span>\n    v: {{ current_version.name }}\n    <span class=\"fa fa-caret-down\"></span>\n  </span>\n  <div class=\"rst-other-versions\">\n    {%- if versions.tags %}\n    <dl>\n      <dt>Tags</dt>\n      {%- for item in versions.tags %}\n      <dd><a href=\"{{ item.url }}\">{{ item.name }}</a></dd>\n      {%- endfor %}\n    </dl>\n    {%- endif %}\n    {%- if versions.branches %}\n    <dl>\n      <dt>Branches</dt>\n      {%- for item in versions.branches %}\n      <dd><a href=\"{{ item.url }}\">{{ item.name }}</a></dd>\n      {%- endfor %}\n    </dl>\n    {%- endif %}\n  </div>\n</div>\n{%- endif %}"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.base.rst",
    "content": "gym\\_ignition.base\n==================\n\n.. automodule:: gym_ignition.base\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.base.runtime\n--------------------------\n\n.. automodule:: gym_ignition.base.runtime\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.base.task\n-----------------------\n\n.. automodule:: gym_ignition.base.task\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.context.gazebo.rst",
    "content": "gym\\_ignition.context.gazebo\n============================\n\n.. automodule:: gym_ignition.context.gazebo\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.context.gazebo.controllers\n----------------------------------------\n\n.. automodule:: gym_ignition.context.gazebo.controllers\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.context.gazebo.plugin\n-----------------------------------\n\n.. automodule:: gym_ignition.context.gazebo.plugin\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.context.rst",
    "content": "gym\\_ignition.context\n=====================\n\n.. automodule:: gym_ignition.context\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   gym_ignition.context.gazebo\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.randomizers.model.rst",
    "content": "gym\\_ignition.randomizers.model\n===============================\n\n.. automodule:: gym_ignition.randomizers.model\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.randomizers.model.sdf\n-----------------------------------\n\n.. automodule:: gym_ignition.randomizers.model.sdf\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.randomizers.physics.rst",
    "content": "gym\\_ignition.randomizers.physics\n=================================\n\n.. automodule:: gym_ignition.randomizers.physics\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.randomizers.physics.dart\n--------------------------------------\n\n.. automodule:: gym_ignition.randomizers.physics.dart\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.randomizers.rst",
    "content": "gym\\_ignition.randomizers\n=========================\n\n.. automodule:: gym_ignition.randomizers\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   gym_ignition.randomizers.model\n   gym_ignition.randomizers.physics\n\n\ngym\\_ignition.randomizers.abc\n-----------------------------\n\n.. automodule:: gym_ignition.randomizers.abc\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.randomizers.gazebo\\_env\\_randomizer\n-------------------------------------------------\n\n.. automodule:: gym_ignition.randomizers.gazebo_env_randomizer\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.rbd.idyntree.rst",
    "content": "gym\\_ignition.rbd.idyntree\n==========================\n\n.. automodule:: gym_ignition.rbd.idyntree\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.rbd.idyntree.helpers\n----------------------------------\n\n.. automodule:: gym_ignition.rbd.idyntree.helpers\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.rbd.idyntree.inverse\\_kinematics\\_nlp\n---------------------------------------------------\n\n.. automodule:: gym_ignition.rbd.idyntree.inverse_kinematics_nlp\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.rbd.idyntree.kindyncomputations\n---------------------------------------------\n\n.. automodule:: gym_ignition.rbd.idyntree.kindyncomputations\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.rbd.idyntree.numpy\n--------------------------------\n\n.. automodule:: gym_ignition.rbd.idyntree.numpy\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.rbd.rst",
    "content": "gym\\_ignition.rbd\n=================\n\n.. automodule:: gym_ignition.rbd\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   gym_ignition.rbd.idyntree\n\n\ngym\\_ignition.rbd.conversions\n-----------------------------\n\n.. automodule:: gym_ignition.rbd.conversions\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.rbd.utils\n-----------------------\n\n.. automodule:: gym_ignition.rbd.utils\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.rst",
    "content": "gym\\_ignition\n=============\n\n.. automodule:: gym_ignition\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   gym_ignition.base\n   gym_ignition.context\n   gym_ignition.randomizers\n   gym_ignition.rbd\n   gym_ignition.runtimes\n   gym_ignition.scenario\n   gym_ignition.utils\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.runtimes.rst",
    "content": "gym\\_ignition.runtimes\n======================\n\n.. automodule:: gym_ignition.runtimes\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.runtimes.gazebo\\_runtime\n--------------------------------------\n\n.. automodule:: gym_ignition.runtimes.gazebo_runtime\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.runtimes.realtime\\_runtime\n----------------------------------------\n\n.. automodule:: gym_ignition.runtimes.realtime_runtime\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.scenario.rst",
    "content": "gym\\_ignition.scenario\n======================\n\n.. automodule:: gym_ignition.scenario\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.scenario.model\\_with\\_file\n----------------------------------------\n\n.. automodule:: gym_ignition.scenario.model_with_file\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.scenario.model\\_wrapper\n-------------------------------------\n\n.. automodule:: gym_ignition.scenario.model_wrapper\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition/gym_ignition.utils.rst",
    "content": "gym\\_ignition.utils\n===================\n\n.. automodule:: gym_ignition.utils\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition.utils.logger\n--------------------------\n\n.. automodule:: gym_ignition.utils.logger\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.utils.math\n------------------------\n\n.. automodule:: gym_ignition.utils.math\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.utils.misc\n------------------------\n\n.. automodule:: gym_ignition.utils.misc\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.utils.resource\\_finder\n------------------------------------\n\n.. automodule:: gym_ignition.utils.resource_finder\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.utils.scenario\n----------------------------\n\n.. automodule:: gym_ignition.utils.scenario\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition.utils.typing\n--------------------------\n\n.. automodule:: gym_ignition.utils.typing\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition-environments/gym_ignition_environments.models.rst",
    "content": "gym\\_ignition\\_environments.models\n==================================\n\n.. automodule:: gym_ignition_environments.models\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition\\_environments.models.cartpole\n-------------------------------------------\n\n.. automodule:: gym_ignition_environments.models.cartpole\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.models.icub\n---------------------------------------\n\n.. automodule:: gym_ignition_environments.models.icub\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.models.panda\n----------------------------------------\n\n.. automodule:: gym_ignition_environments.models.panda\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.models.pendulum\n-------------------------------------------\n\n.. automodule:: gym_ignition_environments.models.pendulum\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition-environments/gym_ignition_environments.randomizers.rst",
    "content": "gym\\_ignition\\_environments.randomizers\n=======================================\n\n.. automodule:: gym_ignition_environments.randomizers\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition\\_environments.randomizers.cartpole\n------------------------------------------------\n\n.. automodule:: gym_ignition_environments.randomizers.cartpole\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.randomizers.cartpole\\_no\\_rand\n----------------------------------------------------------\n\n.. automodule:: gym_ignition_environments.randomizers.cartpole_no_rand\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition-environments/gym_ignition_environments.rst",
    "content": "gym\\_ignition\\_environments\n===========================\n\n.. automodule:: gym_ignition_environments\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   gym_ignition_environments.models\n   gym_ignition_environments.randomizers\n   gym_ignition_environments.tasks\n"
  },
  {
    "path": "docs/sphinx/apidoc/gym-ignition-environments/gym_ignition_environments.tasks.rst",
    "content": "gym\\_ignition\\_environments.tasks\n=================================\n\n.. automodule:: gym_ignition_environments.tasks\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\ngym\\_ignition\\_environments.tasks.cartpole\\_continuous\\_balancing\n-----------------------------------------------------------------\n\n.. automodule:: gym_ignition_environments.tasks.cartpole_continuous_balancing\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.tasks.cartpole\\_continuous\\_swingup\n---------------------------------------------------------------\n\n.. automodule:: gym_ignition_environments.tasks.cartpole_continuous_swingup\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.tasks.cartpole\\_discrete\\_balancing\n---------------------------------------------------------------\n\n.. automodule:: gym_ignition_environments.tasks.cartpole_discrete_balancing\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\ngym\\_ignition\\_environments.tasks.pendulum\\_swingup\n---------------------------------------------------\n\n.. automodule:: gym_ignition_environments.tasks.pendulum_swingup\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/scenario/scenario.bindings.rst",
    "content": "scenario.bindings\n=================\n\n.. automodule:: scenario.bindings\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\nscenario.bindings.core\n----------------------\n\n.. automodule:: scenario.bindings.core\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\nscenario.bindings.gazebo\n------------------------\n\n.. automodule:: scenario.bindings.gazebo\n   :members:\n   :undoc-members:\n   :show-inheritance:\n"
  },
  {
    "path": "docs/sphinx/apidoc/scenario/scenario.rst",
    "content": "scenario\n========\n\n.. automodule:: scenario\n   :members:\n   :undoc-members:\n   :show-inheritance:\n\n\n.. toctree::\n   :maxdepth: 4\n\n   scenario.bindings\n"
  },
  {
    "path": "docs/sphinx/breathe/core.rst",
    "content": ".. _scenario_core:\n\nCore\n====\n\n.. doxygennamespace:: scenario::core\n   :project: scenario\n   :members:\n"
  },
  {
    "path": "docs/sphinx/breathe/gazebo.rst",
    "content": ".. _scenario_gazebo:\n\nGazebo\n======\n\n.. doxygennamespace:: scenario::gazebo\n   :project: scenario\n   :members:\n"
  },
  {
    "path": "docs/sphinx/conf.py",
    "content": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common options. For a full\n# list see the documentation:\n# https://www.sphinx-doc.org/en/master/usage/configuration.html\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n# import os\n# import sys\n# sys.path.insert(0, os.path.abspath('.'))\n\n# -- Project information -----------------------------------------------------\nfrom datetime import datetime\n\nproject = \"gym-ignition\"\ncopyright = f\"{datetime.now().year}, Istituto Italiano di Tecnologia\"\nauthor = \"Diego Ferigo\"\n\n# -- General configuration ---------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.todo\",\n    \"sphinx.ext.mathjax\",\n    \"sphinx.ext.githubpages\",\n    \"sphinx.ext.napoleon\",\n    \"sphinx.ext.extlinks\",\n    \"sphinx_autodoc_typehints\",\n    \"sphinx_multiversion\",\n    \"sphinx_fontawesome\",\n    \"breathe\",\n    \"sphinx_tabs.tabs\",\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = \"en\"\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = [\"_build\", \"Thumbs.db\", \".DS_Store\"]\n\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = \"sphinx_book_theme\"\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\nhtml_theme_options = {\n    \"repository_url\": \"https://github.com/robotology/gym-ignition\",\n    \"use_repository_button\": True,\n    \"use_issues_button\": True,\n    \"use_edit_page_button\": True,\n    \"path_to_docs\": \"docs/sphinx\",\n    \"home_page_in_toc\": True,\n    \"use_download_button\": False,\n    \"use_fullscreen_button\": True,\n    \"single_page\": False,\n}\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\n# html_static_path = ['_static']\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"pastie\"\n\n\n# -- Extension configuration -------------------------------------------------\n\n# -- Options for todo extension ----------------------------------------------\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = True\n\n# -- Options for breathe extension ----------------------------------------------\n\nbreathe_default_project = \"scenario\"\n\n# -- Options for sphinx_multiversion extension ----------------------------------\n\n# From: https://holzhaus.github.io/sphinx-multiversion\nsmv_prefer_remote_refs = False\nsmv_remote_whitelist = r\"^(origin|upstream)$\"\nsmv_tag_whitelist = r\"^dummy\"\nsmv_branch_whitelist = r\"^(master|devel|docs/.*)$\"\nsmv_released_pattern = r\"^tags/.*$\"\nsmv_outputdir_format = \"{ref.name}\"\n\nhtml_sidebars = {\n    \"**\": [\n        \"sbt-sidebar-nav.html\",\n        \"versioning.html\",\n        \"search-field.html\",\n        \"sbt-sidebar-footer.html\",\n    ]\n}\n\n# -- Options for extlinks extension ----------------------------------\nextlinks = {\n    \"issue\": (\"https://github.com/robotology/gym-ignition/issues/%s\", \"#\"),\n    \"pr\": (\"https://github.com/robotology/gym-ignition/pull/%s\", \"#\"),\n}\n"
  },
  {
    "path": "docs/sphinx/getting_started/gym-ignition.rst",
    "content": ".. _getting_started_gym_ignition:\n\ngym-ignition\n************\n\nThe previous sections reported the usage of ScenarIO to perform rigid-body simulations of any kind.\nThe :py:mod:`gym_ignition` Python package provides boilerplate code that use ScenarIO to create environments\nfor reinforcement learning research compatible with OpenAI Gym.\n\nBeyond the abstractions provided by ScenarIO, gym-ignition introduces the following:\n\n- :py:class:`~gym_ignition.base.runtime.Runtime`: Base class to abstract the runtime of an environment.\n  It provides the code that steps the simulator for simulated environments or deals with real-time execution for\n  environments running on real robots.\n  The implementation for Ignition Gazebo is :py:class:`~gym_ignition.runtimes.gazebo_runtime.GazeboRuntime`.\n\n- :py:class:`~gym_ignition.base.task.Task`: Base class providing the structure of the decision-making logic.\n  The code of the task must be independent from the runtime, and only the ScenarIO APIs should be used.\n  The active runtime will then execute the task on either simulated or real worlds.\n\n- :py:mod:`gym_ignition.randomizers`: Utilities to develop ``gym.Wrapper`` classes that randomize the environment\n  every rollout.\n  The implementation for Ignition Gazebo is :py:class:`~gym_ignition.randomizers.gazebo_env_randomizer.GazeboEnvRandomizer`.\n\n- :py:mod:`gym_ignition.rbd`: Utilities commonly used in robotic environments, like inverse kinematics and rigid-body\n  dynamics algorithms.\n  Refer to :py:class:`~gym_ignition.rbd.idyntree.inverse_kinematics_nlp.InverseKinematicsNLP` and\n  :py:class:`~gym_ignition.rbd.idyntree.kindyncomputations.KinDynComputations` for more details.\n\n.. tip::\n\n    If you want to learn more about ``iDynTree``, the two classes we mainly use are ``iDynTree::KinDynComputations`` (`docs <https://robotology.github.io/idyntree/master/classiDynTree_1_1KinDynComputations.html>`__) and ``iDynTree::InverseKinematics`` (`docs <https://robotology.github.io/idyntree/master/classiDynTree_1_1InverseKinematics.html>`__).\n\n    The theory and notation is summarized in `Multibody dynamics notation <https://pure.tue.nl/ws/portalfiles/portal/139293126/A_Multibody_Dynamics_Notation_Revision_2_.pdf>`_.\n\nYou can find demo environments created with ``gym-ignition`` in the\n`gym_ignition_environments <https://github.com/robotology/gym-ignition/blob/master/python/gym_ignition_environments>`_ folder.\nThese examples show how to structure a new standalone Python package containing the environment with your robots.\n\nFor example, taking the cartpole balancing problem with discrete actions,\nthe components you need to implement are the following:\n\n- A model :py:class:`~gym_ignition_environments.models.cartpole.CartPole`\n  (`model/cartpole.py <https://github.com/robotology/gym-ignition/blob/master/python/gym_ignition_environments/models/cartpole.py>`_)\n\n- A task :py:class:`~gym_ignition_environments.tasks.cartpole_discrete_balancing.CartPoleDiscreteBalancing`\n  (`cartpole_discrete_balancing.py <https://github.com/robotology/gym-ignition/blob/master/python/gym_ignition_environments/tasks/cartpole_discrete_balancing.py>`_)\n\n- A randomizer :py:class:`~gym_ignition_environments.randomizers.cartpole.CartpoleEnvRandomizer`\n  (`randomizers/cartpole.py <https://github.com/robotology/gym-ignition/blob/master/python/gym_ignition_environments/randomizers/cartpole.py>`_)\n\n- Environment registration as done in `__init__.py <https://github.com/robotology/gym-ignition/blob/master/python/gym_ignition_environments/__init__.py>`_\n\nWith all these resources in place, you can run a random policy of the environment as shown in\n`launch_cartpole.py <https://github.com/robotology/gym-ignition/blob/master/examples/python/launch_cartpole.py>`_.\n"
  },
  {
    "path": "docs/sphinx/getting_started/manipulation.rst",
    "content": ".. _getting_started_manipulation:\n\nManipulation example\n********************\n\nThis example provides a wider overview of the functionalities currently implemented in gym-ignition.\n\nThe code reported below is taken from the example\n`panda_pick_and_place.py <https://github.com/robotology/gym-ignition/blob/master/examples/panda_pick_and_place.py>`_.\nIt shows the following functionalities:\n\n- Download models from `Ignition Fuel <https://app.ignitionrobotics.org/dashboard>`_.\n- Insert and remove models during runtime.\n- Exploit the high-level :py:class:`~gym_ignition_environments.models.panda.Panda` helper class to insert the manipulator.\n- Enable custom C++ controllers (:cpp:class:`scenario::controllers::ComputedTorqueFixedBase`).\n- Detect contacts and read contact wrenches.\n- Exploit :py:class:`~gym_ignition.rbd.idyntree.inverse_kinematics_nlp.InverseKinematicsNLP`.\n\n.. figure:: https://user-images.githubusercontent.com/469199/99905096-f29a0f80-2cce-11eb-9f1c-002f6c887bc6.png\n   :align: center\n\n.. tip::\n\n   This example can be the starting point to develop manipulation environments for robot learning.\n   Visit the :ref:`getting_started_gym_ignition` page for more information about how to wrap this code in the resources provided by ``gym_ignition``.\n\n.. note::\n\n   This is an illustrative example. A compliant joint controller is used to move the manipulator, it does not perform any\n   trajectory planning and it does not avoid self collisions, which are not enabled in the simulation by default.\n   There are cube positions where the joint configuration changes a lot from the previous, generating an abrupt movement\n   of the manipulator. When these situations occur, grasping might fail.\n\n.. code-block:: python\n\n    import enum\n    import time\n    from functools import partial\n    from typing import List\n\n    import gym_ignition\n    import gym_ignition_environments\n    import numpy as np\n    from gym_ignition.context.gazebo import controllers\n    from gym_ignition.rbd import conversions\n    from gym_ignition.rbd.idyntree import inverse_kinematics_nlp\n    from scipy.spatial.transform import Rotation as R\n\n    from scenario import core as scenario_core\n    from scenario import gazebo as scenario_gazebo\n\n    # Configure verbosity\n    scenario_gazebo.set_verbosity(scenario_gazebo.Verbosity_error)\n\n    # Configure numpy output\n    np.set_printoptions(precision=4, suppress=True)\n\n\n    def add_panda_controller(\n        panda: gym_ignition_environments.models.panda.Panda, controller_period: float\n    ) -> None:\n\n        # Set the controller period\n        assert panda.set_controller_period(period=controller_period)\n\n        # Increase the max effort of the fingers\n        panda.get_joint(\n            joint_name=\"panda_finger_joint1\"\n        ).to_gazebo().set_max_generalized_force(max_force=500.0)\n        panda.get_joint(\n            joint_name=\"panda_finger_joint2\"\n        ).to_gazebo().set_max_generalized_force(max_force=500.0)\n\n        # Insert the ComputedTorqueFixedBase controller\n        assert panda.to_gazebo().insert_model_plugin(\n            *controllers.ComputedTorqueFixedBase(\n                kp=[100.0] * (panda.dofs() - 2) + [10000.0] * 2,\n                ki=[0.0] * panda.dofs(),\n                kd=[17.5] * (panda.dofs() - 2) + [100.0] * 2,\n                urdf=panda.get_model_file(),\n                joints=panda.joint_names(),\n            ).args()\n        )\n\n        # Initialize the controller to the current state\n        assert panda.set_joint_position_targets(panda.joint_positions())\n        assert panda.set_joint_velocity_targets(panda.joint_velocities())\n        assert panda.set_joint_acceleration_targets(panda.joint_accelerations())\n\n\n    def get_panda_ik(\n        panda: gym_ignition_environments.models.panda.Panda, optimized_joints: List[str]\n    ) -> inverse_kinematics_nlp.InverseKinematicsNLP:\n\n        # Create IK\n        ik = inverse_kinematics_nlp.InverseKinematicsNLP(\n            urdf_filename=panda.get_model_file(),\n            considered_joints=optimized_joints,\n            joint_serialization=panda.joint_names(),\n        )\n\n        # Initialize IK\n        ik.initialize(\n            verbosity=1,\n            floating_base=False,\n            cost_tolerance=1e-8,\n            constraints_tolerance=1e-8,\n            base_frame=panda.base_frame(),\n        )\n\n        # Set the current configuration\n        ik.set_current_robot_configuration(\n            base_position=np.array(panda.base_position()),\n            base_quaternion=np.array(panda.base_orientation()),\n            joint_configuration=np.array(panda.joint_positions()),\n        )\n\n        # Add the cartesian target of the end effector\n        end_effector = \"end_effector_frame\"\n        ik.add_target(\n            frame_name=end_effector,\n            target_type=inverse_kinematics_nlp.TargetType.POSE,\n            as_constraint=False,\n        )\n\n        return ik\n\n\n    def insert_bucket(world: scenario_gazebo.World) -> scenario_gazebo.Model:\n\n        # Insert objects from Fuel\n        uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n        # Download the cube SDF file\n        bucket_sdf = scenario_gazebo.get_model_file_from_fuel(\n            uri=uri(\n                org=\"GoogleResearch\",\n                name=\"Threshold_Basket_Natural_Finish_Fabric_Liner_Small\",\n            ),\n            use_cache=False,\n        )\n\n        # Assign a custom name to the model\n        model_name = \"bucket\"\n\n        # Insert the model\n        assert world.insert_model(\n            bucket_sdf, scenario_core.Pose([0.68, 0, 1.02], [1.0, 0, 0, 1]), model_name\n        )\n\n        # Return the model\n        return world.get_model(model_name=model_name)\n\n\n    def insert_table(world: scenario_gazebo.World) -> scenario_gazebo.Model:\n\n        # Insert objects from Fuel\n        uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n        # Download the cube SDF file\n        bucket_sdf = scenario_gazebo.get_model_file_from_fuel(\n            uri=uri(org=\"OpenRobotics\", name=\"Table\"), use_cache=False\n        )\n\n        # Assign a custom name to the model\n        model_name = \"table\"\n\n        # Insert the model\n        assert world.insert_model(bucket_sdf, scenario_core.Pose_identity(), model_name)\n\n        # Return the model\n        return world.get_model(model_name=model_name)\n\n\n    def insert_cube_in_operating_area(\n        world: scenario_gazebo.World,\n    ) -> scenario_gazebo.Model:\n\n        # Insert objects from Fuel\n        uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n        # Download the cube SDF file\n        cube_sdf = scenario_gazebo.get_model_file_from_fuel(\n            uri=uri(org=\"openrobotics\", name=\"wood cube 5cm\"), use_cache=False\n        )\n\n        # Sample a random position\n        random_position = np.random.uniform(low=[0.2, -0.3, 1.01], high=[0.4, 0.3, 1.01])\n\n        # Get a unique name\n        model_name = gym_ignition.utils.scenario.get_unique_model_name(\n            world=world, model_name=\"cube\"\n        )\n\n        # Insert the model\n        assert world.insert_model(\n            cube_sdf, scenario_core.Pose(random_position, [1.0, 0, 0, 0]), model_name\n        )\n\n        # Return the model\n        return world.get_model(model_name=model_name)\n\n\n    def solve_ik(\n        target_position: np.ndarray,\n        target_orientation: np.ndarray,\n        ik: inverse_kinematics_nlp.InverseKinematicsNLP,\n    ) -> np.ndarray:\n\n        quat_xyzw = R.from_euler(seq=\"y\", angles=90, degrees=True).as_quat()\n\n        ik.update_transform_target(\n            target_name=ik.get_active_target_names()[0],\n            position=target_position,\n            quaternion=conversions.Quaternion.to_wxyz(xyzw=quat_xyzw),\n        )\n\n        # Run the IK\n        ik.solve()\n\n        return ik.get_reduced_solution().joint_configuration\n\n\n    def end_effector_reached(\n        position: np.array,\n        end_effector_link: scenario_core.Link,\n        max_error_pos: float = 0.01,\n        max_error_vel: float = 0.5,\n        mask: np.ndarray = np.array([1.0, 1.0, 1.0]),\n    ) -> bool:\n\n        masked_target = mask * position\n        masked_current = mask * np.array(end_effector_link.position())\n\n        return (\n            np.linalg.norm(masked_current - masked_target) < max_error_pos\n            and np.linalg.norm(end_effector_link.world_linear_velocity()) < max_error_vel\n        )\n\n\n    def get_unload_position(bucket: scenario_core.Model) -> np.ndarray:\n\n        return bucket.base_position() + np.array([0, 0, 0.3])\n\n\n    class FingersAction(enum.Enum):\n\n        OPEN = enum.auto()\n        CLOSE = enum.auto()\n\n\n    def move_fingers(\n        panda: gym_ignition_environments.models.panda.Panda, action: FingersAction\n    ) -> None:\n\n        # Get the joints of the fingers\n        finger1 = panda.get_joint(joint_name=\"panda_finger_joint1\")\n        finger2 = panda.get_joint(joint_name=\"panda_finger_joint2\")\n\n        if action is FingersAction.OPEN:\n            finger1.set_position_target(position=finger1.position_limit().max)\n            finger2.set_position_target(position=finger2.position_limit().max)\n\n        if action is FingersAction.CLOSE:\n            finger1.set_position_target(position=finger1.position_limit().min)\n            finger2.set_position_target(position=finger2.position_limit().min)\n\n\n    # ====================\n    # INITIALIZE THE WORLD\n    # ====================\n\n    # Get the simulator and the world\n    gazebo, world = gym_ignition.utils.scenario.init_gazebo_sim(\n        step_size=0.001, real_time_factor=2.0, steps_per_run=1\n    )\n\n    # Open the GUI\n    gazebo.gui()\n    time.sleep(3)\n    gazebo.run(paused=True)\n\n    # Insert the Panda manipulator\n    panda = gym_ignition_environments.models.panda.Panda(\n        world=world, position=[-0.1, 0, 1.0]\n    )\n\n    # Disable joint velocity limits\n    _ = [j.to_gazebo().set_velocity_limit(1_000) for j in panda.joints()]\n\n    # Enable contacts only for the finger links\n    panda.get_link(\"panda_leftfinger\").to_gazebo().enable_contact_detection(True)\n    panda.get_link(\"panda_rightfinger\").to_gazebo().enable_contact_detection(True)\n\n    # Process model insertion in the simulation\n    gazebo.run(paused=True)\n\n    # Monkey patch the class with finger helpers\n    panda.open_fingers = partial(move_fingers, panda=panda, action=FingersAction.OPEN)\n    panda.close_fingers = partial(move_fingers, panda=panda, action=FingersAction.CLOSE)\n\n    # Add a custom joint controller to the panda\n    add_panda_controller(panda=panda, controller_period=gazebo.step_size())\n\n    # Populate the world\n    table = insert_table(world=world)\n    bucket = insert_bucket(world=world)\n    gazebo.run(paused=True)\n\n    # Create and configure IK for the panda\n    ik_joints = [\n        j.name() for j in panda.joints() if j.type is not scenario_core.JointType_fixed\n    ]\n    ik = get_panda_ik(panda=panda, optimized_joints=ik_joints)\n\n    # Get some manipulator links\n    finger_left = panda.get_link(link_name=\"panda_leftfinger\")\n    finger_right = panda.get_link(link_name=\"panda_rightfinger\")\n    end_effector_frame = panda.get_link(link_name=\"end_effector_frame\")\n\n    while True:\n\n        # Insert a new cube\n        cube = insert_cube_in_operating_area(world=world)\n        gazebo.run(paused=True)\n\n        # =========================\n        # PHASE 1: Go over the cube\n        # =========================\n\n        print(\"Hovering\")\n\n        # Position over the cube\n        position_over_cube = np.array(cube.base_position()) + np.array([0, 0, 0.4])\n\n        # Get the joint configuration that brings the EE over the cube\n        over_joint_configuration = solve_ik(\n            target_position=position_over_cube,\n            target_orientation=np.array(cube.base_orientation()),\n            ik=ik,\n        )\n\n        # Set the joint references\n        assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n\n        # Open the fingers\n        panda.open_fingers()\n\n        # Run the simulation until the EE reached the desired position\n        while not end_effector_reached(\n            position=position_over_cube,\n            end_effector_link=end_effector_frame,\n            max_error_pos=0.05,\n            max_error_vel=0.5,\n        ):\n            gazebo.run()\n\n        # Wait a bit more\n        [gazebo.run() for _ in range(500)]\n\n        # =======================\n        # PHASE 2: Reach the cube\n        # =======================\n\n        print(\"Reaching\")\n\n        # Get the joint configuration that brings the EE to the cube\n        over_joint_configuration = solve_ik(\n            target_position=np.array(cube.base_position()) + np.array([0, 0, 0.04]),\n            target_orientation=np.array(cube.base_orientation()),\n            ik=ik,\n        )\n\n        # Set the joint references\n        assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n        panda.open_fingers()\n\n        # Run the simulation until the EE reached the desired position\n        while not end_effector_reached(\n            position=np.array(cube.base_position()) + np.array([0, 0, 0.04]),\n            end_effector_link=end_effector_frame,\n        ):\n\n            gazebo.run()\n\n        # Wait a bit more\n        [gazebo.run() for _ in range(500)]\n\n        # =======================\n        # PHASE 3: Grasp the cube\n        # =======================\n\n        print(\"Grasping\")\n\n        # Close the fingers\n        panda.close_fingers()\n\n        # Detect a graps reading the contact wrenches of the finger links\n        while not (\n            np.linalg.norm(finger_left.contact_wrench()) >= 50.0\n            and np.linalg.norm(finger_right.contact_wrench()) >= 50.0\n        ):\n            gazebo.run()\n\n        # =============\n        # PHASE 4: Lift\n        # =============\n\n        print(\"Lifting\")\n\n        # Position over the cube\n        position_over_cube = np.array(cube.base_position()) + np.array([0, 0, 0.4])\n\n        # Get the joint configuration that brings the EE over the cube\n        over_joint_configuration = solve_ik(\n            target_position=position_over_cube,\n            target_orientation=np.array(cube.base_orientation()),\n            ik=ik,\n        )\n\n        # Set the joint references\n        assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n\n        # Run the simulation until the EE reached the desired position\n        while not end_effector_reached(\n            position=position_over_cube,\n            end_effector_link=end_effector_frame,\n            max_error_pos=0.1,\n            max_error_vel=0.5,\n        ):\n            gazebo.run()\n\n        # Wait a bit more\n        [gazebo.run() for _ in range(500)]\n\n        # =====================================\n        # PHASE 5: Place the cube in the bucket\n        # =====================================\n\n        print(\"Dropping\")\n\n        # Get the joint configuration that brings the EE over the bucket\n        unload_joint_configuration = solve_ik(\n            target_position=get_unload_position(bucket=bucket),\n            target_orientation=np.array([0, 1.0, 0, 0]),\n            ik=ik,\n        )\n\n        # Set the joint references\n        assert panda.set_joint_position_targets(unload_joint_configuration, ik_joints)\n\n        # Run the simulation until the EE reached the desired position\n        while not end_effector_reached(\n            position=get_unload_position(bucket=bucket)\n            + np.random.uniform(low=-0.05, high=0.05, size=3),\n            end_effector_link=end_effector_frame,\n            max_error_pos=0.01,\n            max_error_vel=0.1,\n            mask=np.array([1, 1, 0]),\n        ):\n\n            gazebo.run()\n\n        # Open the fingers\n        panda.open_fingers()\n\n        # Wait that both fingers are in not contact (with the cube)\n        while finger_left.in_contact() or finger_right.in_contact():\n            gazebo.run()\n\n        # Wait a bit more\n        [gazebo.run() for _ in range(500)]\n\n        # Remove the cube\n        world.remove_model(model_name=cube.name())\n\n    # It is always a good practice to close the simulator.\n    # In this case it is not required since above there is an infinite loop.\n    # gazebo.close()\n"
  },
  {
    "path": "docs/sphinx/getting_started/scenario.rst",
    "content": ".. _getting_started_scenario:\n\nScenarIO\n========\n\nIn this getting started section we show how to use the Gazebo ScenarIO library to simulate a pendulum system.\nWe will use the models of the ground plane and the pendulum stored in the repository\n`gym_ignition_models <https://github.com/robotology/gym-ignition-models>`_.\n\nThe final outcome of this section is shown in the following GIF:\n\n.. figure:: https://user-images.githubusercontent.com/469199/99263551-a9097a80-281f-11eb-98de-714c69385b06.png\n   :align: center\n\n.. tip::\n    We fully support `Ignition Fuel <https://app.ignitionrobotics.org/dashboard>`_, a constantly enlarging database of SDF models.\n    You can use :py:meth:`~scenario.bindings.gazebo.get_model_file_from_fuel` to download any model of the database:\n\n    .. code-block:: python\n\n      from scenario import gazebo as scenario_gazebo\n\n      model_name = \"Electrical Box\"\n\n      model_file = scenario_gazebo.get_model_file_from_fuel(\n          uri=f\"https://fuel.ignitionrobotics.org/openrobotics/models/{model_name}\")\n\n.. _getting_started_scenario_python:\n\nPython\n******\n\n.. tabs::\n  .. group-tab:: example.py\n\n    .. code-block:: python\n\n      import time\n      import gym_ignition_models\n      from scenario import gazebo as scenario_gazebo\n\n      # Create the simulator\n      gazebo = scenario_gazebo.GazeboSimulator(step_size=0.001,\n                                               rtf=1.0,\n                                               steps_per_run=1)\n\n      # Initialize the simulator\n      gazebo.initialize()\n\n      # Get the default world and insert the ground plane\n      world = gazebo.get_world()\n      world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n\n      # Select the physics engine\n      world.set_physics_engine(scenario_gazebo.PhysicsEngine_dart)\n\n      # Open the GUI\n      gazebo.gui()\n      time.sleep(3)\n      gazebo.run(paused=True)\n\n      # Insert a pendulum\n      world.insert_model(gym_ignition_models.get_model_file(\"pendulum\"))\n      gazebo.run(paused=True)\n      time.sleep(3)\n\n      # Get the pendulum model\n      pendulum = world.get_model(\"pendulum\")\n\n      # Reset the pole position\n      pendulum.get_joint(\"pivot\").to_gazebo().reset_position(0.01)\n      gazebo.run(paused=True)\n      time.sleep(3)\n\n      # Simulate 30 seconds\n      for _ in range(int(30.0 / gazebo.step_size())):\n          gazebo.run()\n\n      # Close the simulator\n      time.sleep(5)\n      gazebo.close()\n\n.. _getting_started_scenario_cpp:\n\nC++\n***\n\n.. tabs::\n  .. group-tab:: example.cpp\n\n    .. code-block:: cpp\n\n      #include <scenario/gazebo/GazeboSimulator.h>\n      #include <scenario/gazebo/Joint.h>\n      #include <scenario/gazebo/Model.h>\n      #include <scenario/gazebo/World.h>\n\n      #include <chrono>\n      #include <string>\n      #include <thread>\n\n      int main(int argc, char* argv[])\n      {\n          // Create the simulator\n          auto gazebo = scenario::gazebo::GazeboSimulator(\n              /*stepSize=*/0.001, /*rtf=*/1.0, /*stepsPerRun=*/1);\n\n          // Initialize the simulator\n          gazebo.initialize();\n\n          // Get the default world\n          auto world = gazebo.getWorld();\n\n          // Insert the ground plane\n          const std::string groundPlaneSDF = \"ground_plane.sdf\";\n          world->insertModel(groundPlaneSDF);\n\n          // Select the physics engine\n          world->setPhysicsEngine(scenario::gazebo::PhysicsEngine::Dart);\n\n          // Open the GUI\n          gazebo.gui();\n          std::this_thread::sleep_for(std::chrono::seconds(3));\n          gazebo.run(/*paused=*/true);\n\n          // Insert a pendulum\n          const std::string pendulumURDF = \"pendulum.urdf\";\n          world->insertModel(/*modelFile=*/pendulumURDF);\n          gazebo.run(/*paused=*/true);\n\n          // Get the pendulum\n          auto pendulum = world->getModel(/*modelName=*/\"pendulum\");\n\n          // Reset the pole position\n          auto pivot = pendulum->getJoint(\"pivot\");\n          auto pivotGazebo = std::static_pointer_cast<scenario::gazebo::Joint>(pivot);\n          pivotGazebo->resetPosition(0.001);\n\n          // Simulate 30 seconds\n          for (size_t i = 0; i < 30.0 / gazebo.stepSize(); ++i) {\n              gazebo.run();\n          }\n\n          // Close the simulator\n          std::this_thread::sleep_for(std::chrono::seconds(3));\n          gazebo.close();\n\n          return 0;\n      }\n\n  .. group-tab:: CMakeLists.txt\n\n    .. code-block:: cmake\n\n      cmake_minimum_required(VERSION 3.16)\n      project(ExampleWithScenario VERSION 1.0)\n\n      set(CMAKE_CXX_STANDARD 17)\n      set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n      find_package(Scenario COMPONENTS Gazebo REQUIRED)\n\n      add_executable(ExampleWithScenario example.cpp)\n\n      target_link_libraries(ExampleWithScenario PRIVATE\n          ScenarioGazebo::ScenarioGazebo\n          ScenarioGazebo::GazeboSimulator)\n\n.. note::\n\n    The environment should be properly configured to find the plugins and the models.\n    Use ``IGN_GAZEBO_SYSTEM_PLUGIN_PATH`` for the plugins and ``IGN_GAZEBO_RESOURCE_PATH`` for the models and meshes.\n"
  },
  {
    "path": "docs/sphinx/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Redirecting to master branch</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"refresh\" content=\"0; url=./master/index.html\">\n    <link rel=\"canonical\" href=\"https://robotology.github.io/gym-ignition/master/index.html\">\n  </head>\n</html>\n"
  },
  {
    "path": "docs/sphinx/index.rst",
    "content": ".. _scenario_and_gym_ignition:\n\nScenarIO and gym-ignition\n=========================\n\nThis project targets both *control* and *robot learning* research domains:\n\n- Researchers in robotics and control can simulate their robots with familiar tools like Gazebo and URDF/SDF,\n  without the need to rely on any middleware.\n- Researchers in robot learning can quickly develop new robotic environments that can scale to hundreds of parallel instances.\n\nWe provide two related subprojects to each of these categories:\n\n1. **ScenarIO** provides APIs to interface with the robots.\n2. **gym-ignition** helps structuring environments compatible with OpenAI Gym,\n   while minimizing boilerplate code and providing common rigid-body dynamics utilities.\n\nCheck the sections :ref:`What is ScenarIO <what_is_scenario>` and\n:ref:`What is gym-ignition <what_is_gym_ignition>` for more details,\nand visit :ref:`Motivations <motivations>` for an extended overview.\n\nFor a quick practical introduction, visit the :ref:`Getting Started <getting_started_scenario>` page.\n\nIf you use this project for your research, please check the FAQ about :ref:`how to give credit <faq_citation>`.\n\n.. list-table::\n\n   * - |pendulum_swing|\n     - |panda_grasping|\n     - |icub_stepping|\n\n.. |icub_stepping| image:: https://user-images.githubusercontent.com/469199/99262746-9e021a80-281e-11eb-9df1-d70134b0801a.png\n.. |panda_grasping| image:: https://user-images.githubusercontent.com/469199/99263111-0cdf7380-281f-11eb-9cfe-338b2aae0503.png\n.. |pendulum_swing| image:: https://user-images.githubusercontent.com/469199/99262383-321fb200-281e-11eb-89cc-cc31f590daa3.png\n\n.. toctree::\n   :hidden:\n   :maxdepth: 1\n   :caption: What\n\n   what/what_is_scenario\n   what/what_is_gym_ignition\n\n.. toctree::\n   :hidden:\n   :maxdepth: 1\n   :caption: Why\n\n   why/motivations\n   why/why_scenario\n   why/why_ignition_gazebo\n   why/why_gym_ignition\n\n.. toctree::\n   :hidden:\n   :maxdepth: 1\n   :caption: Installation (How)\n\n   installation/support_policy\n   installation/stable\n   installation/nightly\n   installation/developer\n\n.. toctree::\n   :hidden:\n   :maxdepth: 1\n   :caption: Getting Started\n\n   getting_started/scenario\n   getting_started/manipulation\n   getting_started/gym-ignition\n\n.. toctree::\n   :hidden:\n   :maxdepth: 2\n   :caption: ScenarIO C++ API:\n\n   breathe/core\n   breathe/gazebo\n\n.. toctree::\n   :hidden:\n   :maxdepth: 2\n   :caption: Python Packages\n\n   apidoc/scenario/scenario.bindings\n   apidoc/gym-ignition/gym_ignition\n   apidoc/gym-ignition-environments/gym_ignition_environments\n\n.. toctree::\n   :hidden:\n   :maxdepth: 2\n   :caption: Information\n\n   info/faq\n   info/limitations\n"
  },
  {
    "path": "docs/sphinx/info/faq.rst",
    "content": "FAQ\n===\n\n.. _faq_citation:\n\nHow to give credit?\n-------------------\n\nIf you use **ScenarIO** or **gym-ignition** for your research,\nplease cite the following reference:\n\n.. code-block:: bibtex\n   :caption: BibTeX entry\n\n   @INPROCEEDINGS{ferigo2020gymignition,\n     title={Gym-Ignition: Reproducible Robotic Simulations for Reinforcement Learning},\n     author={D. {Ferigo} and S. {Traversaro} and G. {Metta} and D. {Pucci}},\n     booktitle={2020 IEEE/SICE International Symposium on System Integration (SII)},\n     year={2020},\n     pages={885-890},\n     doi={10.1109/SII46433.2020.9025951}\n   }\n\nInteraction with Tensorflow\n---------------------------\n\nIf your Python application imports both ``scenario`` and ``tensorflow``,\nyou might experience segfaults with no error messages.\nLikely the problem is the `protobuf <https://github.com/protocolbuffers/protobuf>`_ library.\nIn fact, both Tensorflow and Ignition Gazebo link agains protobuf, but while Gazebo uses the\ndefault version of your OS, Tensorflow vendors a more recent version.\nIf you import ``scenario`` before ``tensorflow``, the system protobuf is loaded, and\nTensorflow will segfault.\n\nThe only workaround we found is importing Tensorflow first:\n\n>>> import tensorflow\n>>> import scenario.bindings.gazebo\n\nOgre2 and OpenGL\n----------------\n\nOn GNU/Linux distributions that ship an old OpenGL version, the GUI could fail to open printing\nerror like *Unable to create the rendering window*.\nThe reason is that Ignition Gazebo has `ogre-next <https://github.com/OGRECave/ogre-next>`_\n(also known as ogre2) as default rendering engine, and it requires OpenGL greater than 3.3.\nYou can find more details `here <https://github.com/ignitionrobotics/docs/blob/master/fortress/troubleshooting.md#unable-to-create-the-rendering-window>`_.\n\nThe workaround we recommend is modifying the file ``~/.ignition/gazebo/gui.config`` as follows:\n\n.. code-block:: diff\n\n   --- .ignition/gazebo/gui.config 2020-06-04 14:41:33.471804733 +0200\n   +++ .ignition/gazebo/gui.config 2020-06-04 14:42:47.826475035 +0200\n   @@ -30,7 +30,7 @@\n        <property type='bool' key='showTitleBar'>false</property>\n        <property type='string' key='state'>docked</property>\n      </ignition-gui>\n   -  <engine>ogre2</engine>\n   +  <engine>ogre</engine>\n      <scene>scene</scene>\n      <ambient_light>0.4 0.4 0.4</ambient_light>\n      <background_color>0.8 0.8 0.8</background_color>\n\nAfter this modification, world SDF files that do no specifically ask ``ogre2`` will use\n``ogre`` as default rendering engine which works also with older OpenGL versions.\n\nDefault SDF world\n-----------------\n\nIf not specified differently, the :cpp:class:`~scenario::gazebo::GazeboSimulator`\nclass uses a default world file that is completely empty, without even the ground plane.\nYou can load a custom SDF world using :cpp:func:`~scenario::gazebo::GazeboSimulator::insertWorldFromSDF()` and then\nextracting it from the simulator with :cpp:func:`~scenario::gazebo::GazeboSimulator::getWorld()` using its name.\n\n.. code-block:: xml\n   :caption: ``empty.world``: use this file as starting point for your custom world\n\n   <?xml version=\"1.0\" ?>\n   <sdf version=\"1.7\">\n       <world name=\"default\">\n           <physics default=\"true\" type=\"ignored\">\n           </physics>\n           <light type=\"directional\" name=\"sun\">\n               <cast_shadows>true</cast_shadows>\n               <pose>0 0 10 0 0 0</pose>\n               <diffuse>0.8 0.8 0.8 1</diffuse>\n               <specular>0.2 0.2 0.2 1</specular>\n               <attenuation>\n                   <range>1000</range>\n                   <constant>0.9</constant>\n                   <linear>0.01</linear>\n                   <quadratic>0.001</quadratic>\n               </attenuation>\n               <direction>-0.5 0.1 -0.9</direction>\n           </light>\n       </world>\n   </sdf>\n\n.. note::\n\n   If you don't specify any GUI configuration, the default ``~/.ignition/gazebo/gui.config`` is used.\n   This is the preferred approach since it's easier to maintain and keep world files updated.\n   You can find more information in the upstream `default.sdf <https://github.com/ignitionrobotics/ign-gazebo/blob/master/examples/worlds/default.sdf>`_.\n\n.. tip::\n\n   You don't need to add the physics plugin in the world file. You can use\n   :cpp:func:`scenario::gazebo::World::setPhysicsEngine()` from your code.\n   You can also load other plugins during runtime using\n   :cpp:func:`scenario::gazebo::World::insertWorldPlugin()` and\n   :cpp:func:`scenario::gazebo::Model::insertModelPlugin()`.\n"
  },
  {
    "path": "docs/sphinx/info/limitations.rst",
    "content": "Limitations\n===========\n\nSensors support\n---------------\n\nIgnition Gazebo supports a wide variety of `sensors <https://ignitionrobotics.org/docs/citadel/comparison#sensors>`_,\nlike cameras, lidars, ...\nHowever, ScenarI/O and consequently gym-ignition are not yet able to extract data from sensors.\nFollow :issue:`199` if you're interested in sensors support.\n\nPerformance\n-----------\n\nWhen operating on a single model, DART provides good enough performance and accuracy for most of the use-cases.\nHowever, we noticed that it does not perform well when many models are inserted in the simulated world,\nespecially in contact-rich scenarios.\n\nIf your aim is performing simulations for robot learning, we recommend running multiple instances of the simulator,\neach of them operating on a world containing a single robot.\n\nIf your aim is simulating a big world where the controlled model can move inside the scene, exploiting a new feature\nof Ignition Gazebo called `levels <https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/tutorials/levels.md>`_\ncould be the proper solution. This feature is exploited by the big worlds of `subt <https://subtchallenge.com>`_.\n\nInstead, if your world has many models and the usage of levels does not apply to your use-case, you can try to switch\nthe physics backend to an engine that handles better your simulation.\n\n.. note::\n\n   At the time of writing only DART is officially supported.\n   There is some recent activity to implement the bullet physics engine, but this back-and is not yet ready.\n   As last resort, you can implement a new physics backend following the\n   `instructions <https://github.com/ignitionrobotics/ign-physics/blob/ign-physics3/tutorials/03_physics_plugins.md>`_.\n"
  },
  {
    "path": "docs/sphinx/installation/developer.rst",
    "content": ".. _installation_developer:\n\nDeveloper Installation\n======================\n\nThis installation type is intended for those that want to contribute to the development of the project.\nCompared to :ref:`Stable <installation_stable>` and :ref:`Nightly <installation_nightly>`,\nthis installation type provides a simplified setup for development, VCS integration, and debugging.\n\nDepending on whether you want to target the ``Stable`` or ``Nightly`` channels,\nyou have to clone respectively the ``master`` or ``devel`` branch.\nCheck our :ref:`support policy <support_policy>` to select the right distribution of Ignition to install.\n\nDependencies\n************\n\nThe developer installation requires finding in the system other dependencies not required by the other installation types.\nIn those cases, we rely on setuptools to download, install, and find all the necessary third-party dependencies.\n\n1. **iDynTree**: ``gym_ignition`` provides helper classes to manipulate the kinematics and the dynamics of rigid-bodies.\n   Among the many existing solutions, we selected the algorithms implemented in `iDynTree <https://github.com/robotology/idyntree/>`_.\n\n   Follow the `official installation instructions <https://github.com/robotology/idyntree/#installation>`__ and make sure\n   that you also enable and install the `Python bindings <https://github.com/robotology/idyntree/#bindings>`__.\n\n   You can verify that the installation succeeded and your system is properly configured if you can ``import idyntree.bindings`` in a Python interpreter.\n\nC++ Project\n***********\n\nFrom the root of the repository and from the branch you are interested, you can configure, compile, and install\nthe CMake project as follows:\n\n.. code-block:: bash\n\n    cd scenario/\n    cmake -S . -B build\n    cmake --build build/\n    cmake --build build/ --target install\n\n.. note::\n\n    The default install prefix of the CMake project is ``/usr/local``.\n    If you want to use a different folder, pass ``-DCMAKE_INSTALL_PREFIX=/new/install/prefix`` to the first ``cmake`` command.\n\n.. attention::\n\n    The SWIG bindings are installed in the `site-packages <https://docs.python.org/3/install/#how-installation-works>`_\n    folder of the active Python interpreter.\n    If you have an active virtual environment, it will be automatically detected.\n    We rely on CMake's logic for detecting Python,\n    visit `FindPython3 <https://cmake.org/cmake/help/v3.16/module/FindPython3.html>`_ for more details.\n\n.. include:: virtual_environment.rst\n\nEditable Python Installation\n****************************\n\nInstall the Python package in `editable mode <https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs>`_.\nFrom the root of the repository:\n\n.. code-block:: bash\n\n    pip install -e scenario/\n    pip install -e .\n\nThe editable installation only symlinks the resources of the repository into the active Python installation.\nIt allows to develop directly operating on the files of the repository and use the updated package without requiring\nto install it again.\n\n.. note::\n\n    The ``scenario`` editable installation is just a placeholder.\n    It is necessary to prevent the editable installation of ``gym-ignition`` to override the resources installed by\n    the manual CMake execution.\n    Otherwise, the ``scenario`` package from PyPI would be pulled, resulting with a wrong version.\n\n.. include:: system_configuration.rst\n"
  },
  {
    "path": "docs/sphinx/installation/nightly.rst",
    "content": ".. _installation_nightly:\n\nNightly\n=======\n\nThe nightly channel contains the most recent updates of the project.\nAs described in the :ref:`support policy <support_policy>`, this channel requires building Ignition from sources.\n\nWe publish updated nightly packages after any pull request merged in the ``devel`` branch.\n\n.. include:: virtual_environment.rst\n\nPyPI Package\n************\n\nWe provide two different packages for ScenarIO and gym-ignition.\n\nIf you are interested in the ScenarIO package,\ninstall the `scenario <https://pypi.org/project/scenario/>`_ package from PyPI:\n\n.. code-block:: bash\n\n   pip install --pre scenario\n\nInstead, if you are interested in gym-ignition,\ninstall the `gym-ignition <https://pypi.org/project/gym-ignition/>`_ package from PyPI:\n\n.. code-block:: bash\n\n   pip install --pre scenario gym-ignition\n\nNote that in this case, specifying also the ``scenario`` dependency is necessary,\notherwise ``pip`` will pull the stable package from PyPI.\n\n.. include:: system_configuration.rst\n"
  },
  {
    "path": "docs/sphinx/installation/stable.rst",
    "content": ".. _installation_stable:\n\nStable\n======\n\nThe stable channel is the easiest way to setup your system.\nAs described in the :ref:`support policy <support_policy>`, this channel allows installing Ignition from binary packages.\n\nWe publish updated stable packages after any tagged release of the ``master`` branch.\n\n.. include:: virtual_environment.rst\n\nPyPI Package\n************\n\nWe provide two different packages for ScenarIO and gym-ignition.\n\nIf you are interested in the ScenarIO package,\ninstall the `scenario <https://pypi.org/project/scenario/>`_ package from PyPI:\n\n.. code-block:: bash\n\n   pip install scenario\n\nInstead, if you are interested in gym-ignition,\ninstall the `gym-ignition <https://pypi.org/project/gym-ignition/>`_ package from PyPI:\n\n.. code-block:: bash\n\n   pip install gym-ignition\n\nIt will download and install also ``scenario`` since it depends on it.\n"
  },
  {
    "path": "docs/sphinx/installation/support_policy.rst",
    "content": ".. _support_policy:\n\nSupport policy\n==============\n\n**gym-ignition** is an hybrid C++ and Python project and it requires finding in the system updated compile and runtime\ndependencies, depending on the installation type you select.\n\nThe project mostly supports all the major operating systems.\nHowever, we are currently using and testing only GNU/Linux systems.\nWe do not yet provide official support to other operating systems.\n\nThe table below recaps the project requirements of the :ref:`Stable <installation_stable>` and :ref:`Nightly <installation_nightly>` channels:\n\n+-------------+-----------------+--------+----------------------+----------+------------+---------+\n| Channel     |       C++       | Python |      Ignition        |  Ubuntu  | macOS [*]_ | Windows |\n+=============+=================+========+======================+==========+============+=========+\n| **Stable**  | >= gcc8, clang6 | >= 3.8 | `Fortress`_ (binary) | >= 20.04 |     No     |    No   |\n+-------------+-----------------+--------+----------------------+----------+------------+---------+\n| **Nightly** | >= gcc8, clang6 | >= 3.8 | `Fortress`_ (source) | >= 20.04 |     No     |    No   |\n+-------------+-----------------+--------+----------------------+----------+------------+---------+\n\n.. _`Fortress`: https://ignitionrobotics.org/docs/fortress/install\n\n.. [*] Ignition officially supports macOS and also ``gym-ignition`` could be installed on this platform.\n       However, we do not currently test this configuration and we cannot guarantee support.\n\n.. important::\n\n    Our policy is to support Ubuntu from the most recent LTS distribution, currently Ubuntu 20.04 Focal.\n    We typically switch to a new LTS when the first minor release ``YY.MM.1`` is released.\n\n    The Python and compilers policies follow a similar approach, we try to keep them updated as much as\n    possible following what the supported LTS distribution includes.\n\n.. note::\n\n    External contributions to extend the support and provide feedback about other platforms are most welcome.\n\n.. admonition:: Fun fact\n\n    In the same spirit of `ubuntu/+bug/1 <https://bugs.launchpad.net/ubuntu/+bug/1>`_, we have our own :issue:`1`.\n"
  },
  {
    "path": "docs/sphinx/installation/system_configuration.rst",
    "content": "System Configuration\n********************\n\nThis section applies only to the installations that require building Ignition from sources.\n\nIf you installed Ignition from sources, you likely used ``colcon`` and therefore the entire suite was installed in a custom folder called workspace.\nThe workspace contains all the shared libraries and executables of Ignition, including the plugins loaded during runtime.\nSince we cannot know in advance where you created the workspace, ``gym-ignition`` is not able to find the physics plugins.\n\nAfter you enabled the workspace by sourcing its bash script, you may need to also export the following variable:\n\n.. code-block:: bash\n\n   export IGN_GAZEBO_PHYSICS_ENGINE_PATH=${IGN_GAZEBO_PHYSICS_ENGINE_PATH}:${COLCON_PREFIX_PATH}/lib/ign-physics-3/engine-plugins/\n\nMake sure to select the folder corresponding to the correct version of ign-physics, otherwise the wrong plugins are found.\n"
  },
  {
    "path": "docs/sphinx/installation/virtual_environment.rst",
    "content": "Virtual Environment (optional)\n******************************\n\nThis step is optional but highly recommended.\nVisit the `virtual environments <https://docs.python.org/3.6/tutorial/venv.html>`_ documentation for more details.\n\n.. code-block:: bash\n\n   sudo apt install virtualenv\n   virtualenv -p python3.8 $HOME/venv\n   source $HOME/venv/bin/activate\n\nNote that the activation is temporary and it is valid only in the same terminal.\nMake sure to execute the next steps in a terminal where the virtual environment is active.\n"
  },
  {
    "path": "docs/sphinx/what/what_is_gym_ignition.rst",
    "content": ".. _what_is_gym_ignition:\n\nWhat is gym-ignition?\n=====================\n\n**gym-ignition** is a framework to create **reproducible robotics environments** for reinforcement learning research.\n\nIt is based on the :ref:`ScenarIO <what_is_scenario>` project which provides the low-level APIs to interface with the Ignition Gazebo simulator.\nBy default, RL environments share a lot of boilerplate code, e.g. for initializing the simulator or structuring the classes\nto expose the ``gym.Env`` interface.\nGym-ignition provides the :py:class:`~gym_ignition.base.task.Task` and :py:class:`~gym_ignition.base.runtime.Runtime`\nabstractions that help you focusing on the development of the decision-making logic rather than engineering.\nIt includes :py:mod:`~gym_ignition.randomizers` to simplify the implementation of domain randomization\nof models, physics, and tasks.\nGym-ignition also provides powerful dynamics algorithms compatible with both fixed-base and floating-based robots by\nexploiting `iDynTree <https://github.com/robotology/idyntree/>`_ and exposing\nhigh-level functionalities (:py:mod:`~gym_ignition.rbd.idyntree`).\n\nGym-ignition does not provide out-of-the-box environments ready to be used.\nRather, its aim is simplifying and streamlining their development.\nNonetheless, for illustrative purpose, it includes canonical examples in the\n:py:mod:`gym_ignition_environments` package.\n"
  },
  {
    "path": "docs/sphinx/what/what_is_scenario.rst",
    "content": ".. _what_is_scenario:\n\nWhat is ScenarIO\n================\n\n**ScenarIO** is a C++ abstraction layer to interact with simulated and real robots.\n\nIt mainly provides the following\n`C++ interfaces <https://github.com/robotology/gym-ignition/tree/master/scenario/core/include/scenario/core>`_:\n\n- :cpp:class:`scenario::core::World`\n- :cpp:class:`scenario::core::Model`\n- :cpp:class:`scenario::core::Link`\n- :cpp:class:`scenario::core::Joint`\n\nThese interfaces can be implemented to operate on different scenarios,\nincluding robots operating on either simulated worlds or in real-time.\n\nScenarIO currently fully implements **Gazebo ScenarIO** (APIs),\na simulated back-end that interacts with `Ignition Gazebo <https://ignitionrobotics.org>`_.\nThe result allows stepping the simulator programmatically, ensuring a fully reproducible behaviour.\nIt relates closely to other projects like\n`pybullet <https://github.com/bulletphysics/bullet3>`_ and `mujoco-py <https://github.com/openai/mujoco-py>`_.\n\nA real-time backend that interacts with the `YARP <https://github.com/robotology/yarp>`_ middleware is under development.\n\nScenarIO can be used either from C++ (:ref:`Core APIs <scenario_core>`, :ref:`Gazebo APIs <scenario_gazebo>`)\nor from Python (:py:mod:`~scenario.bindings.core`, :py:mod:`~scenario.bindings.gazebo`).\n\nIf you're interested to know the reasons why we started developing ScenarIO and why we selected Ignition Gazebo\nfor our simulations, visit the :ref:`Motivations <motivations>` section.\n"
  },
  {
    "path": "docs/sphinx/why/motivations.rst",
    "content": ".. _motivations:\n\nIntro\n=====\n\nIn this section we recap the motivations behind this project.\nChoosing the right framework for your research is often challenging and we hope to provide a broader look that could\nhelp deciding whether it meets your needs or not.\n\nThe development of the framework is evolving quickly, and the architecture and motivations described in the\n:ref:`reference publication <faq_citation>` are becoming outdated.\nWhile that publication remains the reference in case you use the project for your research,\nthis section provides a constantly updated description aligned with the most recent development news.\n"
  },
  {
    "path": "docs/sphinx/why/why_gym_ignition.rst",
    "content": ".. _why_gym_ignition:\n\nWhy gym-ignition\n================\n\nIn the previous sections we described why we developed ScenarIO and why we used Ignition Gazebo to implement its simulation back-end.\nWhile we mentioned few advantages for the robot learning domain, ScenarIO remains a general C++ library that can be used for generic robotic applications.\n\nThe reinforcement learning community, in the past years, converged towards Python for the development of the environments\ncontaining the decision-making logic.\n`OpenAI Gym <https://gym.openai.com>`_ became the reference interface to provide a clear separation between agents and environments.\nA widespread interface is powerful because if you implement an environment that exposes the ``gym.Env`` interface, you can then use\nall the countless frameworks provided by the community to train a policy selecting your favourite algorithm.\n\nThe Python package ``gym_ignition`` enables you to create robotic environments compatible with OpenAI Gym.\nBeing based on ScenarIO, it enables to develop environments that can run not only on different physics engines,\nbut also on real robots.\n\nYou can think of ``gym_ignition`` as a way to help you structuring your environment.\nIf you know how `pytorch-lightning <https://github.com/PyTorchLightning/pytorch-lightning>`_ relates to PyTorch,\nthe same applies to the interaction between gym-ignition and ScenarIO.\nThanks to the :py:class:`~gym_ignition.base.task.Task` and :py:class:`~gym_ignition.base.runtime.Runtime` interfaces,\n``gym_ignition`` abstracts away all the unnecessary boilerplate that otherwise you have to copy and paste between environments.\n\nFor example, :py:class:`~gym_ignition.runtimes.gazebo_runtime.GazeboRuntime` provides all boilerplate code to take\nyour implementation of a :py:class:`~gym_ignition.base.task.Task` and simulate it with Ignition Gazebo.\n\nFurthermore, we provide useful classes with functionalities that are commonly required by robotic environments, like\nInverse Kinematic (:py:class:`~gym_ignition.rbd.idyntree.inverse_kinematics_nlp.InverseKinematicsNLP`)\nand multibody dynamics algorithms (:py:class:`~gym_ignition.rbd.idyntree.kindyncomputations.KinDynComputations`)\nwith full support of floating-base systems.\n\n.. note::\n\n   Developing environments for robot learning in C++ is a valid choice and the community has shown different examples.\n   ScenarIO can be used to develop C++ environments as well, however we find more useful using Python since it allows\n   a faster prototyping.\n\n.. note::\n\n   To the best of our knowledge, the first package that implemented a structure that abstracts the task, the robot, and\n   the simulator is `openai_ros <http://wiki.ros.org/openai_ros>`_.\n   We have been inspired by its structure in the early stage of development, and the current interfaces implemented in\n   gym-ignition are an evolution of the original architecture.\n"
  },
  {
    "path": "docs/sphinx/why/why_ignition_gazebo.rst",
    "content": ".. _why_ignition_gazebo:\n\nWhy Ignition Gazebo\n===================\n\nIn this section we want to go a bit deeper in the motivations that led us to select Ignition Gazebo as target solution for the simulation back-end of ScenarIO.\n\nTo begin, a bit of history. The `Gazebo <https://gazebosim.org>`_ simulator that the entire robotic community has used for\nover a decade is different than Ignition Gazebo.\nWe will refer to the old simulator as Gazebo Classic.\nIgnition Gazebo is the new generation of the simulator.\nIt takes all the lesson learned by the development of Gazebo Classic and provides a more modular and extensible framework for robotic simulations.\nThe monolithic structure of Gazebo Classic has been broken in standalone libraries, obtaining a *suite* called `Ignition <https://ignitionrobotics.org>`_.\nIgnition Gazebo is just one of the libraries [*]_ that compose the suite.\nWhen we started the development of gym-ignition, Ignition Gazebo was \"stable\" enough to start using it.\nThe clear advantage is support: Gazebo Classic will just receive bug fixing, all the development effort now shifted towards the new Ignition Gazebo.\nThe price to pay, instead, is that Ignition Gazebo has not yet reached feature parity with Gazebo Classic, even though\nthe gap is getting filled quickly.\n\n.. [*] Yes, you read correctly: *library*. Ignition Gazebo is a library.\n       A ``ignition::gazebo::Server`` object can be instantiated and it can be stepped programmatically from your code.\n       This type of architecture became quite popular recently because it gives you full control of the simulation.\n       Ignition Gazebo, therefore, became a solution similar to the well known alternatives like ``pybullet`` and ``mujoco-py``.\n\nWe have been and currently are Gazebo Classic users, as many other robotics research labs.\nOver time, we became familiar with the tools and methods of Gazebo Classic and built a lot of code and applications that depend on it.\nUnfortunately, despite someone has shown attempts, Gazebo Classic is not suitable for the large-scale simulations that are\ntypical in modern reinforcement learning architectures.\nIgnition Gazebo offered us a viable solution for this use case that allows us to exploit the know-how we gained with Gazebo Classic.\n\nThe two main features that drove us towards the adoption of Ignition Gazebo are the following:\n\n1. **Physics engines are loaded as plugin libraries and Ignition Gazebo operates on an API-stable interface.**\n   This architecture allows everyone to implement a new physics engine backend and run simulations exploiting all the other\n   components of the Ignition suite (rendering, systems, ...).\n   While today only `DART <https://github.com/dartsim/dart>`_ is officially supported, we believe this is one of the best\n   attempts to obtain in the long run a framework that allows to switch physics engines with minimal effort.\n   For reinforcement learning research, it could bring domain randomization to the next level.\n2. **Simulations can be stepped programmatically without relying on network transport, guaranteeing full reproducibility.**\n   Reproducible simulations are paramount whether you are prototyping a new robot controller or you are running\n   large-scale simulations for robot learning.\n   Most of the client-server architectures cannot guarantee reproducibility since asynchronous network transports could\n   provide different results depending on the load of your system.\n   An effective solution is using the simulator as a library and stepping it programmatically from your code.\n   Gazebo ScenarIO provides APIs to perform these kind of simulations with Ignition Gazebo.\n\nThere are a bunch of other nice features we didn't cover in this section.\nNot all of them are currently exposed to ScenarIO Gazebo, please open a feature request if you have any suggestion or,\neven better, fire up a pull request!\n\nTo summarize, these are the features that motivated us to choose Ignition Gazebo:\n\n- Simulator developed for robotics\n- Simulator-as-a-library structure\n- Abstraction of different physics engines and rendering engines\n- Modular software architecture\n- Powerful and constantly improving SDF model description\n- Well maintained, packaged, and widely tested\n- Large big database of objects to create worlds: `Ignition Fuel <https://app.ignitionrobotics.org/dashboard>`_\n- Long term vision and support\n\n.. note::\n\n   Ignition Gazebo is the target simulator of the new `DARPA Subterranean Challenge <https://subtchallenge.com>`_.\n   Have a look to their simulation results to understand what you can expect from using Ignition Gazebo.\n"
  },
  {
    "path": "docs/sphinx/why/why_scenario.rst",
    "content": ".. _why_scenario:\n\nWhy ScenarIO\n============\n\n*SCENe interfAces for Robot Input/Output* is an abstraction layer to interface with robots.\nIt exposes APIs to interact with a scene, providing a :cpp:class:`~scenario::core::World` that can return\n:cpp:class:`~scenario::core::Model` objects, from which you can gather measurements and send commands.\nThe relevant APIs of ScenarIO are documented in the :ref:`Scenario Core <scenario_core>` section.\n\nMany simulators already provide an abstraction of different physics engines.\nThey expose a unified interface that, after selecting the desired back-end, maps its unified methods to those of the\nunderlying physics engine. The aim of ScenarIO is extending this idea also to real-time robots.\n\nThe simulation backend of ScenarIO communicates with a simulator that itself abstracts physics engines.\nThis is powerful because, in this way, ScenarIO is independent from the details of the underlying physics engine.\nAny current and future physics engine supported by the simulator is compatible with ScenarIO without requiring any\nchange from our side.\n\nRegarding real-time robots, the APIs of ScenarIO can be implemented exploiting middlewares like ROS or YARP.\nAt the time of writing there are no official real-time backends, stay tuned for further updates.\n\nOnce both the simulation and real-time backends are in place, you can then write code to control your robot just once,\nit will interact either with the simulated or the real robot depending on the ScenarIO backend you enabled.\n\n.. note::\n\n   The ScenarIO interface is flexible and generic.\n   Let's say you already have built your functionality with the backends we provide,\n   and you are not happy from the performance of the simulator we used.\n   You can implement your own simulation backend and run it alongside those we provide.\n   The same applies to the real-time backend, in case your robot uses a custom middleware or SDK.\n\n.. tip::\n\n   So far, we always referred to the C++ abstraction layer provided by ScenarIO.\n   The interface / implementation pattern is implemented with classic inheritance and polymorphism.\n   Having such unified interface simplifies the process to expose it to other languages.\n   Thanks to SWIG, we officially provide Python bindings of ScenarIO,\n   so that you can prototype your applications even faster!\n"
  },
  {
    "path": "examples/panda_pick_and_place.py",
    "content": "import enum\nimport time\nfrom functools import partial\nfrom typing import List\n\nimport gym_ignition\nimport gym_ignition_environments\nimport numpy as np\nfrom gym_ignition.context.gazebo import controllers\nfrom gym_ignition.rbd import conversions\nfrom gym_ignition.rbd.idyntree import inverse_kinematics_nlp\nfrom scipy.spatial.transform import Rotation as R\n\nfrom scenario import core as scenario_core\nfrom scenario import gazebo as scenario_gazebo\n\n# Configure verbosity\nscenario_gazebo.set_verbosity(scenario_gazebo.Verbosity_error)\n\n# Configure numpy output\nnp.set_printoptions(precision=4, suppress=True)\n\n\ndef add_panda_controller(\n    panda: gym_ignition_environments.models.panda.Panda, controller_period: float\n) -> None:\n\n    # Set the controller period\n    assert panda.set_controller_period(period=controller_period)\n\n    # Increase the max effort of the fingers\n    panda.get_joint(\n        joint_name=\"panda_finger_joint1\"\n    ).to_gazebo().set_max_generalized_force(max_force=500.0)\n    panda.get_joint(\n        joint_name=\"panda_finger_joint2\"\n    ).to_gazebo().set_max_generalized_force(max_force=500.0)\n\n    # Insert the ComputedTorqueFixedBase controller\n    assert panda.to_gazebo().insert_model_plugin(\n        *controllers.ComputedTorqueFixedBase(\n            kp=[100.0] * (panda.dofs() - 2) + [10000.0] * 2,\n            ki=[0.0] * panda.dofs(),\n            kd=[17.5] * (panda.dofs() - 2) + [100.0] * 2,\n            urdf=panda.get_model_file(),\n            joints=panda.joint_names(),\n        ).args()\n    )\n\n    # Initialize the controller to the current state\n    assert panda.set_joint_position_targets(panda.joint_positions())\n    assert panda.set_joint_velocity_targets(panda.joint_velocities())\n    assert panda.set_joint_acceleration_targets(panda.joint_accelerations())\n\n\ndef get_panda_ik(\n    panda: gym_ignition_environments.models.panda.Panda, optimized_joints: List[str]\n) -> inverse_kinematics_nlp.InverseKinematicsNLP:\n\n    # Create IK\n    ik = inverse_kinematics_nlp.InverseKinematicsNLP(\n        urdf_filename=panda.get_model_file(),\n        considered_joints=optimized_joints,\n        joint_serialization=panda.joint_names(),\n    )\n\n    # Initialize IK\n    ik.initialize(\n        verbosity=1,\n        floating_base=False,\n        cost_tolerance=1e-8,\n        constraints_tolerance=1e-8,\n        base_frame=panda.base_frame(),\n    )\n\n    # Set the current configuration\n    ik.set_current_robot_configuration(\n        base_position=np.array(panda.base_position()),\n        base_quaternion=np.array(panda.base_orientation()),\n        joint_configuration=np.array(panda.joint_positions()),\n    )\n\n    # Add the cartesian target of the end effector\n    end_effector = \"end_effector_frame\"\n    ik.add_target(\n        frame_name=end_effector,\n        target_type=inverse_kinematics_nlp.TargetType.POSE,\n        as_constraint=False,\n    )\n\n    return ik\n\n\ndef insert_bucket(world: scenario_gazebo.World) -> scenario_gazebo.Model:\n\n    # Insert objects from Fuel\n    uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n    # Download the cube SDF file\n    bucket_sdf = scenario_gazebo.get_model_file_from_fuel(\n        uri=uri(\n            org=\"GoogleResearch\",\n            name=\"Threshold_Basket_Natural_Finish_Fabric_Liner_Small\",\n        ),\n        use_cache=False,\n    )\n\n    # Assign a custom name to the model\n    model_name = \"bucket\"\n\n    # Insert the model\n    assert world.insert_model(\n        bucket_sdf, scenario_core.Pose([0.68, 0, 1.02], [1.0, 0, 0, 1]), model_name\n    )\n\n    # Return the model\n    return world.get_model(model_name=model_name)\n\n\ndef insert_table(world: scenario_gazebo.World) -> scenario_gazebo.Model:\n\n    # Insert objects from Fuel\n    uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n    # Download the cube SDF file\n    bucket_sdf = scenario_gazebo.get_model_file_from_fuel(\n        uri=uri(org=\"OpenRobotics\", name=\"Table\"), use_cache=False\n    )\n\n    # Assign a custom name to the model\n    model_name = \"table\"\n\n    # Insert the model\n    assert world.insert_model(bucket_sdf, scenario_core.Pose_identity(), model_name)\n\n    # Return the model\n    return world.get_model(model_name=model_name)\n\n\ndef insert_cube_in_operating_area(\n    world: scenario_gazebo.World,\n) -> scenario_gazebo.Model:\n\n    # Insert objects from Fuel\n    uri = lambda org, name: f\"https://fuel.ignitionrobotics.org/{org}/models/{name}\"\n\n    # Download the cube SDF file\n    cube_sdf = scenario_gazebo.get_model_file_from_fuel(\n        uri=uri(org=\"openrobotics\", name=\"wood cube 5cm\"), use_cache=False\n    )\n\n    # Sample a random position\n    random_position = np.random.uniform(low=[0.2, -0.3, 1.01], high=[0.4, 0.3, 1.01])\n\n    # Get a unique name\n    model_name = gym_ignition.utils.scenario.get_unique_model_name(\n        world=world, model_name=\"cube\"\n    )\n\n    # Insert the model\n    assert world.insert_model(\n        cube_sdf, scenario_core.Pose(random_position, [1.0, 0, 0, 0]), model_name\n    )\n\n    # Return the model\n    return world.get_model(model_name=model_name)\n\n\ndef solve_ik(\n    target_position: np.ndarray,\n    target_orientation: np.ndarray,\n    ik: inverse_kinematics_nlp.InverseKinematicsNLP,\n) -> np.ndarray:\n\n    quat_xyzw = R.from_euler(seq=\"y\", angles=90, degrees=True).as_quat()\n\n    ik.update_transform_target(\n        target_name=ik.get_active_target_names()[0],\n        position=target_position,\n        quaternion=conversions.Quaternion.to_wxyz(xyzw=quat_xyzw),\n    )\n\n    # Run the IK\n    ik.solve()\n\n    return ik.get_reduced_solution().joint_configuration\n\n\ndef end_effector_reached(\n    position: np.array,\n    end_effector_link: scenario_core.Link,\n    max_error_pos: float = 0.01,\n    max_error_vel: float = 0.5,\n    mask: np.ndarray = np.array([1.0, 1.0, 1.0]),\n) -> bool:\n\n    masked_target = mask * position\n    masked_current = mask * np.array(end_effector_link.position())\n\n    return (\n        np.linalg.norm(masked_current - masked_target) < max_error_pos\n        and np.linalg.norm(end_effector_link.world_linear_velocity()) < max_error_vel\n    )\n\n\ndef get_unload_position(bucket: scenario_core.Model) -> np.ndarray:\n\n    return bucket.base_position() + np.array([0, 0, 0.3])\n\n\nclass FingersAction(enum.Enum):\n\n    OPEN = enum.auto()\n    CLOSE = enum.auto()\n\n\ndef move_fingers(\n    panda: gym_ignition_environments.models.panda.Panda, action: FingersAction\n) -> None:\n\n    # Get the joints of the fingers\n    finger1 = panda.get_joint(joint_name=\"panda_finger_joint1\")\n    finger2 = panda.get_joint(joint_name=\"panda_finger_joint2\")\n\n    if action is FingersAction.OPEN:\n        finger1.set_position_target(position=finger1.position_limit().max)\n        finger2.set_position_target(position=finger2.position_limit().max)\n\n    if action is FingersAction.CLOSE:\n        finger1.set_position_target(position=finger1.position_limit().min)\n        finger2.set_position_target(position=finger2.position_limit().min)\n\n\n# ====================\n# INITIALIZE THE WORLD\n# ====================\n\n# Get the simulator and the world\ngazebo, world = gym_ignition.utils.scenario.init_gazebo_sim(\n    step_size=0.001, real_time_factor=2.0, steps_per_run=1\n)\n\n# Open the GUI\ngazebo.gui()\ntime.sleep(3)\ngazebo.run(paused=True)\n\n# Insert the Panda manipulator\npanda = gym_ignition_environments.models.panda.Panda(\n    world=world, position=[-0.1, 0, 1.0]\n)\n\n# Disable joint velocity limits\n_ = [j.to_gazebo().set_velocity_limit(1_000) for j in panda.joints()]\n\n# Enable contacts only for the finger links\npanda.get_link(\"panda_leftfinger\").to_gazebo().enable_contact_detection(True)\npanda.get_link(\"panda_rightfinger\").to_gazebo().enable_contact_detection(True)\n\n# Process model insertion in the simulation\ngazebo.run(paused=True)\n\n# Monkey patch the class with finger helpers\npanda.open_fingers = partial(move_fingers, panda=panda, action=FingersAction.OPEN)\npanda.close_fingers = partial(move_fingers, panda=panda, action=FingersAction.CLOSE)\n\n# Add a custom joint controller to the panda\nadd_panda_controller(panda=panda, controller_period=gazebo.step_size())\n\n# Populate the world\ntable = insert_table(world=world)\nbucket = insert_bucket(world=world)\ngazebo.run(paused=True)\n\n# Create and configure IK for the panda\nik_joints = [\n    j.name() for j in panda.joints() if j.type is not scenario_core.JointType_fixed\n]\nik = get_panda_ik(panda=panda, optimized_joints=ik_joints)\n\n# Get some manipulator links\nfinger_left = panda.get_link(link_name=\"panda_leftfinger\")\nfinger_right = panda.get_link(link_name=\"panda_rightfinger\")\nend_effector_frame = panda.get_link(link_name=\"end_effector_frame\")\n\nwhile True:\n\n    # Insert a new cube\n    cube = insert_cube_in_operating_area(world=world)\n    gazebo.run(paused=True)\n\n    # =========================\n    # PHASE 1: Go over the cube\n    # =========================\n\n    print(\"Hovering\")\n\n    # Position over the cube\n    position_over_cube = np.array(cube.base_position()) + np.array([0, 0, 0.4])\n\n    # Get the joint configuration that brings the EE over the cube\n    over_joint_configuration = solve_ik(\n        target_position=position_over_cube,\n        target_orientation=np.array(cube.base_orientation()),\n        ik=ik,\n    )\n\n    # Set the joint references\n    assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n\n    # Open the fingers\n    panda.open_fingers()\n\n    # Run the simulation until the EE reached the desired position\n    while not end_effector_reached(\n        position=position_over_cube,\n        end_effector_link=end_effector_frame,\n        max_error_pos=0.05,\n        max_error_vel=0.5,\n    ):\n        gazebo.run()\n\n    # Wait a bit more\n    [gazebo.run() for _ in range(500)]\n\n    # =======================\n    # PHASE 2: Reach the cube\n    # =======================\n\n    print(\"Reaching\")\n\n    # Get the joint configuration that brings the EE to the cube\n    over_joint_configuration = solve_ik(\n        target_position=np.array(cube.base_position()) + np.array([0, 0, 0.04]),\n        target_orientation=np.array(cube.base_orientation()),\n        ik=ik,\n    )\n\n    # Set the joint references\n    assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n    panda.open_fingers()\n\n    # Run the simulation until the EE reached the desired position\n    while not end_effector_reached(\n        position=np.array(cube.base_position()) + np.array([0, 0, 0.04]),\n        end_effector_link=end_effector_frame,\n    ):\n\n        gazebo.run()\n\n    # Wait a bit more\n    [gazebo.run() for _ in range(500)]\n\n    # =======================\n    # PHASE 3: Grasp the cube\n    # =======================\n\n    print(\"Grasping\")\n\n    # Close the fingers\n    panda.close_fingers()\n\n    # Detect a graps reading the contact wrenches of the finger links\n    while not (\n        np.linalg.norm(finger_left.contact_wrench()) >= 50.0\n        and np.linalg.norm(finger_right.contact_wrench()) >= 50.0\n    ):\n        gazebo.run()\n\n    # =============\n    # PHASE 4: Lift\n    # =============\n\n    print(\"Lifting\")\n\n    # Position over the cube\n    position_over_cube = np.array(cube.base_position()) + np.array([0, 0, 0.4])\n\n    # Get the joint configuration that brings the EE over the cube\n    over_joint_configuration = solve_ik(\n        target_position=position_over_cube,\n        target_orientation=np.array(cube.base_orientation()),\n        ik=ik,\n    )\n\n    # Set the joint references\n    assert panda.set_joint_position_targets(over_joint_configuration, ik_joints)\n\n    # Run the simulation until the EE reached the desired position\n    while not end_effector_reached(\n        position=position_over_cube,\n        end_effector_link=end_effector_frame,\n        max_error_pos=0.1,\n        max_error_vel=0.5,\n    ):\n        gazebo.run()\n\n    # Wait a bit more\n    [gazebo.run() for _ in range(500)]\n\n    # =====================================\n    # PHASE 5: Place the cube in the bucket\n    # =====================================\n\n    print(\"Dropping\")\n\n    # Get the joint configuration that brings the EE over the bucket\n    unload_joint_configuration = solve_ik(\n        target_position=get_unload_position(bucket=bucket),\n        target_orientation=np.array([0, 1.0, 0, 0]),\n        ik=ik,\n    )\n\n    # Set the joint references\n    assert panda.set_joint_position_targets(unload_joint_configuration, ik_joints)\n\n    # Run the simulation until the EE reached the desired position\n    while not end_effector_reached(\n        position=get_unload_position(bucket=bucket)\n        + np.random.uniform(low=-0.05, high=0.05, size=3),\n        end_effector_link=end_effector_frame,\n        max_error_pos=0.01,\n        max_error_vel=0.1,\n        mask=np.array([1, 1, 0]),\n    ):\n\n        gazebo.run()\n\n    # Open the fingers\n    panda.open_fingers()\n\n    # Wait that both fingers are in not contact (with the cube)\n    while finger_left.in_contact() or finger_right.in_contact():\n        gazebo.run()\n\n    # Wait a bit more\n    [gazebo.run() for _ in range(500)]\n\n    # Remove the cube\n    world.remove_model(model_name=cube.name())\n\n# It is always a good practice to close the simulator.\n# In this case it is not required since above there is an infinite loop.\n# gazebo.close()\n"
  },
  {
    "path": "examples/python/launch_cartpole.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport functools\nimport time\n\nimport gym\nfrom gym_ignition.utils import logger\nfrom gym_ignition_environments import randomizers\n\n# Set verbosity\nlogger.set_level(gym.logger.ERROR)\n# logger.set_level(gym.logger.DEBUG)\n\n# Available tasks\nenv_id = \"CartPoleDiscreteBalancing-Gazebo-v0\"\n# env_id = \"CartPoleContinuousBalancing-Gazebo-v0\"\n# env_id = \"CartPoleContinuousSwingup-Gazebo-v0\"\n\n\ndef make_env_from_id(env_id: str, **kwargs) -> gym.Env:\n    import gym\n    import gym_ignition_environments\n\n    return gym.make(env_id, **kwargs)\n\n\n# Create a partial function passing the environment id\nmake_env = functools.partial(make_env_from_id, env_id=env_id)\n\n# Wrap the environment with the randomizer.\n# This is a simple example no randomization are applied.\nenv = randomizers.cartpole_no_rand.CartpoleEnvNoRandomizations(env=make_env)\n\n# Wrap the environment with the randomizer.\n# This is a complex example that randomizes both the physics and the model.\n# env = randomizers.cartpole.CartpoleEnvRandomizer(\n#     env=make_env, seed=42, num_physics_rollouts=5)\n\n# Enable the rendering\n# env.render('human')\n\n# Initialize the seed\nenv.seed(42)\n\nfor epoch in range(10):\n\n    # Reset the environment\n    observation = env.reset()\n\n    # Initialize returned values\n    done = False\n    totalReward = 0\n\n    while not done:\n\n        # Execute a random action\n        action = env.action_space.sample()\n        observation, reward, done, _ = env.step(action)\n\n        # Render the environment.\n        # It is not required to call this in the loop if physics is not randomized.\n        # env.render('human')\n\n        # Accumulate the reward\n        totalReward += reward\n\n        # Print the observation\n        msg = \"\"\n        for value in observation:\n            msg += \"\\t%.6f\" % value\n        logger.debug(msg)\n\n    print(f\"Reward episode #{epoch}: {totalReward}\")\n\nenv.close()\ntime.sleep(5)\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nbuild-backend = \"setuptools.build_meta\"\nrequires = [\n    \"wheel\",\n    \"setuptools>=45\",\n    \"setuptools_scm[toml]>=6.0\",\n    \"cmake-build-extension\",\n]\n\n[tool.setuptools_scm]\nlocal_scheme = \"dirty-tag\"\n\n[tool.black]\nline-length = 88\n\n[tool.isort]\nprofile = \"black\"\nmulti_line_output = 3\n\n"
  },
  {
    "path": "python/gym_ignition/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Workaround for https://github.com/osrf/sdformat/issues/227.\n# It has to be done before loading the bindings.\nimport gym_ignition_models\n\ngym_ignition_models.setup_environment()\n\n# Add IGN_GAZEBO_RESOURCE_PATH to the default search path\nimport os\n\nfrom gym_ignition.utils import resource_finder\n\nif \"IGN_GAZEBO_RESOURCE_PATH\" in os.environ:\n    resource_finder.add_path_from_env_var(\"IGN_GAZEBO_RESOURCE_PATH\")\n\n\ndef initialize_verbosity() -> None:\n\n    import gym\n    import gym_ignition.utils.logger\n\n    import scenario\n\n    if scenario.detect_install_mode() is scenario.InstallMode.Developer:\n        gym_ignition.utils.logger.set_level(\n            level=gym.logger.INFO, scenario_level=gym.logger.WARN\n        )\n\n    elif scenario.detect_install_mode() is scenario.InstallMode.User:\n        gym_ignition.utils.logger.set_level(\n            level=gym.logger.WARN, scenario_level=gym.logger.WARN\n        )\n\n    else:\n        raise ValueError(scenario.detect_install_mode())\n\n\n# Configure default verbosity\ninitialize_verbosity()\n"
  },
  {
    "path": "python/gym_ignition/base/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Abstract classes\nfrom . import runtime, task\n"
  },
  {
    "path": "python/gym_ignition/base/runtime.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\n\nimport gym\nfrom gym_ignition.base.task import Task\n\n\nclass Runtime(gym.Env, abc.ABC):\n    \"\"\"\n    Base class for defining executors of :py:class:`~gym_ignition.base.task.Task` objects.\n\n    :py:class:`~gym_ignition.base.task.Task` classes are supposed to be generic and are\n    not tied to any specific runtime. Implementations of a runtime class contain all the\n    logic to define how to execute the task, allowing to run the same\n    :py:class:`~gym_ignition.base.task.Task` class on different simulators or in a\n    real-time setting.\n\n    Runtimes are the real :py:class:`gym.Env` objects returned to the users when they call\n    the :py:class:`gym.make` factory method.\n\n    Args:\n        task: the :py:class:`~gym_ignition.base.task.Task` object to handle.\n        agent_rate: the rate at which the environment will be called. Sometimes tasks need\n            to know this information.\n\n    Example:\n        Here is minimal example of how the :py:class:`Runtime`, :py:class:`gym.Env` and\n        :py:class:`~gym_ignition.base.task.Task` could be integrated:\n\n    .. code-block:: python\n\n        class FooRuntime(Runtime):\n\n            def __init__(self, task):\n                super().__init__(task=task, agent_rate=agent_rate)\n                self.action_space, self.observation_space = self.task.create_spaces()\n\n            def reset(self):\n                self.task.reset_task()\n                return self.task.get_observation()\n\n            def step(self, action):\n                self.task.set_action(action)\n\n                # [...] code that performs the real step [...]\n\n                done = self.task.is_done()\n                reward = self.task.get_reward()\n                observation = self.task.get_observation()\n\n                return observation, reward, done, {}\n\n            def close(self):\n                pass\n\n    Note:\n        Runtimes can handle only one :py:class:`~gym_ignition.base.task.Task` object.\n    \"\"\"\n\n    def __init__(self, task: Task, agent_rate: float):\n\n        #: Task handled by the runtime.\n        self.task: Task = task\n\n        #: Rate of environment execution.\n        self.agent_rate = agent_rate\n\n    @abc.abstractmethod\n    def timestamp(self) -> float:\n        \"\"\"\n        Return the timestamp associated to the execution of the environment.\n\n        In real-time environments, the timestamp is the time read from the host system.\n        In simulated environments, the timestamp is the simulated time, which might not\n        match the real-time in the case of a real-time factor different than 1.\n\n        Returns:\n            The current environment timestamp.\n        \"\"\"\n"
  },
  {
    "path": "python/gym_ignition/base/task.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Dict, Tuple\n\nimport gym\nimport numpy as np\nfrom gym.utils import seeding\nfrom gym_ignition.utils.typing import (\n    Action,\n    ActionSpace,\n    Observation,\n    ObservationSpace,\n    Reward,\n    SeedList,\n)\n\nfrom scenario import core\n\n\nclass Task(abc.ABC):\n    \"\"\"\n    Interface to define a decision-making task.\n\n    The Task is the central interface of each environment implementation.\n    It defines the logic of the environment in a format that is agnostic of both the\n    runtime (either simulated or real-time) and the models it operates on.\n\n    :py:class:`~gym_ignition.base.runtime.Runtime` instances are the real objects returned\n    to the users when they call :py:class:`gym.make`. Depending on the type of the\n    runtime, it could contain one or more :py:class:`Task` objects.\n    The :py:class:`~gym_ignition.base.runtime.Runtime` is a relay class that calls the\n    logic of the :py:class:`Task` from its interface methods and implements the real\n    :py:meth:`gym.Env.step`.\n    Simulated runtimes step the physics engine, instead, real-time\n    runtimes, enforce real-time execution.\n\n    A :py:class:`Task` object is meant to be:\n\n    - Independent from the selected :py:class:`~gym_ignition.base.runtime.Runtime`.\n      In fact, it defines only the decision making logic;\n    - Independent from the :py:class:`~scenario.core.Model` objects it operates on.\n      This is achieved thanks to the model abstraction provided by\n      :cpp:class:`scenario::core::Model`.\n\n    The population of the world where the task operates is demanded to a\n    :py:class:`gym.Wrapper` object, that acts as an environment randomizer.\n    \"\"\"\n\n    action_space: gym.spaces.Space = None\n    observation_space: gym.spaces.Space = None\n\n    def __init__(self, agent_rate: float) -> None:\n\n        # World object\n        self._world = None\n\n        #: Rate of the agent.\n        #: It matches the rate at which the :py:class:`Gym.Env` methods are called.\n        self.agent_rate = agent_rate\n\n        #: RNG available to the object to ensure reproducibility.\n        #: Use it for all the random resources.\n        self.np_random: np.random.RandomState\n\n        #: The seed of the task\n        self.seed: int\n\n        # Initialize the RNG and the seed\n        self.np_random, self.seed = seeding.np_random()\n\n    # ==========\n    # PROPERTIES\n    # ==========\n\n    @property\n    def world(self) -> core.World:\n        \"\"\"\n        Get the world where the task is operating.\n\n        Returns:\n            The world object.\n        \"\"\"\n\n        if self._world is not None:\n            return self._world\n\n        raise Exception(\"The world was never stored\")\n\n    @world.setter\n    def world(self, world: core.World) -> None:\n\n        if world is None or world.name == \"\":\n            raise ValueError(\"World not valid\")\n\n        # Store the world\n        self._world = world\n\n    def has_world(self) -> bool:\n        \"\"\"\n        Check if the world was stored.\n\n        Returns:\n            True if the task has a valid world, False otherwise.\n        \"\"\"\n\n        return self._world is not None and self._world.name != \"\"\n\n    # ==============\n    # Task Interface\n    # ==============\n\n    @abc.abstractmethod\n    def create_spaces(self) -> Tuple[ActionSpace, ObservationSpace]:\n        \"\"\"\n        Create the action and observations spaces.\n\n        Note:\n            This method does not currently have access to the Models part of the\n            environment. If the Task is meant to work on different models, we recommend\n            using their URDF / SDF model to extract the information you need\n            (e.g. number of DoFs, joint position limits, etc). Since actions and\n            observations are often normalized, in many cases there's no need to extract\n            a lot of information from the model file.\n\n        Raises:\n            RuntimeError: In case of failure.\n\n        Returns:\n            A tuple containing the action and observation spaces.\n        \"\"\"\n\n    @abc.abstractmethod\n    def reset_task(self) -> None:\n        \"\"\"\n        Reset the task.\n\n        This method contains the logic for resetting the task.\n        It is called in the :py:meth:`gym.Env.reset` method of the corresponding\n        environment.\n\n        Raises:\n            RuntimeError: In case of failure.\n        \"\"\"\n\n    @abc.abstractmethod\n    def set_action(self, action: Action) -> None:\n        \"\"\"\n        Set the task action.\n\n        This method contains the logic for setting the environment action.\n        It is called in the beginning of the :py:meth:`gym.Env.step` method.\n\n        Args:\n            action: The action to set.\n\n        Raises:\n            RuntimeError: In case of failure.\n        \"\"\"\n\n    @abc.abstractmethod\n    def get_observation(self) -> Observation:\n        \"\"\"\n        Return the task observation.\n\n        This method contains the logic for constructing the environment observation.\n        It is called in the end of both :py:meth:`gym.Env.reset` and\n        :py:meth:`gym.Env.step` methods.\n\n        Raises:\n            RuntimeError: In case of failure.\n\n        Returns:\n            The task observation.\n        \"\"\"\n\n    @abc.abstractmethod\n    def get_reward(self) -> Reward:\n        \"\"\"\n        Return the task reward.\n\n        This method contains the logic for computing the environment reward.\n        It is called in the end of the :py:meth:`gym.Env.step` method.\n\n        Raises:\n            RuntimeError: In case of failure.\n\n        Returns:\n            The scalar reward.\n        \"\"\"\n\n    @abc.abstractmethod\n    def is_done(self) -> bool:\n        \"\"\"\n        Return the task termination flag.\n\n        This method contains the logic for defining when the environment has terminated.\n        Subsequent calls to :py:meth:`Task.set_action` should be preceded by a task\n        reset through :py:meth:`Task.reset_task`.\n\n        It is called in the end of the :py:meth:`gym.Env.step` method.\n\n        Raises:\n            RuntimeError: In case of failure.\n\n        Returns:\n            True if the environment terminated, False otherwise.\n        \"\"\"\n\n    def get_info(self) -> Dict:\n        \"\"\"\n        Return the info dictionary.\n\n        Returns:\n            A ``dict`` with extra information of the task.\n        \"\"\"\n        return {}\n\n    def seed_task(self, seed: int = None) -> SeedList:\n        \"\"\"\n        Seed the task.\n\n        This method configures the :py:attr:`Task.np_random` RNG.\n\n        Args:\n            seed: The seed number.\n\n        Return:\n            The list of seeds used by the task.\n        \"\"\"\n\n        # Create the seed if not passed\n        seed = np.random.randint(2 ** 32 - 1) if seed is None else seed\n\n        # Get an instance of the random number generator from gym utils.\n        # This is necessary to have an independent rng for each environment.\n        self.np_random, self.seed = seeding.np_random(seed)\n\n        # Seed the spaces\n        self.action_space.seed(self.seed)\n        self.observation_space.seed(self.seed)\n\n        return SeedList([self.seed])\n"
  },
  {
    "path": "python/gym_ignition/context/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import gazebo\n"
  },
  {
    "path": "python/gym_ignition/context/gazebo/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import controllers, plugin\n"
  },
  {
    "path": "python/gym_ignition/context/gazebo/controllers.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom dataclasses import dataclass, field\nfrom typing import Iterable, List, Tuple\n\nfrom gym_ignition.context.gazebo import plugin\n\nGRAVITY = (0, 0, -9.80665)\n\n\n@dataclass\nclass ComputedTorqueFixedBase(plugin.GazeboPlugin):\n\n    urdf: str\n    kp: List[float]\n    ki: List[float]\n    kd: List[float]\n    joints: List[str]\n    gravity: Tuple[float, float, float] = field(default_factory=lambda: GRAVITY)\n\n    # Private fields\n    _name: str = field(init=False, repr=False, default=\"ComputedTorqueFixedBase\")\n    _plugin_name: str = field(init=False, repr=False, default=\"ControllerRunner\")\n    _plugin_class: str = field(\n        init=False, repr=False, default=\"scenario::plugins::gazebo::ControllerRunner\"\n    )\n\n    def to_xml(self) -> str:\n        xml = f\"\"\"\n        <controller name=\"{self._name}\">\n            <kp>{self._to_str(self.kp)}</kp>\n            <ki>{self._to_str(self.ki)}</ki>\n            <kd>{self._to_str(self.kd)}</kd>\n            <urdf>{self.urdf}</urdf>\n            <joints>{self._to_str(self.joints)}</joints>\n            <gravity>{self._to_str(self.gravity)}</gravity>\n        </controller>\n        \"\"\"\n\n        return xml\n\n    @staticmethod\n    def _to_str(iterable: Iterable) -> str:\n\n        return \" \".join([str(el) for el in iterable])\n"
  },
  {
    "path": "python/gym_ignition/context/gazebo/plugin.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom dataclasses import dataclass, field\nfrom typing import Tuple\n\n# Default SDF version used in the serialized XML context\nSDF_VERSION = 1.7\n\n# Read the following for more information about dataclasses internals:\n# https://florimond.dev/blog/articles/2018/10/reconciling-dataclasses-and-properties-in-python/\n\n\n@dataclass\nclass GazeboPlugin(abc.ABC):\n    \"\"\"\n    Base class of all World and Model plugins for Ignition Gazebo.\n\n    The Plugin abstract class provides boilerplate code that simplifies and streamlines\n    the definition of helper classes that insert Ignition Gazebo plugins to either World\n    or Model objects.\n\n    Classes that inherit from Plugin have to provide the following information:\n\n    1) All the properties of the plugin as dataclass fields\n    2) The private specification of the plugin (plugin name and plugin class)\n    3) Optionally: the serialized XML context\n\n    Example:\n\n    .. code-block:: python\n\n        plugin = MyPlugin(my_property=42)\n        model = MyModel(world=my_world)\n\n        model.insert_model_plugin(*plugin.args())\n    \"\"\"\n\n    _plugin_name: str = field(init=False, repr=False)\n    _plugin_class: str = field(init=False, repr=False)\n\n    def to_xml(self) -> str:\n        \"\"\"\n        Get the XML plugin content.\n\n        Returns:\n            The XML plugin content.\n        \"\"\"\n        return \"\"\n\n    def args(self) -> Tuple[str, str, str]:\n        \"\"\"\n        Get the arguments passed to the ScenarI/O methods used to insert plugins.\n\n        Returns:\n            A tuple with the args required to insert the plugin.\n        \"\"\"\n        return (\n            str(self._plugin_name),\n            str(self._plugin_class),\n            GazeboPlugin.wrap_in_sdf(self.to_xml()),\n        )\n\n    @staticmethod\n    def wrap_in_sdf(context: str) -> str:\n        \"\"\"\n        Wrap the XML context inside a SDF root.\n\n        Args:\n            context: The XML string with the plugin's context.\n\n        Returns:\n            The plugin's context wrapped inside a SDF root.\n        \"\"\"\n\n        return f\"\"\"<sdf version='{SDF_VERSION}'>{context}</sdf>\"\"\"\n"
  },
  {
    "path": "python/gym_ignition/randomizers/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import abc, gazebo_env_randomizer, model, physics\n"
  },
  {
    "path": "python/gym_ignition/randomizers/abc.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\n\nimport gym_ignition.base.task\n\nfrom scenario import core as scenario_core\n\n\nclass TaskRandomizer(abc.ABC):\n    @abc.abstractmethod\n    def randomize_task(self, task: gym_ignition.base.task.Task, **kwargs) -> None:\n        \"\"\"\n        Randomize a :py:class:`~gym_ignition.base.task.Task` instance.\n\n        Args:\n            task: the task to randomize.\n\n        Note:\n            Note that each task has a :py:attr:`~gym_ignition.base.task.Task.world`\n            property that provides access to the simulated\n            :py:class:`scenario.bindings.core.World`.\n        \"\"\"\n        pass\n\n\nclass PhysicsRandomizer(abc.ABC):\n    \"\"\"\n    Abstract class that provides the machinery for randomizing the physics of a Task.\n\n    Args:\n        randomize_after_rollouts_num: defines after many rollouts physics should be\n            randomized (i.e. the amount of times :py:meth:`gym.Env.reset` is called).\n    \"\"\"\n\n    def __init__(self, randomize_after_rollouts_num: int = 0):\n\n        self._rollout_counter = randomize_after_rollouts_num\n        self.randomize_after_rollouts_num = randomize_after_rollouts_num\n\n    @abc.abstractmethod\n    def randomize_physics(self, task: gym_ignition.base.task.Task, **kwargs) -> None:\n        \"\"\"\n        Method that insert and configures the physics of a Task's world.\n\n        By default this method loads a plugin that uses DART with no randomizations.\n        Randomizing physics engine parameters or changing physics engine backend could be\n        done by redefining this method and passing it to\n        :py:class:`~gym_ignition.runtimes.gazebo_runtime.GazeboRuntime`.\n\n        Args:\n            task: A task containing a world object without physics.\n        \"\"\"\n        pass\n\n    @abc.abstractmethod\n    def get_engine(self):\n        \"\"\"\n        Return the physics engine to use for the rollout.\n\n        Note:\n\n            Supported physics engines:\n\n            - :py:const:`scenario.bindings.gazebo.PhysicsEngine_dart`\n\n        Return:\n            The desired physics engine to set in the world.\n        \"\"\"\n\n        pass\n\n    def increase_rollout_counter(self) -> None:\n        \"\"\"\n        Increase the rollouts counter.\n        \"\"\"\n\n        if self.randomize_after_rollouts_num != 0:\n            assert self._rollout_counter != 0\n            self._rollout_counter -= 1\n\n    def physics_expired(self) -> bool:\n        \"\"\"\n        Checks if the physics needs to be randomized.\n\n        Return:\n            True if the physics has expired, false otherwise.\n        \"\"\"\n\n        if self.randomize_after_rollouts_num == 0:\n            return False\n\n        if self._rollout_counter == 0:\n            self._rollout_counter = self.randomize_after_rollouts_num\n            return True\n\n        return False\n\n\nclass ModelRandomizer(abc.ABC):\n    @abc.abstractmethod\n    def randomize_model(\n        self, task: gym_ignition.base.task.Task, **kwargs\n    ) -> scenario_core.Model:\n        \"\"\"\n        Randomize the model.\n\n        Args:\n            task: The task that operates on the model to randomize.\n\n        Return:\n            The randomized model.\n        \"\"\"\n        pass\n\n\nclass ModelDescriptionRandomizer(abc.ABC):\n    @abc.abstractmethod\n    def randomize_model_description(\n        self, task: gym_ignition.base.task.Task, **kwargs\n    ) -> str:\n        \"\"\"\n        Randomize the model description.\n\n        Args:\n            task: The task that operates on the model description to randomize.\n\n        Return:\n            A string with the randomized model description.\n        \"\"\"\n        pass\n"
  },
  {
    "path": "python/gym_ignition/randomizers/gazebo_env_randomizer.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Callable, Dict, Optional, Union, cast\n\nimport gym\nfrom gym_ignition.randomizers.abc import PhysicsRandomizer, TaskRandomizer\nfrom gym_ignition.randomizers.physics import dart\nfrom gym_ignition.runtimes import gazebo_runtime\nfrom gym_ignition.utils import typing\n\nMakeEnvCallable = Callable[[Optional[Dict]], gym.Env]\n\n\nclass GazeboEnvRandomizer(gym.Wrapper, TaskRandomizer, abc.ABC):\n    \"\"\"\n    Base class to implement an environment randomizer for Ignition Gazebo.\n\n    The randomizer is a :py:class:`gym.Wrapper` that extends the\n    :py:meth:`gym.Env.reset` method. Objects that inherit from this class are used to\n    setup the environment for the handled :py:class:`~gym_ignition.base.task.Task`.\n\n    In its simplest form, a randomizer populates the world with all the models that need\n    to be part of the simulation. The task could then operate on them from a\n    :py:class:`~scenario.core.Model` object.\n\n    More complex environments may require to randomize one or more simulated entities.\n    Concrete classes that implement a randomizer could use\n    :py:class:`~gym_ignition.randomizers.model.sdf.SDFRandomizer` to randomize the model\n    and :py:class:`~gym_ignition.randomizers.abc.PhysicsRandomizer` to randomize\n    the physics.\n\n    Args:\n        env: Defines the environment to handle. This argument could be either the string\n            id if the environment does not need to be registered or a function that\n            returns an environment object.\n        physics_randomizer: Object that randomizes physics. The default physics engine is\n            DART with no randomizations.\n\n    Note:\n        In order to randomize physics, the handled\n        :py:class:`scenario.gazebo.GazeboSimulator` is destroyed and created again.\n        This operation is demanding, consider randomizing physics at a low rate.\n    \"\"\"\n\n    def __init__(\n        self,\n        env: Union[str, MakeEnvCallable],\n        physics_randomizer: PhysicsRandomizer = dart.DART(),\n        **kwargs,\n    ):\n\n        # Print the extra kwargs\n        gym.logger.debug(f\"GazeboEnvRandomizer: {dict(kwargs=kwargs)}\")\n\n        # Store the options\n        self._env_option = env\n        self._kwargs = dict(**kwargs, physics_engine=physics_randomizer.get_engine())\n\n        # Create the environment\n        env_to_wrap = self._create_environment(env=self._env_option, **self._kwargs)\n\n        # Initialize the wrapper\n        gym.Wrapper.__init__(self, env=env_to_wrap)\n\n        # Store the physics randomizer\n        self._physics_randomizer = physics_randomizer\n\n    # ===============\n    # gym.Env methods\n    # ===============\n\n    def reset(self, **kwargs) -> typing.Observation:\n\n        # Reset the physics\n        if self._physics_randomizer.physics_expired():\n\n            # Get the random components of the task\n            seed = self.env.task.seed\n            np_random = self.env.task.np_random\n\n            # Reset the runtime + task, creating a new Gazebo instance\n            self.env.close()\n            del self.env\n            self.env = self._create_environment(self._env_option, **self._kwargs)\n\n            # Restore the random components\n            self.env.seed(seed=seed)\n            assert self.env.task.seed == seed\n            self.env.task.np_random = np_random\n\n        # Mark the beginning of a new rollout\n        self._physics_randomizer.increase_rollout_counter()\n\n        # Reset the task through the TaskRandomizer\n        self.randomize_task(task=self.env.task, gazebo=self.env.gazebo, **kwargs)\n\n        ok_paused_run = self.env.gazebo.run(paused=True)\n\n        if not ok_paused_run:\n            raise RuntimeError(\"Failed to execute a paused Gazebo run\")\n\n        # Reset the Task\n        return self.env.reset()\n\n    # ===============\n    # Private methods\n    # ===============\n\n    def _create_environment(\n        self, env: Union[str, MakeEnvCallable], **kwargs\n    ) -> gazebo_runtime.GazeboRuntime:\n\n        if isinstance(env, str):\n            env_to_wrap = self._create_from_id(env_id=env, **kwargs)\n\n        elif callable(env):\n            env_to_wrap = self._create_from_callable(make_env=env, **kwargs)\n\n        else:\n            raise ValueError(\"The type of env object was not recognized\")\n\n        if not isinstance(env_to_wrap.unwrapped, gazebo_runtime.GazeboRuntime):\n            raise ValueError(\"The environment to wrap is not a GazeboRuntime\")\n\n        return cast(gazebo_runtime.GazeboRuntime, env_to_wrap)\n\n    @staticmethod\n    def _create_from_callable(make_env: MakeEnvCallable, **kwargs) -> gym.Env:\n\n        env = make_env(**kwargs)\n        return env\n\n    @staticmethod\n    def _create_from_id(env_id: str, **kwargs) -> gym.Env:\n\n        env = gym.make(env_id, **kwargs)\n        return env\n"
  },
  {
    "path": "python/gym_ignition/randomizers/model/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import sdf\n"
  },
  {
    "path": "python/gym_ignition/randomizers/model/sdf.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom enum import Enum, auto\nfrom pathlib import Path\nfrom typing import Dict, List, NamedTuple, Union\n\nimport numpy as np\nfrom lxml import etree\n\n\nclass Distribution(Enum):\n    Uniform = auto()\n    Gaussian = auto()\n\n\nclass Method(Enum):\n    Absolute = auto()\n    Additive = auto()\n    Coefficient = auto()\n\n\nclass RandomizationData(NamedTuple):\n    xpath: str\n    distribution: str\n    parameters: \"DistributionParameters\"\n    method: Method\n    ignore_zeros: bool = False\n    force_positive: bool = False\n    element: etree.Element = None\n\n\nclass GaussianParams(NamedTuple):\n    variance: float\n    mean: float = None\n\n\nclass UniformParams(NamedTuple):\n    low: float\n    high: float\n\n\nDistributionParameters = Union[UniformParams, GaussianParams]\n\n\nclass RandomizationDataBuilder:\n    \"\"\"\n    Builder class of a :py:class:`~gym_ignition.randomizers.model.sdf.RandomizationData`\n    object.\n\n    Args:\n        randomizer: The :py:class:`~gym_ignition.randomizers.model.sdf.SDFRandomizer`\n            object to which the created randomization will be inserted.\n    \"\"\"\n\n    def __init__(self, randomizer: \"SDFRandomizer\"):\n\n        self.storage: Dict = {}\n        self.randomizer = randomizer\n\n    def at_xpath(self, xpath: str) -> \"RandomizationDataBuilder\":\n        \"\"\"\n        Set the XPath pattern associated to the randomization.\n\n        Args:\n            xpath: The XPath pattern.\n\n        Returns:\n            The randomization builder to allow chaining methods.\n        \"\"\"\n        self.storage[\"xpath\"] = xpath\n        return self\n\n    def sampled_from(\n        self, distribution: Distribution, parameters: DistributionParameters\n    ) -> \"RandomizationDataBuilder\":\n        \"\"\"\n        Set the distribution associated to the randomization.\n\n        Args:\n            distribution: The desired distribution.\n            parameters: The namedtuple with the parameters of the distribution.\n\n        Returns:\n            The randomization builder to allow chaining methods.\n        \"\"\"\n\n        self.storage[\"distribution\"] = distribution\n        self.storage[\"parameters\"] = parameters\n\n        if self.storage[\"distribution\"] is Distribution.Gaussian and not isinstance(\n            parameters, GaussianParams\n        ):\n            raise ValueError(\"Wrong parameters type\")\n\n        if self.storage[\"distribution\"] is Distribution.Uniform and not isinstance(\n            parameters, UniformParams\n        ):\n            raise ValueError(\"Wrong parameters type\")\n\n        return self\n\n    def method(self, method: Method) -> \"RandomizationDataBuilder\":\n        \"\"\"\n        Set the randomization method.\n\n        Args:\n            method: The desired randomization method.\n\n        Returns:\n            The randomization builder to allow chaining methods.\n        \"\"\"\n\n        self.storage[\"method\"] = method\n        return self\n\n    def ignore_zeros(self, ignore_zeros: bool) -> \"RandomizationDataBuilder\":\n        \"\"\"\n        Ignore the randomization of values that are zero.\n\n        If the value to randomize has a default value of 0 in the SDF, when this method\n        is chained the randomization is skipped. In the case of a multi-match XPath\n        pattern, the values that are not zero are not skipped.\n\n        Args:\n            ignore_zeros: True if zeros should be ignored, false otherwise.\n\n        Returns:\n            The randomization builder to allow chaining methods.\n        \"\"\"\n\n        self.storage[\"ignore_zeros\"] = ignore_zeros\n        return self\n\n    def force_positive(self, force_positive: bool = True) -> \"RandomizationDataBuilder\":\n        \"\"\"\n        Force the randomized value to be greater than zero.\n\n        This option is helpful to enforce that values e.g. the mass will stay positive\n        regardless of the applied distribution parameters.\n\n        Args:\n            force_positive: True to force positive parameters, false otherwise.\n\n        Returns:\n            The randomization builder to allow chaining methods.\n        \"\"\"\n\n        self.storage[\"force_positive\"] = force_positive\n        return self\n\n    def add(self) -> None:\n        \"\"\"\n        Close the chaining of methods and return to the SDF randomizer the configuration.\n\n        Raises:\n            RuntimeError: If the XPath pattern does not find any match in the SDF.\n        \"\"\"\n\n        data = RandomizationData(**self.storage)\n\n        if len(self.randomizer.find_xpath(data.xpath)) == 0:\n            raise RuntimeError(f\"Failed to find element matching XPath '{data.xpath}'\")\n\n        self.randomizer.insert(randomization_data=data)\n\n\nclass SDFRandomizer:\n    \"\"\"\n    Randomized SDF files generator.\n\n    Args:\n        sdf_model: The absolute path to the SDF file.\n\n    Raises:\n       ValueError: If the SDF file does not exist.\n    \"\"\"\n\n    def __init__(self, sdf_model: str):\n\n        self._sdf_file = sdf_model\n\n        if not Path(self._sdf_file).is_file():\n            raise ValueError(f\"File '{sdf_model}' does not exist\")\n\n        # Initialize the root\n        tree = self._get_tree_from_file(self._sdf_file)\n        self._root: etree.Element = tree.getroot()\n\n        # List of randomizations\n        self._randomizations: List[RandomizationData] = []\n\n        # List of default values used with Method.Coefficient\n        self._default_values: Dict[etree.Element, float] = {}\n\n        # Store an independent RNG\n        self.rng = np.random.default_rng()\n\n    def seed(self, seed: int) -> None:\n        \"\"\"\n        Seed the SDF randomizer.\n\n        Args:\n            seed: The seed number.\n        \"\"\"\n        self.rng = np.random.default_rng(seed)\n\n    def find_xpath(self, xpath: str) -> List[etree.Element]:\n        \"\"\"\n        Find the elements that match an XPath pattern.\n\n        This method could be helpful to test the matches of a XPath pattern before using\n        it in :py:meth:`~gym_ignition.randomizers.model.sdf.RandomizationDataBuilder.at_xpath`.\n\n        Args:\n            xpath: The XPath pattern.\n\n        Return:\n            A list of elements matching the XPath pattern.\n        \"\"\"\n        return self._root.findall(xpath)\n\n    def process_data(self) -> None:\n        \"\"\"\n        Process all the inserted randomizations.\n\n        Raises:\n            RuntimeError: If the XPath of a randomization has no matches.\n        \"\"\"\n\n        # Since we support multi-match XPaths, we expand all the individual matches\n        expanded_randomizations = []\n\n        for data in self._randomizations:\n\n            # Find all the matches\n            elements: List[etree.Element] = self._root.findall(path=data.xpath)\n\n            if len(elements) == 0:\n                raise RuntimeError(f\"Failed to find elements from XPath '{data.xpath}'\")\n\n            for element in elements:\n\n                if data.ignore_zeros and float(self._get_element_text(element)) == 0:\n                    continue\n\n                # Get the precise XPath to the element\n                element_xpath = element.getroottree().getpath(element)\n\n                # Get the parameters\n                params = data.parameters\n\n                if data.method in {Method.Additive, Method.Coefficient}:\n                    element_text = float(self._get_element_text(element))\n                    self._default_values[element] = element_text\n\n                # Update the data\n                complete_data = data._replace(\n                    xpath=element_xpath, element=element, parameters=params\n                )\n\n                expanded_randomizations.append(complete_data)\n\n        # Store the updated data\n        self._randomizations = expanded_randomizations\n\n    def sample(self, pretty_print=False) -> str:\n        \"\"\"\n        Sample a randomized SDF string.\n\n        Args:\n            pretty_print: True to pretty print the output.\n\n        Raises:\n            ValueError: If the distribution of a randomization is not recognized.\n            ValueError: If the method of a randomization is not recognized.\n\n        Returns:\n            The randomized model as SDF string.\n        \"\"\"\n\n        for data in self._randomizations:\n\n            if data.distribution is Distribution.Gaussian:\n\n                sample = self.rng.normal(\n                    loc=data.parameters.mean, scale=data.parameters.variance\n                )\n\n            elif data.distribution is Distribution.Uniform:\n\n                sample = self.rng.uniform(\n                    low=data.parameters.low, high=data.parameters.high\n                )\n\n            else:\n                raise ValueError(\"Distribution not recognized\")\n\n            # Update the value\n            if data.method is Method.Absolute:\n\n                data.element.text = str(sample)\n\n            elif data.method is Method.Additive:\n\n                default_value = self._default_values[data.element]\n                data.element.text = str(sample + default_value)\n\n            elif data.method is Method.Coefficient:\n\n                default_value = self._default_values[data.element]\n                data.element.text = str(sample * default_value)\n\n            else:\n                raise ValueError(\"Method not recognized\")\n\n            if data.force_positive:\n                data.element.text = str(max(float(data.element.text), 0.0))\n\n        return etree.tostring(self._root, pretty_print=pretty_print).decode()\n\n    def new_randomization(self) -> RandomizationDataBuilder:\n        \"\"\"\n        Start the chaining to build a new randomization.\n\n        Return:\n            A randomization builder.\n        \"\"\"\n        return RandomizationDataBuilder(randomizer=self)\n\n    def insert(self, randomization_data) -> None:\n        \"\"\"\n        Insert a randomization.\n\n        Args:\n            randomization_data: A new randomization.\n        \"\"\"\n        self._randomizations.append(randomization_data)\n\n    def get_active_randomizations(self) -> List[RandomizationData]:\n        \"\"\"\n        Return the active randomizations.\n\n        This method could be helpful also in the case of multi-match XPath patterns to\n        validate that the inserted randomizations have been processed correctly.\n\n        Returns:\n            The list of the active randomizations.\n        \"\"\"\n        return self._randomizations\n\n    def clean(self) -> None:\n        \"\"\"\n        Clean the SDF randomizer.\n        \"\"\"\n\n        self._randomizations = []\n        self._default_values = {}\n\n        tree = self._get_tree_from_file(self._sdf_file)\n        self._root = tree.getroot()\n\n    @staticmethod\n    def _get_tree_from_file(xml_file) -> etree.ElementTree:\n\n        parser = etree.XMLParser(remove_blank_text=True)\n        tree = etree.parse(source=xml_file, parser=parser)\n\n        return tree\n\n    @staticmethod\n    def _get_element_text(element: etree.Element) -> str:\n\n        text = element.text\n\n        if text is None:\n            raise RuntimeError(f\"The element {element.tag} does not have any content\")\n\n        return text\n"
  },
  {
    "path": "python/gym_ignition/randomizers/physics/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import dart\n"
  },
  {
    "path": "python/gym_ignition/randomizers/physics/dart.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport gym_ignition.base.task\nfrom gym_ignition import randomizers\n\nfrom scenario import gazebo as scenario\n\n\nclass DART(randomizers.abc.PhysicsRandomizer):\n    \"\"\"\n    Class that configures the Gazebo World of a Task to use the DART physics engine.\n\n    Note:\n        This class does not apply any physics randomization.\n    \"\"\"\n\n    def __init__(self):\n\n        super().__init__()\n\n    def get_engine(self):\n\n        return scenario.PhysicsEngine_dart\n\n    def randomize_physics(self, task: gym_ignition.base.task.Task, **kwargs) -> None:\n\n        pass\n"
  },
  {
    "path": "python/gym_ignition/rbd/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import conversions, idyntree, utils\n"
  },
  {
    "path": "python/gym_ignition/rbd/conversions.py",
    "content": "import abc\nfrom typing import Tuple\n\nimport numpy as np\nfrom scipy.spatial.transform import Rotation\n\n\nclass Transform(abc.ABC):\n    @staticmethod\n    def from_position_and_quaternion(\n        position: np.ndarray, quaternion: np.ndarray\n    ) -> np.ndarray:\n\n        if quaternion.size != 4:\n            raise ValueError(\"Quaternion array must have 4 elements\")\n\n        rotation = Quaternion.to_rotation(quaternion)\n        transform = Transform.from_position_and_rotation(\n            position=position, rotation=rotation\n        )\n\n        return transform\n\n    @staticmethod\n    def from_position_and_rotation(\n        position: np.ndarray, rotation: np.ndarray\n    ) -> np.ndarray:\n\n        if position.size != 3:\n            raise ValueError(\"Position array must have 3 elements\")\n\n        if rotation.shape != (3, 3):\n            raise ValueError(\"Rotation must be a square 3x3 matrix\")\n\n        transform = np.eye(4)\n        transform[0:3, 3] = position\n        transform[0:3, 0:3] = rotation\n\n        return transform\n\n    @staticmethod\n    def to_position_and_rotation(\n        transform: np.ndarray,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n\n        if transform.shape != (4, 4):\n            raise ValueError(\"Transform must be a 4x4 matrix\")\n\n        position = transform[0:3, 3]\n        rotation = transform[0:3, 0:3]\n\n        return position, rotation\n\n    @staticmethod\n    def to_position_and_quaternion(\n        transform: np.ndarray,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n\n        p, R = Transform.to_position_and_rotation(transform=transform)\n        return p, Quaternion.from_matrix(matrix=R)\n\n\nclass Quaternion(abc.ABC):\n    @staticmethod\n    def to_wxyz(xyzw: np.ndarray) -> np.ndarray:\n\n        if xyzw.shape != (4,):\n            raise ValueError(xyzw)\n\n        return xyzw[[3, 0, 1, 2]]\n\n    @staticmethod\n    def to_xyzw(wxyz: np.ndarray) -> np.ndarray:\n\n        if wxyz.shape != (4,):\n            raise ValueError(wxyz)\n\n        return wxyz[[1, 2, 3, 0]]\n\n    @staticmethod\n    def to_rotation(quaternion: np.ndarray) -> np.ndarray:\n\n        if quaternion.shape != (4,):\n            raise ValueError(quaternion)\n\n        xyzw = Quaternion.to_xyzw(quaternion)\n\n        return Rotation.from_quat(xyzw).as_matrix()\n\n    @staticmethod\n    def from_matrix(matrix: np.ndarray) -> np.ndarray:\n\n        if matrix.shape != (3, 3):\n            raise ValueError(matrix)\n\n        quaternion_xyzw = Rotation.from_matrix(matrix).as_quat()\n        quaternion_wxyz = Quaternion.to_wxyz(quaternion_xyzw)\n\n        return quaternion_wxyz\n"
  },
  {
    "path": "python/gym_ignition/rbd/idyntree/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import helpers, inverse_kinematics_nlp, kindyncomputations, numpy\n"
  },
  {
    "path": "python/gym_ignition/rbd/idyntree/helpers.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nimport os\nfrom enum import Enum, auto\nfrom typing import List\n\nimport idyntree.bindings as idt\nfrom gym_ignition.utils import resource_finder\n\n\nclass FrameVelocityRepresentation(Enum):\n\n    MIXED_REPRESENTATION = auto()\n    BODY_FIXED_REPRESENTATION = auto()\n    INERTIAL_FIXED_REPRESENTATION = auto()\n\n    def to_idyntree(self):\n\n        if self.value == FrameVelocityRepresentation.MIXED_REPRESENTATION.value:\n            return idt.MIXED_REPRESENTATION\n        elif self.value == FrameVelocityRepresentation.BODY_FIXED_REPRESENTATION.value:\n            return idt.BODY_FIXED_REPRESENTATION\n        elif (\n            self.value\n            == FrameVelocityRepresentation.INERTIAL_FIXED_REPRESENTATION.value\n        ):\n            return idt.INERTIAL_FIXED_REPRESENTATION\n        else:\n            raise ValueError(self.value)\n\n\nclass iDynTreeHelpers(abc.ABC):\n    @staticmethod\n    def get_model_loader(model_file: str, considered_joints: List[str] = None):\n\n        # Find the urdf file\n        urdf_file = resource_finder.find_resource(file_name=model_file)\n\n        # Get the file extension\n        folder, model_file = os.path.split(urdf_file)\n        model_name, extension = os.path.splitext(model_file)\n\n        if extension == \".sdf\":\n            raise RuntimeError(\"SDF models are not currently supported by iDynTree\")\n\n        # Create the model loader\n        mdl_loader = idt.ModelLoader()\n\n        # Load the urdf model\n        if considered_joints is None:\n            ok_load = mdl_loader.loadModelFromFile(urdf_file)\n        else:\n            ok_load = mdl_loader.loadReducedModelFromFile(urdf_file, considered_joints)\n\n        if not ok_load:\n            raise RuntimeError(f\"Failed to load model from file '{urdf_file}'\")\n\n        return mdl_loader\n\n    @staticmethod\n    def get_kindyncomputations(\n        model_file: str,\n        considered_joints: List[str] = None,\n        velocity_representation: FrameVelocityRepresentation = FrameVelocityRepresentation.MIXED_REPRESENTATION,\n    ):\n\n        # Get the model loader\n        model_loader = iDynTreeHelpers.get_model_loader(model_file, considered_joints)\n\n        # Create KinDynComputations and insert the model\n        kindyn = idt.KinDynComputations()\n        ok_load = kindyn.loadRobotModel(model_loader.model())\n\n        if not ok_load:\n            raise RuntimeError(\"Failed to load model\")\n\n        # Configure the velocity representation\n        velocity_representation_idyntree = velocity_representation.to_idyntree()\n        ok_repr = kindyn.setFrameVelocityRepresentation(\n            velocity_representation_idyntree\n        )\n\n        if not ok_repr:\n            raise RuntimeError(\"Failed to set the velocity representation\")\n\n        return kindyn\n"
  },
  {
    "path": "python/gym_ignition/rbd/idyntree/inverse_kinematics_nlp.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport os\nfrom dataclasses import dataclass\nfrom enum import Enum, auto\nfrom typing import Dict, List, Optional, Tuple, Union\n\nimport idyntree.bindings as idt\nimport numpy as np\nfrom gym_ignition import rbd\n\n\nclass TargetType(Enum):\n\n    POSITION = auto()\n    ROTATION = auto()\n    POSE = auto()\n\n\n@dataclass\nclass TransformTargetData:\n\n    position: np.ndarray\n    quaternion: np.ndarray\n\n\n@dataclass\nclass TargetData:\n\n    type: TargetType\n    weight: Union[float, Tuple[float, float]]\n    data: Union[np.ndarray, TransformTargetData]\n\n\n@dataclass\nclass IKSolution:\n\n    joint_configuration: np.ndarray\n    base_position: np.ndarray = np.array([0.0, 0.0, 0.0])\n    base_quaternion: np.ndarray = np.array([1.0, 0.0, 0.0, 0.0])\n\n\nclass RotationParametrization(Enum):\n\n    QUATERNION = auto()\n    ROLL_PITCH_YAW = auto()\n\n    def to_idyntree(self):\n\n        if self.value == RotationParametrization.QUATERNION.value:\n            return idt.InverseKinematicsRotationParametrizationQuaternion\n\n        elif self.value == RotationParametrization.ROLL_PITCH_YAW.value:\n            return idt.InverseKinematicsRotationParametrizationRollPitchYaw\n\n        else:\n            raise ValueError(self.value)\n\n\nclass TargetResolutionMode(Enum):\n\n    TARGET_AS_CONSTRAINT_FULL = auto()\n    TARGET_AS_CONSTRAINT_NONE = auto()\n    TARGET_AS_CONSTRAINT_POSITION = auto()\n    TARGET_AS_CONSTRAINT_ROTATION = auto()\n\n    def to_idyntree(self):\n\n        if self.value == TargetResolutionMode.TARGET_AS_CONSTRAINT_FULL.value:\n            return idt.InverseKinematicsTreatTargetAsConstraintFull\n\n        elif self.value == TargetResolutionMode.TARGET_AS_CONSTRAINT_NONE.value:\n            return idt.InverseKinematicsTreatTargetAsConstraintNone\n\n        elif self.value == TargetResolutionMode.TARGET_AS_CONSTRAINT_POSITION.value:\n            return idt.InverseKinematicsTreatTargetAsConstraintPositionOnly\n\n        elif self.value == TargetResolutionMode.TARGET_AS_CONSTRAINT_ROTATION.value:\n            return idt.InverseKinematicsTreatTargetAsConstraintRotationOnly\n\n        else:\n            raise ValueError(self.value)\n\n\nclass InverseKinematicsNLP:\n    def __init__(\n        self,\n        urdf_filename: str,\n        considered_joints: List[str] = None,\n        joint_serialization: List[str] = None,\n    ) -> None:\n\n        self._floating_base: bool = False\n        self._base_frame: Optional[str] = None\n        self._urdf_filename: str = urdf_filename\n        self._targets_data: Dict[str, TargetData] = dict()\n        self._ik: Optional[idt.InverseKinematics] = None\n\n        self._considered_joints: List[str] = considered_joints\n        self._joint_serialization: List[str] = joint_serialization\n\n    # ======================\n    # INITIALIZATION METHODS\n    # ======================\n\n    def initialize(\n        self,\n        rotation_parametrization: RotationParametrization = RotationParametrization.ROLL_PITCH_YAW,\n        target_mode: TargetResolutionMode = TargetResolutionMode.TARGET_AS_CONSTRAINT_NONE,\n        cost_tolerance: float = 1e-08,\n        constraints_tolerance: float = 1e-4,\n        max_iterations: int = 1000,\n        base_frame: str = None,\n        floating_base: bool = False,\n        verbosity: int = 1,\n    ) -> None:\n\n        # Create the IK object\n        self._ik = idt.InverseKinematics()\n\n        # Load the URDF model and get the model loader object.\n        # We create the full model with all the joints specified in joint_serialization.\n        model_loader: idt.ModelLoader = self._get_model_loader(\n            urdf=self._urdf_filename, joint_serialization=self._joint_serialization\n        )\n\n        # Get the model\n        model: idt.Model = model_loader.model()\n\n        # If all joints are enabled, get the list of joint names in order to know the\n        # serialization of the full IK solution\n        if self._joint_serialization is None:\n            self._joint_serialization = []\n\n            for joint_idx in range(model.getNrOfJoints()):\n                self._joint_serialization.append(model.getJointName(joint_idx))\n\n        # Configure the considered joints for the optimization.\n        # If not specified, use the serialization of the full solution.\n        if self._considered_joints is None:\n            self._considered_joints = self._joint_serialization\n\n        # Set the model in the IK specifying the considered joints\n        if not self._ik.setModel(model, self._considered_joints):\n            raise RuntimeError(\"Failed to set the model in the IK object\")\n\n        # Configure IK\n        self._ik.setVerbosity(verbosity)\n        self._ik.setMaxIterations(max_iterations)\n        self._ik.setCostTolerance(cost_tolerance)\n        self._ik.setConstraintsTolerance(constraints_tolerance)\n        self._ik.setDefaultTargetResolutionMode(target_mode.to_idyntree())\n        self._ik.setRotationParametrization(rotation_parametrization.to_idyntree())\n\n        # Optionally change the base frame\n        if base_frame is not None:\n            # Store the frame of the base link\n            self._base_frame = base_frame\n\n            # Change the base frame\n            if not self._ik.setFloatingBaseOnFrameNamed(base_frame):\n                raise RuntimeError(\"Failed to change floating base frame\")\n        else:\n            self._base_frame = model.getLinkName(model.getDefaultBaseLink())\n\n        # Store whether the IK optimize a fixed or floating base robot\n        self._floating_base = floating_base\n\n        if not self._floating_base:\n\n            # Add a frame constraint for the base\n            self.add_frame_transform_constraint(\n                frame_name=self._base_frame,\n                position=np.array([0.0, 0, 0.0]),\n                quaternion=np.array([1.0, 0, 0, 0]),\n            )\n\n    def set_current_robot_configuration(\n        self,\n        base_position: np.ndarray,\n        base_quaternion: np.ndarray,\n        joint_configuration: np.ndarray,\n    ) -> None:\n\n        if joint_configuration.size != len(self._joint_serialization):\n            raise ValueError(joint_configuration)\n\n        H = rbd.idyntree.numpy.FromNumPy.to_idyntree_transform(\n            position=base_position, quaternion=base_quaternion\n        )\n\n        q = rbd.idyntree.numpy.FromNumPy.to_idyntree_dyn_vector(\n            array=joint_configuration\n        )\n\n        if not self._ik.setCurrentRobotConfiguration(H, q):\n            raise RuntimeError(\"Failed to set the current robot configuration\")\n\n        if not self._floating_base:\n\n            self.update_frame_transform_constraint(\n                frame_name=self._base_frame,\n                position=base_position,\n                quaternion=base_quaternion,\n            )\n\n    def set_current_joint_configuration(\n        self, joint_name: str, configuration: float\n    ) -> None:\n\n        if joint_name not in self._joint_serialization:\n            raise ValueError(joint_name)\n\n        if not self._ik.setJointConfiguration(\n            jointName=joint_name, jointConfiguration=configuration\n        ):\n            raise RuntimeError(\n                f\"Failed to set the configuration of joint '{joint_name}'\"\n            )\n\n    # ==============\n    # TARGET METHODS\n    # ==============\n\n    def add_target(\n        self,\n        frame_name: str,\n        target_type: TargetType,\n        weight: Union[float, Tuple[float, float]] = None,\n        as_constraint: bool = False,\n    ) -> None:\n\n        # Check the type of the 'weight' argument\n        float_target_types = {TargetType.ROTATION, TargetType.POSITION}\n        weight_type = float if target_type in float_target_types else tuple\n\n        # Backward compatibility: if the target type is POSE and the weight is a float,\n        # we apply the same weight to both target components\n        if target_type is TargetType.POSE and isinstance(weight, float):\n            weight = (weight, weight)\n\n        # Set the default weight if not specified\n        default_weight = 1.0 if target_type in float_target_types else (1.0, 1.0)\n        weight = weight if weight is not None else default_weight\n\n        if not isinstance(weight, weight_type):\n            raise ValueError(f\"The weight must be {weight_type} for this target\")\n\n        if target_type == TargetType.ROTATION:\n            # Add the target\n            ok_target = self._ik.addRotationTarget(\n                frame_name, idt.Rotation.Identity(), weight\n            )\n\n            # Initialize the target data buffers\n            self._targets_data[frame_name] = TargetData(\n                type=TargetType.ROTATION, weight=weight, data=np.array([1.0, 0, 0, 0])\n            )\n\n        elif target_type == TargetType.POSITION:\n            # Add the target\n            ok_target = self._ik.addPositionTarget(\n                frame_name, idt.Position_Zero(), weight\n            )\n\n            # Initialize the target data buffers\n            self._targets_data[frame_name] = TargetData(\n                type=TargetType.POSITION, weight=weight, data=np.array([0.0, 0, 0])\n            )\n\n        elif target_type == TargetType.POSE:\n            # Add the target\n            ok_target = self._ik.addTarget(\n                frame_name, idt.Transform.Identity(), weight[0], weight[1]\n            )\n\n            # Create the transform target data\n            target_data = TransformTargetData(\n                position=np.array([0.0, 0, 0]), quaternion=np.array([1.0, 0, 0, 0])\n            )\n\n            # Initialize the target data buffers\n            self._targets_data[frame_name] = TargetData(\n                type=TargetType.POSE, weight=weight, data=target_data\n            )\n\n        else:\n            raise ValueError(target_type)\n\n        if not ok_target:\n            raise RuntimeError(f\"Failed to add target for frame '{frame_name}'\")\n\n        if as_constraint:\n            if target_type == TargetType.ROTATION:\n                constraint = idt.InverseKinematicsTreatTargetAsConstraintRotationOnly\n            elif target_type == TargetType.POSITION:\n                constraint = idt.InverseKinematicsTreatTargetAsConstraintPositionOnly\n            else:\n                assert target_type == TargetType.POSE\n                constraint = idt.InverseKinematicsTreatTargetAsConstraintFull\n\n            if not self._ik.setTargetResolutionMode(frame_name, constraint):\n                raise RuntimeError(f\"Failed to set target '{frame_name}' as constraint\")\n\n    def add_com_target(\n        self,\n        weight: float = 1.0,\n        as_constraint: bool = False,\n        constraint_tolerance: float = 1e-8,\n    ) -> None:\n\n        # Add the target\n        self._ik.setCOMTarget(idt.Position_Zero(), weight)\n\n        # Configure it either as target or constraint\n        self._ik.setCOMAsConstraint(asConstraint=as_constraint)\n        self._ik.setCOMAsConstraintTolerance(tolerance=constraint_tolerance)\n\n        # Initialize the target data buffers\n        assert \"com\" not in self._targets_data.keys()\n        self._targets_data[\"com\"] = TargetData(\n            type=TargetType.POSITION, weight=weight, data=np.array([0.0, 0, 0])\n        )\n\n    def update_position_target(self, target_name: str, position: np.ndarray) -> None:\n\n        if target_name not in self.get_active_target_names(\n            target_type=TargetType.POSITION\n        ):\n\n            raise ValueError(f\"Failed to find a position target '{target_name}'\")\n\n        # Create the iDynTree position\n        p = rbd.idyntree.numpy.FromNumPy.to_idyntree_position(position=position)\n\n        # Update the target inside IK\n        if not self._ik.updateTarget(target_name, p):\n            raise RuntimeError(f\"Failed to update position of target '{target_name}'\")\n\n        # Get the configured weight\n        weight = self._targets_data[target_name].weight\n\n        # Update the target data\n        self._targets_data[target_name] = TargetData(\n            type=TargetType.POSITION, weight=weight, data=position\n        )\n\n    def update_rotation_target(self, target_name: str, quaternion: np.ndarray) -> None:\n\n        if target_name not in self.get_active_target_names(\n            target_type=TargetType.ROTATION\n        ):\n\n            raise ValueError(f\"Failed to find a rotation target '{target_name}'\")\n\n        # Create the iDynTree rotation matrix\n        R = rbd.idyntree.numpy.FromNumPy.to_idyntree_rotation(quaternion=quaternion)\n\n        # Update the target inside IK\n        if not self._ik.updateRotationTarget(target_name, R):\n            raise RuntimeError(f\"Failed to update rotation of target '{target_name}'\")\n\n        # Get the configured weight\n        weight = self._targets_data[target_name].weight\n\n        # Update the target data\n        self._targets_data[target_name] = TargetData(\n            type=TargetType.ROTATION, weight=weight, data=quaternion\n        )\n\n    def update_transform_target(\n        self, target_name: str, position: np.ndarray, quaternion: np.ndarray\n    ) -> None:\n\n        if target_name not in self.get_active_target_names(target_type=TargetType.POSE):\n\n            raise ValueError(f\"Failed to find a transform target '{target_name}'\")\n\n        # Create the iDynTree transform\n        H = rbd.idyntree.numpy.FromNumPy.to_idyntree_transform(\n            position=position, quaternion=quaternion\n        )\n\n        # Update the target inside IK\n        if not self._ik.updateTarget(target_name, H):\n            raise RuntimeError(f\"Failed to update transform of target '{target_name}'\")\n\n        # Get the configured weight\n        weight = self._targets_data[target_name].weight\n\n        # Create the transform target data\n        transform_data = TransformTargetData(position=position, quaternion=quaternion)\n\n        # Update the target data\n        self._targets_data[target_name] = TargetData(\n            type=TargetType.POSE, weight=weight, data=transform_data\n        )\n\n    def update_com_target(self, position: np.ndarray) -> None:\n\n        if not self._ik.isCOMTargetActive():\n            raise RuntimeError(\"Constraint on CoM not active\")\n\n        # Create the iDynTree position\n        p = rbd.idyntree.numpy.FromNumPy.to_idyntree_position(position=position)\n\n        # Update the target inside IK\n        self._ik.setCOMTarget(p, self._targets_data[\"com\"].weight)\n\n        # Update the target data\n        self._targets_data[\"com\"] = TargetData(\n            type=TargetType.POSITION,\n            weight=self._targets_data[\"com\"].weight,\n            data=position,\n        )\n\n    def deactivate_com_target(self) -> None:\n\n        if not self._ik.isCOMTargetActive():\n            raise RuntimeError(\"Constraint on CoM not active\")\n\n        self._ik.deactivateCOMTarget()\n\n    # =============\n    # FRAME METHODS\n    # =============\n\n    def add_frame_transform_constraint(\n        self, frame_name: str, position: np.ndarray, quaternion: np.ndarray\n    ) -> None:\n\n        # Create the transform\n        H = rbd.idyntree.numpy.FromNumPy.to_idyntree_transform(\n            position=position, quaternion=quaternion\n        )\n\n        # Add the target\n        if not self._ik.addFrameConstraint(frame_name, H):\n            raise RuntimeError(f\"Failed to add constraint on frame '{frame_name}'\")\n\n    def add_frame_position_constraint(\n        self, frame_name: str, position: np.ndarray\n    ) -> None:\n\n        # Create the position\n        p = rbd.idyntree.numpy.FromNumPy.to_idyntree_position(position=position)\n\n        # Add the constraint\n        if not self._ik.addFramePositionConstraint(frame_name, p):\n            raise RuntimeError(f\"Failed to add constraint on frame '{frame_name}'\")\n\n    def add_frame_rotation_constraint(\n        self, frame_name: str, quaternion: np.ndarray\n    ) -> None:\n\n        # Create the position\n        R = rbd.idyntree.numpy.FromNumPy.to_idyntree_rotation(quaternion=quaternion)\n\n        # Add the constraint\n        if not self._ik.addFrameRotationConstraint(frame_name, R):\n            raise RuntimeError(f\"Failed to add constraint on frame '{frame_name}'\")\n\n    def update_frame_transform_constraint(\n        self, frame_name: str, position: np.ndarray, quaternion: np.ndarray\n    ) -> None:\n\n        if not self._ik.isFrameConstraintActive(frame_name):\n            raise RuntimeError(f\"Constraint on frame '{frame_name}' not active\")\n\n        # Create the transform\n        H = rbd.idyntree.numpy.FromNumPy.to_idyntree_transform(\n            position=position, quaternion=quaternion\n        )\n\n        if not self._ik.activateFrameConstraint(frame_name, H):\n            raise RuntimeError(f\"Failed to update constraint on frame '{frame_name}'\")\n\n    def deactivate_frame_constraint(self, frame_name: str) -> None:\n\n        if not self._ik.isFrameConstraintActive(frame_name):\n            raise RuntimeError(f\"Constraint on frame '{frame_name}' not active\")\n\n        if not self._ik.deactivateFrameConstraint(frame_name):\n            raise RuntimeError(\n                f\"Failed to deactivate constraint on frame '{frame_name}'\"\n            )\n\n    # ===================\n    # IK SOLUTION METHODS\n    # ===================\n\n    def solve(self) -> None:\n\n        if not self._ik.solve():\n            raise RuntimeError(\"Failed to solve IK\")\n\n        # Initialize next solver call\n        self._warm_start_with_last_solution()\n\n    def warm_start_from(\n        self, full_solution: IKSolution = None, reduced_solution: IKSolution = None\n    ) -> None:\n\n        if (\n            full_solution is None\n            and reduced_solution is None\n            or full_solution is not None\n            and reduced_solution is not None\n        ):\n            raise ValueError(\"You have to specify either a full or a reduced solution\")\n\n        if (\n            reduced_solution is not None\n            and reduced_solution.joint_configuration.size\n            != len(self._considered_joints)\n        ):\n            raise RuntimeError(\n                \"The joint configuration does not match the number of considered joints\"\n            )\n\n        if full_solution is not None and full_solution.joint_configuration.size != len(\n            self._joint_serialization\n        ):\n            raise RuntimeError(\n                \"The joint configuration does not match the number of model joints\"\n            )\n\n        solution = reduced_solution if reduced_solution is not None else full_solution\n\n        H = rbd.idyntree.numpy.FromNumPy.to_idyntree_transform(\n            position=solution.base_position, quaternion=solution.base_quaternion\n        )\n\n        q = rbd.idyntree.numpy.FromNumPy.to_idyntree_dyn_vector(\n            array=solution.joint_configuration\n        )\n\n        # Warm start the solver\n        if not self._ik.setFullJointsInitialCondition(H, q):\n            raise RuntimeError(\"Failed to warm start the IK solver\")\n\n    # =======\n    # GETTERS\n    # =======\n\n    def get_base_frame(self) -> str:\n\n        return self._base_frame\n\n    def get_available_target_names(self) -> List[str]:\n\n        # Get the reduced model\n        model = self._ik.reducedModel()\n\n        # Note that also frames (modeled as fake links) are available targets\n        link_names = []\n\n        for link_index in range(model.getNrOfLinks()):\n            link_names.append(model.getLinkName(link_index))\n\n        return link_names\n\n    def get_active_target_names(self, target_type: TargetType = None) -> List[str]:\n\n        if target_type is None:\n            return list(self._targets_data.keys())\n\n        else:\n            return [\n                name\n                for name, value in self._targets_data.items()\n                if value.type == target_type\n            ]\n\n    def get_target_data(self, target_name: str) -> TargetData:\n\n        return self._targets_data[target_name]\n\n    def get_full_solution(self) -> IKSolution:\n\n        # Initialize buffers\n        base_transform = idt.Transform.Identity()\n        joint_positions = idt.VectorDynSize(self._ik.fullModel().getNrOfJoints())\n        assert len(joint_positions) == len(self._joint_serialization)\n\n        # Get the solution\n        self._ik.getFullJointsSolution(base_transform, joint_positions)\n\n        # Convert to numpy objects\n        joint_positions = joint_positions.toNumPy()\n        base_position = base_transform.getPosition().toNumPy()\n        base_quaternion = base_transform.getRotation().asQuaternion().toNumPy()\n\n        return IKSolution(\n            base_position=base_position,\n            base_quaternion=base_quaternion,\n            joint_configuration=joint_positions,\n        )\n\n    def get_reduced_solution(self) -> IKSolution:\n\n        # Initialize buffers\n        base_transform = idt.Transform.Identity()\n        joint_positions = idt.VectorDynSize(self._ik.reducedModel().getNrOfJoints())\n        assert len(joint_positions) == len(self._considered_joints)\n\n        # Get the solution\n        self._ik.getReducedSolution(base_transform, joint_positions)\n\n        # Convert to numpy objects\n        joint_positions = joint_positions.toNumPy()\n        base_position = base_transform.getPosition().toNumPy()\n        base_quaternion = base_transform.getRotation().asQuaternion().toNumPy()\n\n        return IKSolution(\n            base_position=base_position,\n            base_quaternion=base_quaternion,\n            joint_configuration=joint_positions,\n        )\n\n    # ===============\n    # PRIVATE METHODS\n    # ===============\n\n    @staticmethod\n    def _get_model_loader(\n        urdf: str, joint_serialization: List[str] = None\n    ) -> idt.ModelLoader:\n\n        # Get the model loader\n        model_loader = idt.ModelLoader()\n\n        if not os.path.exists(urdf):\n            raise FileNotFoundError(urdf)\n\n        # Load the model\n        if joint_serialization:\n            ok_load = model_loader.loadReducedModelFromFile(urdf, joint_serialization)\n        else:\n            ok_load = model_loader.loadModelFromFile(urdf)\n\n        if not ok_load:\n            raise RuntimeError(\"Failed to load model\")\n\n        # Due to some SWIG internal, returning the model contained by the loader\n        # does not work as expected\n        return model_loader\n\n    def _warm_start_with_last_solution(self) -> None:\n\n        last_solution = self.get_full_solution()\n        self.warm_start_from(full_solution=last_solution)\n"
  },
  {
    "path": "python/gym_ignition/rbd/idyntree/kindyncomputations.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import List, Tuple\n\nimport idyntree.bindings as idt\nimport numpy as np\nfrom gym_ignition.rbd import conversions\nfrom gym_ignition.rbd.idyntree import numpy\n\nfrom scenario import core as scenario_core\n\nfrom .helpers import FrameVelocityRepresentation, iDynTreeHelpers\n\n\nclass KinDynComputations:\n    def __init__(\n        self,\n        model_file: str,\n        considered_joints: List[str] = None,\n        world_gravity: np.ndarray = np.array([0, 0, -9.806]),\n        velocity_representation: FrameVelocityRepresentation = FrameVelocityRepresentation.MIXED_REPRESENTATION,\n    ) -> None:\n\n        self.velocity_representation = velocity_representation\n\n        self.kindyn = iDynTreeHelpers.get_kindyncomputations(\n            model_file, considered_joints, velocity_representation\n        )\n\n        self.world_gravity = np.array(world_gravity)\n        self.dofs = self.kindyn.getNrOfDegreesOfFreedom()\n\n        if considered_joints is None:\n\n            model: idt.Model = self.kindyn.model()\n\n            all_joints = [model.getJointName(i) for i in range(model.getNrOfJoints())]\n            self._considered_joints = all_joints\n        else:\n            self._considered_joints = considered_joints\n\n    def joint_serialization(self) -> List[str]:\n\n        return self._considered_joints\n\n    def set_robot_state(\n        self,\n        s: np.ndarray,\n        ds: np.ndarray,\n        world_H_base: np.ndarray = np.eye(4),\n        base_velocity: np.ndarray = np.zeros(6),\n        world_gravity: np.ndarray = None,\n    ) -> None:\n\n        gravity = world_gravity if world_gravity is not None else self.world_gravity\n\n        if s.size != self.dofs:\n            raise ValueError(s)\n\n        if ds.size != self.dofs:\n            raise ValueError(ds)\n\n        if gravity.size != 3:\n            raise ValueError(gravity)\n\n        if world_H_base.shape != (4, 4):\n            raise ValueError(world_H_base)\n\n        if base_velocity.size != 6:\n            raise ValueError(base_velocity)\n\n        s_idyntree = numpy.FromNumPy.to_idyntree_dyn_vector(array=s)\n        ds_idyntree = numpy.FromNumPy.to_idyntree_dyn_vector(array=ds)\n\n        world_gravity_idyntree = numpy.FromNumPy.to_idyntree_fixed_vector(array=gravity)\n\n        world_H_base_idyntree = numpy.FromNumPy.to_idyntree_transform(\n            position=world_H_base[0:3, 3], rotation=world_H_base[0:3, 0:3]\n        )\n\n        base_velocity_idyntree = numpy.FromNumPy.to_idyntree_twist(\n            linear_velocity=base_velocity[0:3], angular_velocity=base_velocity[3:6]\n        )\n\n        ok_state = self.kindyn.setRobotState(\n            world_H_base_idyntree,\n            s_idyntree,\n            base_velocity_idyntree,\n            ds_idyntree,\n            world_gravity_idyntree,\n        )\n\n        if not ok_state:\n            raise RuntimeError(\"Failed to set the robot state\")\n\n    def set_robot_state_from_model(\n        self, model: scenario_core.Model, world_gravity: np.ndarray = None\n    ) -> None:\n\n        s = np.array(model.joint_positions(self.joint_serialization()))\n        ds = np.array(model.joint_velocities(self.joint_serialization()))\n\n        world_o_base = np.array(model.base_position())\n        world_quat_base = np.array(model.base_orientation())\n\n        # Velocity representations\n        body = FrameVelocityRepresentation.BODY_FIXED_REPRESENTATION.to_idyntree()\n        mixed = FrameVelocityRepresentation.MIXED_REPRESENTATION.to_idyntree()\n\n        if self.kindyn.getFrameVelocityRepresentation() is mixed:\n\n            base_linear_velocity = np.array(model.base_world_linear_velocity())\n            base_angular_velocity = np.array(model.base_world_angular_velocity())\n\n        elif self.kindyn.getFrameVelocityRepresentation() is body:\n\n            base_linear_velocity = np.array(model.base_body_linear_velocity())\n            base_angular_velocity = np.array(model.base_body_angular_velocity())\n\n        else:\n            raise RuntimeError(\"INERTIAL_FIXED_REPRESENTATION not yet supported\")\n\n        # Pack the data structures\n        world_H_base = conversions.Transform.from_position_and_quaternion(\n            position=world_o_base, quaternion=world_quat_base\n        )\n        base_velocity_6d = np.concatenate((base_linear_velocity, base_angular_velocity))\n\n        self.set_robot_state(\n            s=s,\n            ds=ds,\n            world_H_base=world_H_base,\n            base_velocity=base_velocity_6d,\n            world_gravity=world_gravity,\n        )\n\n    def get_floating_base(self) -> str:\n\n        return self.kindyn.getFloatingBase()\n\n    def get_joint_positions(self) -> np.ndarray:\n\n        vector = idt.VectorDynSize()\n\n        if not self.kindyn.getJointPos(vector):\n            raise RuntimeError(\"Failed to extract joint positions\")\n\n        return vector.toNumPy()\n\n    def get_joint_velocities(self) -> np.ndarray:\n\n        vector = idt.VectorDynSize()\n\n        if not self.kindyn.getJointVel(vector):\n            raise RuntimeError(\"Failed to extract joint velocities\")\n\n        return vector.toNumPy()\n\n    def get_model_velocity(self) -> np.ndarray:\n\n        nu = idt.VectorDynSize()\n\n        if not self.kindyn.getModelVel(nu):\n            raise RuntimeError(\"Failed to get the model velocity\")\n\n        return nu.toNumPy()\n\n    def get_model_position(self) -> np.ndarray:\n\n        W_H_B: idt.Transform = self.kindyn.getWorldBaseTransform()\n        rpy: idt.Vector3 = self.kindyn.getWorldBaseTransform().getRotation().asRPY()\n\n        q_base = np.concatenate([W_H_B.getPosition().toNumPy(), rpy.toNumPy()])\n\n        return np.concatenate([q_base, self.get_joint_positions()])\n\n    def get_world_transform(self, frame_name: str) -> np.ndarray:\n\n        if self.kindyn.getFrameIndex(frame_name) < 0:\n            raise ValueError(f\"Frame '{frame_name}' does not exist\")\n\n        H = self.kindyn.getWorldTransform(frame_name)\n\n        return numpy.ToNumPy.from_idyntree_transform(transform=H)\n\n    def get_relative_transform(\n        self, ref_frame_name: str, frame_name: str\n    ) -> np.ndarray:\n\n        if self.kindyn.getFrameIndex(ref_frame_name) < 0:\n            raise ValueError(f\"Frame '{ref_frame_name}' does not exist\")\n\n        if self.kindyn.getFrameIndex(frame_name) < 0:\n            raise ValueError(f\"Frame '{frame_name}' does not exist\")\n\n        ref_H_other: idt.Transform = self.kindyn.getRelativeTransform(\n            ref_frame_name, frame_name\n        )\n\n        return ref_H_other.asHomogeneousTransform().toNumPy()\n\n    def get_world_base_transform(self) -> np.ndarray:\n\n        W_H_B: idt.Transform = self.kindyn.getWorldBaseTransform()\n        return W_H_B.asHomogeneousTransform().toNumPy()\n\n    def get_relative_transform_explicit(\n        self,\n        ref_frame_origin: str,\n        ref_frame_orientation: str,\n        frame_origin: str,\n        frame_orientation: str,\n    ) -> np.ndarray:\n\n        for frame in {\n            ref_frame_origin,\n            ref_frame_orientation,\n            frame_origin,\n            frame_orientation,\n        }:\n\n            if frame != \"world\" and self.kindyn.getFrameIndex(frame) < 0:\n                raise ValueError(f\"Frame '{frame}' does not exist\")\n\n        # Compute the transform AB_H_CD\n        frameA = ref_frame_origin\n        frameB = ref_frame_orientation\n        frameC = frame_origin\n        frameD = frame_orientation\n\n        if frame_orientation == \"world\":\n            frameD = frameC\n\n        if ref_frame_orientation == \"world\":\n            frameB = frameA\n\n        frameA_index = self.kindyn.getFrameIndex(frameName=frameA)\n        frameB_index = self.kindyn.getFrameIndex(frameName=frameB)\n        frameC_index = self.kindyn.getFrameIndex(frameName=frameC)\n        frameD_index = self.kindyn.getFrameIndex(frameName=frameD)\n\n        ref_H_other: idt.Transform = self.kindyn.getRelativeTransformExplicit(\n            frameA_index, frameB_index, frameC_index, frameD_index\n        )\n\n        AB_H_CD = ref_H_other\n\n        if frame_orientation == \"world\":\n            AB_H_C = AB_H_CD\n            C_H_CW: idt.Transform = self.kindyn.getWorldTransform(frameC).inverse()\n            C_H_CW.setPosition(idt.Position(0, 0, 0))\n            AB_H_CW = AB_H_C * C_H_CW\n            AB_H_CD = AB_H_CW\n\n        if ref_frame_orientation == \"world\":\n            A_H_CD = AB_H_CD\n            AW_H_A: idt.Transform = self.kindyn.getWorldTransform(frameA)\n            AW_H_A.setPosition(idt.Position(0, 0, 0))\n            AW_H_CD = AW_H_A * A_H_CD\n            AB_H_CD = AW_H_CD\n\n        return AB_H_CD.asHomogeneousTransform().toNumPy()\n\n    def get_relative_adjoint_wrench_transform_explicit(\n        self,\n        ref_frame_origin: str,\n        ref_frame_orientation: str,\n        frame_origin: str,\n        frame_orientation: str,\n    ) -> np.ndarray:\n\n        AB_H_CD = self.get_relative_transform_explicit(\n            ref_frame_origin=ref_frame_origin,\n            ref_frame_orientation=ref_frame_orientation,\n            frame_origin=frame_origin,\n            frame_orientation=frame_orientation,\n        )\n\n        return (\n            numpy.FromNumPy.to_idyntree_transform(\n                position=AB_H_CD[0:3, 3], rotation=AB_H_CD[0:3, 0:3]\n            )\n            .asAdjointTransformWrench()\n            .toNumPy()\n        )\n\n    def get_mass_matrix(self) -> np.ndarray:\n\n        M = idt.MatrixDynSize()\n\n        if not self.kindyn.getFreeFloatingMassMatrix(M):\n            raise RuntimeError(\"Failed to get the free floating mass matrix\")\n\n        return M.toNumPy()\n\n    def get_generalized_gravity_forces(self) -> np.ndarray:\n\n        g = idt.FreeFloatingGeneralizedTorques(self.kindyn.model())\n\n        if not self.kindyn.generalizedGravityForces(g):\n            raise RuntimeError(\"Failed to get the generalized gravity forces\")\n\n        base_wrench: idt.Wrench = g.baseWrench()\n        joint_torques: idt.JointDOFsDoubleArray = g.jointTorques()\n\n        return np.concatenate(\n            [base_wrench.toNumPy().flatten(), joint_torques.toNumPy().flatten()]\n        )\n\n    def get_bias_forces(self) -> np.ndarray:\n\n        h = idt.FreeFloatingGeneralizedTorques(self.kindyn.model())\n\n        if not self.kindyn.generalizedBiasForces(h):\n            raise RuntimeError(\"Failed to get the generalized bias forces\")\n\n        base_wrench: idt.Wrench = h.baseWrench()\n        joint_torques: idt.JointDOFsDoubleArray = h.jointTorques()\n\n        return np.concatenate(\n            [base_wrench.toNumPy().flatten(), joint_torques.toNumPy().flatten()]\n        )\n\n    def get_momentum(self) -> Tuple[np.ndarray, np.ndarray]:\n\n        spatial_momentum = self.kindyn.getLinearAngularMomentum()\n        momentum_6d = spatial_momentum.asVector().toNumPy()\n\n        linear, angular = np.split(momentum_6d, 2)\n        return linear, angular\n\n    def get_centroidal_momentum(self) -> Tuple[np.ndarray, np.ndarray]:\n\n        spatial_momentum = self.kindyn.getCentroidalTotalMomentum()\n        momentum_6d = spatial_momentum.asVector().toNumPy()\n\n        linear, angular = np.split(momentum_6d, 2)\n        return linear, angular\n\n    def get_com_position(self) -> np.ndarray:\n\n        W_p_com = self.kindyn.getCenterOfMassPosition()\n        return W_p_com.toNumPy()\n\n    def get_com_velocity(self) -> np.ndarray:\n\n        # Velocity representations\n        body = FrameVelocityRepresentation.BODY_FIXED_REPRESENTATION.to_idyntree()\n        mixed = FrameVelocityRepresentation.MIXED_REPRESENTATION.to_idyntree()\n\n        if self.kindyn.getFrameVelocityRepresentation() is mixed:\n\n            # The method always returns the MIXED velocity of the CoM, regardless of\n            # how KinDynComputations was configured.\n            v_com = self.kindyn.getCenterOfMassVelocity()\n            return v_com.toNumPy()\n\n        elif self.kindyn.getFrameVelocityRepresentation() is body:\n\n            # Get the transform of the base frame\n            W_H_B = self.kindyn.getWorldBaseTransform()\n            _, W_R_B = numpy.ToNumPy.from_idyntree_transform(\n                transform=W_H_B, split=True\n            )\n\n            # Get the rotation between world and base frame\n            B_R_W = np.linalg.inv(W_R_B)\n\n            # Convert linear velocity from MIXED to BODY representation\n            BW_v_com = self.kindyn.getCenterOfMassVelocity().toNumPy()\n            B_v_com = B_R_W @ BW_v_com\n\n            return B_v_com\n\n        else:\n            raise RuntimeError(\"INERTIAL_FIXED_REPRESENTATION not yet supported\")\n\n    def get_average_velocity(self) -> np.ndarray:\n\n        twist: idt.Twist = self.kindyn.getAverageVelocity()\n        return twist.toNumPy()\n\n    def get_centroidal_average_velocity(self) -> np.ndarray:\n\n        twist: idt.Twist = self.kindyn.getCentroidalAverageVelocity()\n        return twist.toNumPy()\n\n    def get_frame_jacobian(self, frame_name: str) -> np.ndarray:\n\n        if self.kindyn.getFrameIndex(frame_name) < 0:\n            raise ValueError(f\"Frame '{frame_name}' does not exist\")\n\n        J = idt.MatrixDynSize(6, self.dofs + 6)\n\n        if not self.kindyn.getFrameFreeFloatingJacobian(frame_name, J):\n            raise RuntimeError(\"Failed to get the frame free floating jacobian\")\n\n        return J.toNumPy()\n\n    def get_linear_angular_momentum_jacobian(self) -> np.ndarray:\n\n        J_mom = idt.MatrixDynSize()\n\n        if not self.kindyn.getLinearAngularMomentumJacobian(J_mom):\n            raise RuntimeError(\"Failed to get the momentum jacobian\")\n\n        return J_mom.toNumPy()\n\n    def get_centroidal_total_momentum_jacobian(self) -> np.ndarray:\n\n        J_cmm = idt.MatrixDynSize()\n\n        if not self.kindyn.getCentroidalTotalMomentumJacobian(J_cmm):\n            raise RuntimeError(\"Failed to get the centroidal total momentum jacobian\")\n\n        return J_cmm.toNumPy()\n\n    def get_average_velocity_jacobian(self) -> np.ndarray:\n\n        J_avg_vel = idt.MatrixDynSize()\n\n        if not self.kindyn.getAverageVelocityJacobian(J_avg_vel):\n            raise RuntimeError(\"Failed to get the average velocity jacobian\")\n\n        return J_avg_vel.toNumPy()\n\n    def get_centroidal_average_velocity_jacobian(self) -> np.ndarray:\n\n        J_cen_avg_vel = idt.MatrixDynSize()\n\n        if not self.kindyn.getCentroidalAverageVelocityJacobian(J_cen_avg_vel):\n            raise RuntimeError(\"Failed to get the average velocity jacobian\")\n\n        return J_cen_avg_vel.toNumPy()\n\n    def get_frame_bias_acc(self, frame_name: str) -> np.ndarray:\n\n        if self.kindyn.getFrameIndex(frame_name) < 0:\n            raise ValueError(f\"Frame '{frame_name}' does not exist\")\n\n        dJ_nu = self.kindyn.getFrameBiasAcc(frame_name)\n\n        return dJ_nu.toNumPy()\n\n    def get_com_bias_acc(self) -> np.ndarray:\n\n        dJ_nu = self.kindyn.getCenterOfMassBiasAcc()\n        return dJ_nu.toNumPy()\n"
  },
  {
    "path": "python/gym_ignition/rbd/idyntree/numpy.py",
    "content": "import abc\nfrom typing import Tuple, Union\n\nimport idyntree.bindings as idt\nimport numpy as np\nfrom gym_ignition import rbd\n\n\nclass FromNumPy(abc.ABC):\n    @staticmethod\n    def to_idyntree_dyn_vector(array: np.ndarray) -> idt.VectorDynSize:\n\n        return idt.VectorDynSize_FromPython(array)\n\n    @staticmethod\n    def to_idyntree_fixed_vector(array: np.ndarray):\n\n        size = array.size\n        supported_sizes = [3, 4, 6]\n\n        if size not in supported_sizes:\n            raise ValueError(array)\n\n        if size == 3:\n            idyntree_vector = idt.Vector3()\n        elif size == 4:\n            idyntree_vector = idt.Vector4()\n        elif size == 6:\n            idyntree_vector = idt.Vector6()\n        else:\n            raise RuntimeError\n\n        return idyntree_vector.FromPython(array)\n\n    @staticmethod\n    def to_idyntree_position(position: np.ndarray) -> idt.Position:\n\n        if position.size != 3:\n            raise ValueError(\"The position array must have 3 elements\")\n\n        return idt.Position(position[0], position[1], position[2])\n\n    @staticmethod\n    def to_idyntree_rotation(quaternion: np.ndarray) -> idt.Rotation:\n\n        if quaternion.size != 4:\n            raise ValueError(\"The quaternion array must have 4 elements\")\n\n        quat = idt.Vector4_FromPython(quaternion)\n\n        R = idt.Rotation()\n        R.fromQuaternion(quat)\n\n        return R\n\n    @staticmethod\n    def to_idyntree_transform(\n        position: np.ndarray, quaternion: np.ndarray = None, rotation: np.ndarray = None\n    ) -> idt.Transform:\n\n        if quaternion is None and rotation is None:\n            raise ValueError(\"You must pass either a quaternion or a rotation\")\n\n        if quaternion is not None and rotation is not None:\n            raise ValueError(\"You must pass either a quaternion or a rotation\")\n\n        if rotation is not None:\n            quaternion = rbd.conversions.Quaternion.from_matrix(matrix=rotation)\n\n        p = FromNumPy.to_idyntree_position(position=position)\n        R = FromNumPy.to_idyntree_rotation(quaternion=quaternion)\n\n        H = idt.Transform()\n        H.setPosition(p)\n        H.setRotation(R)\n\n        return H\n\n    @staticmethod\n    def to_idyntree_twist(\n        linear_velocity: np.ndarray, angular_velocity: np.ndarray\n    ) -> idt.Twist:\n\n        if linear_velocity.size != 3:\n            raise ValueError(\"The linear velocity must have 3 elements\")\n\n        if angular_velocity.size != 3:\n            raise ValueError(\"The angular velocity must have 3 elements\")\n\n        twist_numpy = np.concatenate((linear_velocity, angular_velocity))\n\n        twist = idt.Twist_FromPython(twist_numpy)\n\n        return twist\n\n\nclass ToNumPy(abc.ABC):\n    @staticmethod\n    def from_idyntree_vector(vector) -> np.ndarray:\n\n        input_types = (\n            idt.Vector3,\n            idt.Vector4,\n            idt.Vector6,\n            idt.VectorDynSize,\n            idt.Matrix3x3,\n            idt.Matrix4x4,\n            idt.Matrix6x6,\n            idt.MatrixDynSize,\n        )\n\n        if not isinstance(vector, input_types):\n            raise ValueError(vector)\n\n        return np.array(vector.toNumPy())\n\n    @staticmethod\n    def from_idyntree_transform(\n        transform: idt.Transform, split: bool = False\n    ) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:\n\n        if not isinstance(transform, idt.Transform):\n            raise ValueError(transform)\n\n        rotation = transform.getRotation()\n        position = transform.getPosition()\n\n        if split:\n            return position.toNumPy(), rotation.toNumPy()\n\n        else:\n            H = np.zeros(shape=[4, 4])\n            H[0:3, 3] = position.toNumPy()\n            H[0:3, 0:3] = rotation.toNumPy()\n\n            return H\n"
  },
  {
    "path": "python/gym_ignition/rbd/utils.py",
    "content": "# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport numpy as np\n\n\ndef wedge(vector3: np.ndarray) -> np.ndarray:\n    \"\"\"\n    Convert a 3D vector to a skew-symmetric matrix.\n\n    Args:\n        vector3: The 3D vector defining the matrix coefficients.\n\n    Returns:\n        The skew-symmetric matrix whose elements are created from the input vector.\n\n    Note:\n        The wedge operator can be useful to compute the cross product of 3D vectors:\n        :math:`v_1 \\\\times v_2 = v_1^\\\\wedge v_2`.\n    \"\"\"\n\n    if vector3.size != 3:\n        raise ValueError(vector3)\n\n    s = np.zeros(shape=(3, 3))\n    s[1, 0] = vector3[2]\n    s[0, 1] = -vector3[2]\n    s[0, 2] = vector3[1]\n    s[2, 0] = -vector3[1]\n    s[2, 1] = vector3[0]\n    s[1, 2] = -vector3[0]\n\n    return s\n\n\ndef vee(matrix3x3: np.ndarray) -> np.ndarray:\n    \"\"\"\n    Convert a 3x3 matrix to a 3D vector with the components of its skew-symmetric part.\n\n    Args:\n        matrix3x3: The input 3x3 matrix. If present, its symmetric part is removed.\n\n    Returns:\n        The 3D vector defining the skew-symmetric matrix.\n\n    Note:\n        This is the inverse operator of :py:func:`wedge`.\n    \"\"\"\n\n    if matrix3x3.shape != (3, 3):\n        raise ValueError(matrix3x3)\n\n    skew_symmetric = extract_skew(matrix3x3)\n\n    return np.array([skew_symmetric[2, 1], skew_symmetric[0, 2], skew_symmetric[1, 0]])\n\n\ndef extract_skew(matrix: np.ndarray) -> np.ndarray:\n    \"\"\"\n    Extract the skew-symmetric part of a square matrix.\n\n    Args:\n        matrix: A square matrix.\n\n    Returns:\n        The skew-symmetric part of the input matrix.\n    \"\"\"\n\n    if matrix.shape[0] != matrix.shape[1]:\n        raise ValueError(matrix)\n\n    return 0.5 * (matrix - matrix.T)\n\n\ndef extract_symm(matrix: np.ndarray) -> np.ndarray:\n    \"\"\"\n    Extract the symmetric part of a square matrix.\n\n    Args:\n        matrix: A square matrix.\n\n    Returns:\n        The symmetric part of the input matrix.\n    \"\"\"\n\n    if matrix.shape[0] != matrix.shape[1]:\n        raise ValueError(matrix)\n\n    return 0.5 * (matrix + matrix.T)\n"
  },
  {
    "path": "python/gym_ignition/runtimes/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import gazebo_runtime, realtime_runtime\n"
  },
  {
    "path": "python/gym_ignition/runtimes/gazebo_runtime.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import Optional\n\nimport gym_ignition_models\nfrom gym_ignition import base\nfrom gym_ignition.base import runtime\nfrom gym_ignition.utils import logger\nfrom gym_ignition.utils.typing import *\n\nfrom scenario import gazebo as scenario\n\n\nclass GazeboRuntime(runtime.Runtime):\n    \"\"\"\n    Implementation of :py:class:`~gym_ignition.base.runtime.Runtime` for the Ignition\n    Gazebo simulator.\n\n    Args:\n        task_cls: The class of the handled task.\n        agent_rate: The rate at which the environment is called.\n        physics_rate: The rate of the physics engine.\n        real_time_factor: The desired RTF of the simulation.\n        physics_engine: *(optional)* The physics engine to use.\n        world: *(optional)* The path to an SDF world file. The world should not contain\n            any physics plugin.\n\n    Note:\n        Physics randomization is still experimental and it could change in the future.\n        Physics is loaded only once, when the simulator starts. In order to change the\n        physics, a new simulator should be created.\n    \"\"\"\n\n    metadata = {\"render.modes\": [\"human\"]}\n\n    def __init__(\n        self,\n        task_cls: type,\n        agent_rate: float,\n        physics_rate: float,\n        real_time_factor: float,\n        physics_engine=scenario.PhysicsEngine_dart,\n        world: str = None,\n        **kwargs,\n    ):\n\n        if gym.logger.MIN_LEVEL <= gym.logger.DEBUG:\n            import inspect\n\n            frame = inspect.currentframe()\n            args, _, _, values = inspect.getargvalues(frame)\n            gym.logger.debug(f\"{dict({arg: values[arg] for arg in args})}\")\n\n        # Gazebo attributes\n        self._gazebo: Optional[scenario.GazeboSimulator] = None\n        self._physics_rate = physics_rate\n        self._real_time_factor = real_time_factor\n\n        # Store the desired physics engine\n        self._physics_engine = physics_engine\n\n        # World attributes\n        self._world = None\n        self._world_sdf = world\n        self._world_name = None\n\n        # Create the Task object\n        task = task_cls(agent_rate=agent_rate, **kwargs)\n\n        if not isinstance(task, base.task.Task):\n            raise RuntimeError(\"The task is not compatible with the runtime\")\n\n        # Wrap the task with the runtime\n        super().__init__(task=task, agent_rate=agent_rate)\n\n        # Trigger the initialization of the simulator and the world\n        _ = self.gazebo\n\n        # Initialize the spaces\n        self.action_space, self.observation_space = self.task.create_spaces()\n\n        # Store the spaces also in the task\n        self.task.action_space = self.action_space\n        self.task.observation_space = self.observation_space\n\n        # Seed the environment\n        self.seed()\n\n    # =================\n    # Runtime interface\n    # =================\n\n    def timestamp(self) -> float:\n\n        return self.world.time()\n\n    # =================\n    # gym.Env interface\n    # =================\n\n    def step(self, action: Action) -> State:\n\n        if not self.action_space.contains(action):\n            logger.warn(\"The action does not belong to the action space\")\n\n        # Set the action\n        self.task.set_action(action)\n\n        # Step the simulator\n        ok_gazebo = self.gazebo.run()\n        assert ok_gazebo, \"Failed to step gazebo\"\n\n        # Get the observation\n        observation = self.task.get_observation()\n        assert isinstance(observation, np.ndarray)\n\n        if not self.observation_space.contains(observation):\n            logger.warn(\"The observation does not belong to the observation space\")\n\n        # Get the reward\n        reward = self.task.get_reward()\n        assert isinstance(reward, float), \"Failed to get the reward\"\n\n        # Check termination\n        done = self.task.is_done()\n\n        # Get info\n        info = self.task.get_info()\n\n        return State((Observation(observation), Reward(reward), Done(done), Info(info)))\n\n    def reset(self) -> Observation:\n\n        # Reset the task\n        self.task.reset_task()\n\n        # Execute a paused step\n        ok_run = self.gazebo.run(paused=True)\n\n        if not ok_run:\n            raise RuntimeError(\"Failed to run Gazebo\")\n\n        # Get the observation\n        observation = self.task.get_observation()\n        assert isinstance(observation, np.ndarray)\n\n        if not self.observation_space.contains(observation):\n            logger.warn(\"The observation does not belong to the observation space\")\n\n        return Observation(observation)\n\n    def render(self, mode: str = \"human\", **kwargs) -> None:\n\n        if mode != \"human\":\n            raise ValueError(f\"Render mode '{mode}' not supported\")\n\n        gui_ok = self.gazebo.gui()\n\n        if not gui_ok:\n            raise RuntimeError(\"Failed to render the environment\")\n\n        return\n\n    def close(self) -> None:\n\n        ok_close = self.gazebo.close()\n\n        if not ok_close:\n            raise RuntimeError(\"Failed to close Gazebo\")\n\n    def seed(self, seed: int = None) -> SeedList:\n\n        # This method also seeds the spaces. To create them, the task could use the world.\n        # Here we check that is has been created.\n        if not self.task.has_world():\n            raise RuntimeError(\"The world has never been created\")\n\n        # Seed the task (it will also seed the spaces)\n        seed = self.task.seed_task(seed)\n\n        return seed\n\n    # ==============================\n    # Properties and Private Methods\n    # ==============================\n\n    @property\n    def gazebo(self) -> scenario.GazeboSimulator:\n\n        if self._gazebo is not None:\n            assert self._gazebo.initialized()\n            return self._gazebo\n\n        # Compute the number of physics iteration to execute at every environment step\n        num_of_steps_per_run = self._physics_rate / self.agent_rate\n\n        if num_of_steps_per_run != int(num_of_steps_per_run):\n            logger.warn(\n                \"Rounding the number of iterations to {} from the nominal {}\".format(\n                    int(num_of_steps_per_run), num_of_steps_per_run\n                )\n            )\n\n        # Create the simulator\n        gazebo = scenario.GazeboSimulator(\n            1.0 / self._physics_rate, self._real_time_factor, int(num_of_steps_per_run)\n        )\n\n        # Store the simulator\n        self._gazebo = gazebo\n\n        # Insert the world (it will initialize the simulator)\n        _ = self.world\n        assert self._gazebo.initialized()\n\n        return self._gazebo\n\n    @property\n    def world(self) -> scenario.World:\n\n        if self._world is not None:\n            assert self.gazebo.initialized()\n            return self._world\n\n        if self._gazebo is None:\n            raise RuntimeError(\"Gazebo has not yet been created\")\n\n        if self._gazebo.initialized():\n            raise RuntimeError(\"Gazebo was already initialized, cannot insert world\")\n\n        if self._world_sdf is None:\n            self._world_sdf = \"\"\n            self._world_name = \"default\"\n        else:\n            self._world_name = scenario.get_world_name_from_sdf(self._world_sdf)\n\n        # Load the world\n        ok_world = self._gazebo.insert_world_from_sdf(self._world_sdf, self._world_name)\n\n        if not ok_world:\n            raise RuntimeError(\"Failed to load SDF world\")\n\n        # Initialize the simulator\n        ok_initialize = self._gazebo.initialize()\n\n        if not ok_initialize:\n            raise RuntimeError(\"Failed to initialize Gazebo\")\n\n        if not self._gazebo.initialized():\n            raise RuntimeError(\"Gazebo was not initialized\")\n\n        # Get the world\n        world = self._gazebo.get_world(self._world_name)\n\n        assert self._world_sdf is not None\n        assert self._world_name in self._gazebo.world_names()\n\n        if self._world_sdf == \"\":\n\n            # Insert the ground plane\n            ok_ground = world.insert_model(\n                gym_ignition_models.get_model_file(\"ground_plane\")\n            )\n\n            if not ok_ground:\n                raise RuntimeError(\"Failed to insert the ground plane\")\n\n        # Set the world in the task\n        self.task.world = world\n\n        # Select the physics engine\n        world.set_physics_engine(engine=self._physics_engine)\n\n        # Store the world\n        self._world = world\n\n        return self._world\n"
  },
  {
    "path": "python/gym_ignition/runtimes/realtime_runtime.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom gym_ignition.base import runtime, task\nfrom gym_ignition.utils.typing import Action, Done, Info, Observation, State\n\n\nclass RealTimeRuntime(runtime.Runtime):\n    \"\"\"\n    Implementation of :py:class:`~gym_ignition.base.runtime.Runtime` for real-time\n    execution.\n\n    Warning:\n        This class is not yet complete.\n    \"\"\"\n\n    def __init__(self, task_cls: type, robot_cls: type, agent_rate: float, **kwargs):\n\n        # Build the environment\n        task_object = task_cls(**kwargs)\n\n        assert isinstance(\n            task_object, task.Task\n        ), \"'task_cls' object must inherit from Task\"\n\n        super().__init__(task=task_object, agent_rate=agent_rate)\n\n        raise NotImplementedError\n\n    # =================\n    # Runtime interface\n    # =================\n\n    def timestamp(self) -> float:\n\n        raise NotImplementedError\n\n    # =================\n    # gym.Env interface\n    # =================\n\n    def step(self, action: Action) -> State:\n\n        # Validate action and robot\n        assert self.action_space.contains(action), \"%r (%s) invalid\" % (\n            action,\n            type(action),\n        )\n\n        # Set the action\n        ok_action = self.task.set_action(action)\n        assert ok_action, \"Failed to set the action\"\n\n        # TODO: realtime step\n\n        # Get the observation\n        observation = self.task.get_observation()\n        assert self.observation_space.contains(observation), \"%r (%s) invalid\" % (\n            observation,\n            type(observation),\n        )\n\n        # Get the reward\n        reward = self.task.get_reward()\n        assert reward, \"Failed to get the reward\"\n\n        # Check termination\n        done = self.task.is_done()\n\n        return State((observation, reward, Done(done), Info({})))\n\n    def reset(self) -> Observation:\n\n        # Get the observation\n        observation = self.task.get_observation()\n\n        return Observation(observation)\n\n    def render(self, mode: str = \"human\", **kwargs) -> None:\n        raise NotImplementedError\n\n    def close(self) -> None:\n        raise NotImplementedError\n"
  },
  {
    "path": "python/gym_ignition/scenario/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import model_with_file, model_wrapper\n"
  },
  {
    "path": "python/gym_ignition/scenario/model_with_file.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\n\n\nclass ModelWithFile(abc.ABC):\n    def __init__(self):\n\n        super().__init__()\n\n    @classmethod\n    @abc.abstractmethod\n    def get_model_file(cls) -> str:\n        pass\n"
  },
  {
    "path": "python/gym_ignition/scenario/model_wrapper.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\n\nfrom scenario import core as scenario\n\n\nclass ModelWrapper(scenario.Model, abc.ABC):\n    def __init__(self, model: scenario.Model):\n\n        # No need to call scenario.Model.__init__()!\n        abc.ABC.__init__(self)\n\n        self.model = model\n\n    def __getattr__(self, name):\n\n        return getattr(self.model, name)\n"
  },
  {
    "path": "python/gym_ignition/utils/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import logger, math, misc, resource_finder, scenario\nfrom .typing import *\n"
  },
  {
    "path": "python/gym_ignition/utils/logger.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport contextlib\nimport warnings\n\nimport gym\nfrom gym import logger\nfrom gym.logger import debug, error, info\nfrom gym.utils import colorize\n\n\ndef custom_formatwarning(msg, *args, **kwargs):\n    \"\"\"\n    Custom format that overrides :py:func:`warnings.formatwarning`.\n    \"\"\"\n\n    if logger.MIN_LEVEL is logger.DEBUG:\n        warning = \"{}:{} {}: {}\\n\".format(args[1], args[2], args[0].__name__, msg)\n    else:\n        warning = \"{}\\n\".format(msg)\n\n    return warning\n\n\ndef warn(msg: str, *args) -> None:\n    \"\"\"\n    Custom definition of :py:func:`gym.logger.warn` function.\n    \"\"\"\n\n    if logger.MIN_LEVEL <= logger.WARN:\n        warnings.warn(colorize(\"%s: %s\" % (\"WARN\", msg % args), \"yellow\"), stacklevel=2)\n\n\n# Monkey patch warning formatting\nwarnings.formatwarning = custom_formatwarning\n\n\ndef set_level(level: int, scenario_level: int = None) -> None:\n    \"\"\"\n    Set the verbosity level of both :py:mod:`gym` and :py:mod:`gym_ignition`.\n\n    Accepted values:\n\n    - :py:const:`gym.logger.DEBUG` (10)\n    - :py:const:`gym.logger.INFO` (20)\n    - :py:const:`gym.logger.WARN` (30)\n    - :py:const:`gym.logger.ERROR` (40)\n    - :py:const:`gym.logger.DISABLED` (50)\n\n    Args:\n        level: The desired verbosity level.\n        scenario_level: The desired ScenarIO verbosity level (defaults to ``level``).\n    \"\"\"\n\n    # Set the gym verbosity\n    logger.set_level(level)\n\n    try:\n        from scenario import gazebo as scenario\n    except ImportError:\n        return\n\n    if scenario_level is None:\n        scenario_level = level\n\n    # Set the ScenarI/O verbosity\n    if scenario_level <= logger.DEBUG:\n        scenario.set_verbosity(scenario.Verbosity_debug)\n    elif scenario_level <= logger.INFO:\n        scenario.set_verbosity(scenario.Verbosity_info)\n    elif scenario_level <= logger.WARN:\n        scenario.set_verbosity(scenario.Verbosity_warning)\n    elif scenario_level <= logger.ERROR:\n        scenario.set_verbosity(scenario.Verbosity_error)\n    else:\n        scenario.set_verbosity(scenario.Verbosity_suppress_all)\n\n\n@contextlib.contextmanager\ndef gym_verbosity(level: int):\n\n    old_level = gym.logger.MIN_LEVEL\n    gym.logger.set_level(level=level)\n    yield None\n    gym.logger.set_level(old_level)\n"
  },
  {
    "path": "python/gym_ignition/utils/math.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom numbers import Number\nfrom typing import List, Union\n\nimport numpy as np\n\nfrom scenario import gazebo as scenario\n\n\ndef normalize(\n    input: Union[Number, List[Number], np.ndarray],\n    low: Union[Number, List[Number], np.ndarray],\n    high: Union[Number, List[Number], np.ndarray],\n) -> Union[Number, np.ndarray]:\n\n    if low is None or high is None:\n        return input\n\n    if isinstance(input, Number):\n        input = [input]\n\n    if isinstance(low, Number):\n        low = [low]\n\n    if isinstance(high, Number):\n        high = [high]\n\n    output = scenario.normalize(list(input), list(low), list(high))\n\n    if len(output) == 1:\n        return output[0]\n    else:\n        return np.array(output)\n\n\ndef denormalize(\n    input: Union[Number, List[Number], np.ndarray],\n    low: Union[Number, List[Number], np.ndarray],\n    high: Union[Number, List[Number], np.ndarray],\n) -> Union[Number, np.ndarray]:\n\n    if low is None or high is None:\n        return input\n\n    if isinstance(input, Number):\n        input = [input]\n\n    if isinstance(low, Number):\n        low = [low]\n\n    if isinstance(high, Number):\n        high = [high]\n\n    output = scenario.denormalize(list(input), list(low), list(high))\n\n    if len(output) == 1:\n        return output[0]\n    else:\n        return np.array(output)\n"
  },
  {
    "path": "python/gym_ignition/utils/misc.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport tempfile\n\n\ndef string_to_file(string: str) -> str:\n\n    handle, tmpfile = tempfile.mkstemp()\n\n    with open(handle, \"w\") as f:\n        f.write(string)\n\n    return tmpfile\n"
  },
  {
    "path": "python/gym_ignition/utils/resource_finder.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport os\nfrom os.path import exists, isfile\nfrom typing import List\n\nfrom gym_ignition.utils import logger\n\nGYM_IGNITION_DATA_PATH = []\n\n\ndef get_search_paths() -> List[str]:\n    global GYM_IGNITION_DATA_PATH\n    return GYM_IGNITION_DATA_PATH\n\n\ndef add_path(data_path: str) -> None:\n    if not exists(data_path):\n        logger.warn(\n            f\"The path '{data_path}' does not exist. Not added to the data path.\"\n        )\n        return\n\n    global GYM_IGNITION_DATA_PATH\n\n    for path in GYM_IGNITION_DATA_PATH:\n        if path == data_path:\n            logger.debug(f\"The path '{data_path}' is already present in the data path\")\n            return\n\n    logger.debug(f\"Adding new search path: '{data_path}'\")\n    GYM_IGNITION_DATA_PATH.append(data_path)\n\n\ndef add_path_from_env_var(env_variable: str) -> None:\n    if env_variable not in os.environ:\n        logger.warn(f\"Failed to find '{env_variable}' environment variable\")\n        return\n\n    # Get the environment variable\n    env_var_content = os.environ[env_variable]\n\n    # Remove leading ':' characters\n    if env_var_content[0] == \":\":\n        env_var_content = env_var_content[1:]\n\n    # Split multiple value\n    env_var_paths = env_var_content.split(\":\")\n\n    for path in env_var_paths:\n        add_path(path)\n\n\ndef find_resource(file_name: str) -> str:\n    file_abs_path = \"\"\n    global GYM_IGNITION_DATA_PATH\n\n    logger.debug(f\"Looking for file '{file_name}'\")\n\n    # Handle if the path is absolute\n    if os.path.isabs(file_name):\n        if isfile(file_name):\n            logger.debug(f\"  Found resource: '{file_name}'\")\n            return file_name\n        else:\n            raise FileNotFoundError(f\"Failed to find resource '{file_name}'\")\n\n    # Handle if the path is relative\n    for path in GYM_IGNITION_DATA_PATH:\n        logger.debug(f\"  Exploring folder '{path}'\")\n        path_with_slash = path if path[-1] == \"/\" else path + \"/\"\n        candidate_abs_path = path_with_slash + file_name\n\n        if isfile(candidate_abs_path):\n            logger.debug(f\"  Found resource: '{candidate_abs_path}'\")\n            file_abs_path = candidate_abs_path\n            break\n\n    if not file_abs_path:\n        raise FileNotFoundError(f\"Failed to find resource '{file_name}'\")\n\n    return file_abs_path\n"
  },
  {
    "path": "python/gym_ignition/utils/scenario.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import List, Tuple, Union\n\nimport gym.spaces\nimport gym_ignition_models\nimport numpy as np\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\n\ndef get_unique_model_name(world: scenario.World, model_name: str) -> str:\n    \"\"\"\n    Get a unique model name given a world configuration.\n\n    This function find the first available model name starting from the argument and\n    appending a integer postfix until the resulting name is unique in the world.\n\n    Tentatives example: `cartpole`, `cartpole1`, `cartpole2`, ...\n\n    Args:\n        world: An initialized world.\n        model_name: The first model name attempt.\n\n    Raises:\n        ValueError: If the world is not valid.\n\n    Returns:\n        The unique model name calculated from the original name.\n    \"\"\"\n\n    if world.id() == 0:\n        raise ValueError(\"The world is not valid\")\n\n    postfix = 0\n    model_name_tentative = f\"{model_name}\"\n\n    while model_name_tentative in world.model_names():\n\n        postfix += 1\n        model_name_tentative = f\"{model_name}{postfix}\"\n\n    return model_name_tentative\n\n\ndef init_gazebo_sim(\n    step_size: float = 0.001, real_time_factor: float = 1.0, steps_per_run: int = 1\n) -> Tuple[scenario.GazeboSimulator, Union[scenario.World, core.World]]:\n    \"\"\"\n    Initialize a Gazebo simulation with an empty world and default physics.\n\n    Args:\n        step_size: Gazebo step size.\n        real_time_factor: The desired real time factor of the simulation.\n        steps_per_run: How many steps should be executed at each Gazebo run.\n\n    Raises:\n        RuntimeError: If the initialization of either the simulator or the world fails.\n\n    Returns:\n        * **gazebo** -- The Gazebo simulator.\n        * **world** -- The default world.\n    \"\"\"\n\n    # Create the simulator\n    gazebo = scenario.GazeboSimulator(step_size, real_time_factor, steps_per_run)\n\n    # Initialize the simulator\n    ok_initialize = gazebo.initialize()\n\n    if not ok_initialize:\n        raise RuntimeError(\"Failed to initialize Gazebo\")\n\n    # Get the world\n    world = gazebo.get_world()\n\n    # Insert the ground plane\n    ok_ground = world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n\n    if not ok_ground:\n        raise RuntimeError(\"Failed to insert the ground plane\")\n\n    ok_physics = world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    if not ok_physics:\n        raise RuntimeError(\"Failed to insert the physics plugin\")\n\n    return gazebo, world\n\n\ndef get_joint_positions_space(\n    model: scenario.Model, considered_joints: List[str] = None\n) -> gym.spaces.Box:\n    \"\"\"\n    Build a Box space from the joint position limits.\n\n    Args:\n        model: The model from which generating the joint space.\n        considered_joints: List of considered joints. It is helpful to restrict the set\n            of joints and to enforce a custom joint serialization.\n\n    Returns:\n        A box space created from the model's joint position limits.\n    \"\"\"\n\n    if considered_joints is None:\n        considered_joints = model.joint_names()\n\n    # Get the joint limits\n    joint_limits = model.joint_limits(considered_joints)\n\n    # Build the space\n    space = gym.spaces.Box(\n        low=np.array(joint_limits.min), high=np.array(joint_limits.max)\n    )\n\n    return space\n"
  },
  {
    "path": "python/gym_ignition/utils/typing.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import Dict, List, NewType, Tuple, Union\n\nimport gym.spaces\nimport numpy as np\n\nDone = NewType(\"Done\", bool)\nInfo = NewType(\"Info\", Dict)\nReward = NewType(\"Reward\", float)\nObservation = NewType(\"Observation\", np.ndarray)\nAction = NewType(\"Action\", Union[np.ndarray, np.number])\n\nSeedList = NewType(\"SeedList\", List[int])\n\nState = NewType(\"State\", Tuple[Observation, Reward, Done, Info])\n\nActionSpace = NewType(\"ActionSpace\", gym.spaces.Space)\nObservationSpace = NewType(\"ObservationSpace\", gym.spaces.Space)\n"
  },
  {
    "path": "python/gym_ignition_environments/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport numpy\nfrom gym.envs.registration import register\n\nfrom . import models, randomizers, tasks\n\nmax_float = float(numpy.finfo(numpy.float32).max)\n\nregister(\n    id=\"Pendulum-Gazebo-v0\",\n    entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n    max_episode_steps=5000,\n    kwargs={\n        \"task_cls\": tasks.pendulum_swingup.PendulumSwingUp,\n        \"agent_rate\": 1000,\n        \"physics_rate\": 1000,\n        \"real_time_factor\": max_float,\n    },\n)\n\nregister(\n    id=\"CartPoleDiscreteBalancing-Gazebo-v0\",\n    entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n    max_episode_steps=5000,\n    kwargs={\n        \"task_cls\": tasks.cartpole_discrete_balancing.CartPoleDiscreteBalancing,\n        \"agent_rate\": 1000,\n        \"physics_rate\": 1000,\n        \"real_time_factor\": max_float,\n    },\n)\n\nregister(\n    id=\"CartPoleContinuousBalancing-Gazebo-v0\",\n    entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n    max_episode_steps=5000,\n    kwargs={\n        \"task_cls\": tasks.cartpole_continuous_balancing.CartPoleContinuousBalancing,\n        \"agent_rate\": 1000,\n        \"physics_rate\": 1000,\n        \"real_time_factor\": max_float,\n    },\n)\n\nregister(\n    id=\"CartPoleContinuousSwingup-Gazebo-v0\",\n    entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n    max_episode_steps=5000,\n    kwargs={\n        \"task_cls\": tasks.cartpole_continuous_swingup.CartPoleContinuousSwingup,\n        \"agent_rate\": 1000,\n        \"physics_rate\": 1000,\n        \"real_time_factor\": max_float,\n    },\n)\n"
  },
  {
    "path": "python/gym_ignition_environments/models/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import cartpole, icub, panda, pendulum\n"
  },
  {
    "path": "python/gym_ignition_environments/models/cartpole.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import List\n\nfrom gym_ignition.scenario import model_with_file, model_wrapper\nfrom gym_ignition.utils.scenario import get_unique_model_name\n\nfrom scenario import core as scenario\n\n\nclass CartPole(model_wrapper.ModelWrapper, model_with_file.ModelWithFile):\n    def __init__(\n        self,\n        world: scenario.World,\n        position: List[float] = (0.0, 0.0, 0.0),\n        orientation: List[float] = (1.0, 0, 0, 0),\n        model_file: str = None,\n    ):\n\n        # Get a unique model name\n        model_name = get_unique_model_name(world, \"cartpole\")\n\n        # Initial pose\n        initial_pose = scenario.Pose(position, orientation)\n\n        # Get the model file (URDF or SDF) and allow to override it\n        if model_file is None:\n            model_file = CartPole.get_model_file()\n\n        # Insert the model\n        ok_model = world.to_gazebo().insert_model(model_file, initial_pose, model_name)\n\n        if not ok_model:\n            raise RuntimeError(\"Failed to insert model\")\n\n        # Get the model\n        model = world.get_model(model_name)\n\n        # Initialize base class\n        super().__init__(model=model)\n\n    @classmethod\n    def get_model_file(cls) -> str:\n\n        import gym_ignition_models\n\n        return gym_ignition_models.get_model_file(\"cartpole\")\n"
  },
  {
    "path": "python/gym_ignition_environments/models/icub.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import List\n\nfrom gym_ignition import scenario\nfrom gym_ignition.utils.scenario import get_unique_model_name\n\nfrom scenario import core as scenario_core\n\n\nclass ICubGazeboABC(\n    scenario.model_wrapper.ModelWrapper, scenario.model_with_file.ModelWithFile, abc.ABC\n):\n\n    DOFS = 32\n    NUM_LINKS = 39\n    NUM_JOINTS = 32\n\n    initial_positions = {\n        # Left leg\n        \"l_knee\": -1.05,\n        \"l_ankle_pitch\": -0.57,\n        \"l_ankle_roll\": -0.024,\n        \"l_hip_pitch\": 0.48,\n        \"l_hip_roll\": 0.023,\n        \"l_hip_yaw\": -0.005,\n        # Left arm\n        \"l_elbow\": 0.54,\n        \"l_wrist_pitch\": 0.0,\n        \"l_wrist_prosup\": 0.0,\n        \"l_wrist_yaw\": 0.0,\n        \"l_shoulder_pitch\": -0.159,\n        \"l_shoulder_roll\": 0.435,\n        \"l_shoulder_yaw\": 0.183,\n        # Head\n        \"neck_pitch\": 0.0,\n        \"neck_roll\": 0.0,\n        \"neck_yaw\": 0.0,\n        # Right leg\n        \"r_knee\": -1.05,\n        \"r_ankle_pitch\": -0.57,\n        \"r_ankle_roll\": -0.024,\n        \"r_hip_pitch\": 0.48,\n        \"r_hip_roll\": 0.023,\n        \"r_hip_yaw\": -0.005,\n        # Right arm\n        \"r_elbow\": 0.54,\n        \"r_wrist_pitch\": 0.0,\n        \"r_wrist_prosup\": 0.0,\n        \"r_wrist_yaw\": 0.0,\n        \"r_shoulder_pitch\": -0.159,\n        \"r_shoulder_roll\": 0.435,\n        \"r_shoulder_yaw\": 0.183,\n        # Torso\n        \"torso_pitch\": 0.1,\n        \"torso_roll\": 0.0,\n        \"torso_yaw\": 0.0,\n    }\n\n    def __init__(\n        self,\n        world: scenario_core.World,\n        position: List[float],\n        orientation: List[float],\n        model_file: str = None,\n    ):\n\n        # Get a unique model name\n        model_name = get_unique_model_name(world, \"icub\")\n\n        # Initial pose\n        initial_pose = scenario_core.Pose(position, orientation)\n\n        # Get the model file (URDF or SDF) and allow to override it\n        if model_file is None:\n            model_file = self.get_model_file()\n\n        # Insert the model\n        ok_model = world.to_gazebo().insert_model(model_file, initial_pose, model_name)\n\n        if not ok_model:\n            raise RuntimeError(\"Failed to insert model\")\n\n        # Get the model\n        model = world.get_model(model_name)\n\n        # Initialize base class\n        super().__init__(model=model)\n\n        # Store the initial positions\n        q0 = list(self.initial_positions.values())\n        joint_names = list(self.initial_positions.keys())\n        assert self.dofs() == len(q0) == len(joint_names)\n\n        ok_q0 = self.to_gazebo().reset_joint_positions(q0, joint_names)\n        assert ok_q0, \"Failed to set initial position\"\n\n\nclass ICubGazebo(ICubGazeboABC):\n    def __init__(\n        self,\n        world: scenario_core.World,\n        position: List[float] = (0.0, 0.0, 0.572),\n        orientation: List[float] = (0, 0, 0, 1.0),\n        model_file: str = None,\n    ):\n\n        super().__init__(\n            world=world,\n            position=position,\n            orientation=orientation,\n            model_file=model_file,\n        )\n\n    @classmethod\n    def get_model_file(cls) -> str:\n\n        import gym_ignition_models\n\n        return gym_ignition_models.get_model_file(\"iCubGazeboV2_5\")\n\n\nclass ICubGazeboSimpleCollisions(ICubGazeboABC):\n    def __init__(\n        self,\n        world: scenario_core.World,\n        position: List[float] = (0.0, 0.0, 0.572),\n        orientation: List[float] = (0, 0, 0, 1.0),\n        model_file: str = None,\n    ):\n\n        super().__init__(\n            world=world,\n            position=position,\n            orientation=orientation,\n            model_file=model_file,\n        )\n\n    @classmethod\n    def get_model_file(cls) -> str:\n\n        import gym_ignition_models\n\n        return gym_ignition_models.get_model_file(\"iCubGazeboSimpleCollisionsV2_5\")\n"
  },
  {
    "path": "python/gym_ignition_environments/models/panda.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import List\n\nfrom gym_ignition.scenario import model_with_file, model_wrapper\nfrom gym_ignition.utils.scenario import get_unique_model_name\n\nfrom scenario import core as scenario\n\n\nclass Panda(model_wrapper.ModelWrapper, model_with_file.ModelWithFile):\n    def __init__(\n        self,\n        world: scenario.World,\n        position: List[float] = (0.0, 0.0, 0.0),\n        orientation: List[float] = (1.0, 0, 0, 0),\n        model_file: str = None,\n    ):\n\n        # Get a unique model name\n        model_name = get_unique_model_name(world, \"panda\")\n\n        # Initial pose\n        initial_pose = scenario.Pose(position, orientation)\n\n        # Get the default model description (URDF or SDF) allowing to pass a custom model\n        if model_file is None:\n            model_file = Panda.get_model_file()\n\n        # Insert the model\n        ok_model = world.to_gazebo().insert_model(model_file, initial_pose, model_name)\n\n        if not ok_model:\n            raise RuntimeError(\"Failed to insert model\")\n\n        # Get the model\n        model = world.get_model(model_name)\n\n        # Initial joint configuration\n        model.to_gazebo().reset_joint_positions(\n            [0, -0.785, 0, -2.356, 0, 1.571, 0.785],\n            [name for name in model.joint_names() if \"panda_joint\" in name],\n        )\n\n        # From:\n        # https://github.com/mkrizmancic/franka_gazebo/blob/master/config/default.yaml\n        pid_gains_1000hz = {\n            \"panda_joint1\": scenario.PID(50, 0, 20),\n            \"panda_joint2\": scenario.PID(10000, 0, 500),\n            \"panda_joint3\": scenario.PID(100, 0, 10),\n            \"panda_joint4\": scenario.PID(1000, 0, 50),\n            \"panda_joint5\": scenario.PID(100, 0, 10),\n            \"panda_joint6\": scenario.PID(100, 0, 10),\n            \"panda_joint7\": scenario.PID(10, 0.5, 0.1),\n            \"panda_finger_joint1\": scenario.PID(100, 0, 50),\n            \"panda_finger_joint2\": scenario.PID(100, 0, 50),\n        }\n\n        # Check that all joints have gains\n        if not set(model.joint_names()) == set(pid_gains_1000hz.keys()):\n            raise ValueError(\"The number of PIDs does not match the number of joints\")\n\n        # Set the PID gains\n        for joint_name, pid in pid_gains_1000hz.items():\n\n            if not model.get_joint(joint_name).set_pid(pid=pid):\n                raise RuntimeError(f\"Failed to set the PID of joint '{joint_name}'\")\n\n        # Set the default PID update period\n        assert model.set_controller_period(1000.0)\n\n        # Initialize base class\n        super().__init__(model=model)\n\n    @classmethod\n    def get_model_file(cls) -> str:\n\n        import gym_ignition_models\n\n        return gym_ignition_models.get_model_file(\"panda\")\n"
  },
  {
    "path": "python/gym_ignition_environments/models/pendulum.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import List\n\nfrom gym_ignition.scenario import model_with_file, model_wrapper\nfrom gym_ignition.utils.scenario import get_unique_model_name\n\nfrom scenario import core as scenario\n\n\nclass Pendulum(model_wrapper.ModelWrapper, model_with_file.ModelWithFile):\n    def __init__(\n        self,\n        world: scenario.World,\n        position: List[float] = (0.0, 0.0, 0.0),\n        orientation: List[float] = (1.0, 0, 0, 0),\n        model_file: str = None,\n    ):\n\n        # Get a unique model name\n        model_name = get_unique_model_name(world, \"pendulum\")\n\n        # Initial pose\n        initial_pose = scenario.Pose(position, orientation)\n\n        # Get the model file (URDF or SDF) and allow to override it\n        if model_file is None:\n            model_file = Pendulum.get_model_file()\n\n        # Insert the model\n        ok_model = world.to_gazebo().insert_model(model_file, initial_pose, model_name)\n\n        if not ok_model:\n            raise RuntimeError(\"Failed to insert model\")\n\n        # Get the model\n        model = world.get_model(model_name)\n\n        # Initialize base class\n        super().__init__(model=model)\n\n    @classmethod\n    def get_model_file(cls) -> str:\n\n        import gym_ignition_models\n\n        return gym_ignition_models.get_model_file(\"pendulum\")\n"
  },
  {
    "path": "python/gym_ignition_environments/randomizers/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import cartpole, cartpole_no_rand\n"
  },
  {
    "path": "python/gym_ignition_environments/randomizers/cartpole.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Union\n\nfrom gym_ignition import randomizers, utils\nfrom gym_ignition.randomizers import gazebo_env_randomizer\nfrom gym_ignition.randomizers.gazebo_env_randomizer import MakeEnvCallable\nfrom gym_ignition.randomizers.model.sdf import Distribution, Method, UniformParams\nfrom gym_ignition.utils import misc\nfrom gym_ignition_environments import tasks\nfrom gym_ignition_environments.models import cartpole\n\nfrom scenario import gazebo as scenario\n\n# Tasks that are supported by this randomizer. Used for type hinting.\nSupportedTasks = Union[\n    tasks.cartpole_discrete_balancing.CartPoleDiscreteBalancing,\n    tasks.cartpole_continuous_swingup.CartPoleContinuousSwingup,\n    tasks.cartpole_continuous_balancing.CartPoleContinuousBalancing,\n]\n\n\nclass CartpoleRandomizersMixin(\n    randomizers.abc.TaskRandomizer,\n    randomizers.abc.PhysicsRandomizer,\n    randomizers.abc.ModelDescriptionRandomizer,\n    abc.ABC,\n):\n    \"\"\"\n    Mixin that collects the implementation of task, model and physics randomizations for\n    cartpole environments.\n    \"\"\"\n\n    def __init__(self, randomize_physics_after_rollouts: int = 0):\n\n        # Initialize base classes\n        randomizers.abc.TaskRandomizer.__init__(self)\n        randomizers.abc.PhysicsRandomizer.__init__(\n            self, randomize_after_rollouts_num=randomize_physics_after_rollouts\n        )\n        randomizers.abc.ModelDescriptionRandomizer.__init__(self)\n\n        # SDF randomizer\n        self._sdf_randomizer = None\n\n    # ===========================\n    # PhysicsRandomizer interface\n    # ===========================\n\n    def get_engine(self):\n\n        return scenario.PhysicsEngine_dart\n\n    def randomize_physics(self, task: SupportedTasks, **kwargs) -> None:\n\n        gravity_z = task.np_random.normal(loc=-9.8, scale=0.2)\n\n        if not task.world.to_gazebo().set_gravity((0, 0, gravity_z)):\n            raise RuntimeError(\"Failed to set the gravity\")\n\n    # ========================\n    # TaskRandomizer interface\n    # ========================\n\n    def randomize_task(self, task: SupportedTasks, **kwargs) -> None:\n\n        # Remove the model from the world\n        self._clean_world(task=task)\n\n        if \"gazebo\" not in kwargs:\n            raise ValueError(\"gazebo kwarg not passed to the task randomizer\")\n\n        gazebo = kwargs[\"gazebo\"]\n\n        # Execute a paused run to process model removal\n        if not gazebo.run(paused=True):\n            raise RuntimeError(\"Failed to execute a paused Gazebo run\")\n\n        # Generate a random model description\n        random_model = self.randomize_model_description(task=task)\n\n        # Insert a new model in the world\n        self._populate_world(task=task, cartpole_model=random_model)\n\n        # Execute a paused run to process model insertion\n        if not gazebo.run(paused=True):\n            raise RuntimeError(\"Failed to execute a paused Gazebo run\")\n\n    # ====================================\n    # ModelDescriptionRandomizer interface\n    # ====================================\n\n    def randomize_model_description(self, task: SupportedTasks, **kwargs) -> str:\n\n        randomizer = self._get_sdf_randomizer(task=task)\n        sdf = misc.string_to_file(randomizer.sample())\n        return sdf\n\n    # ===============\n    # Private Methods\n    # ===============\n\n    def _get_sdf_randomizer(\n        self, task: SupportedTasks\n    ) -> randomizers.model.sdf.SDFRandomizer:\n\n        if self._sdf_randomizer is not None:\n            return self._sdf_randomizer\n\n        # Get the model file\n        urdf_model_file = cartpole.CartPole.get_model_file()\n\n        # Convert the URDF to SDF\n        sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model_file)\n\n        # Write the SDF string to a temp file\n        sdf_model = utils.misc.string_to_file(sdf_model_string)\n\n        # Create and initialize the randomizer\n        sdf_randomizer = randomizers.model.sdf.SDFRandomizer(sdf_model=sdf_model)\n\n        # Use the RNG of the task\n        sdf_randomizer.rng = task.np_random\n\n        # Randomize the mass of all links\n        sdf_randomizer.new_randomization().at_xpath(\"*/link/inertial/mass\").method(\n            Method.Additive\n        ).sampled_from(\n            Distribution.Uniform, UniformParams(low=-0.2, high=0.2)\n        ).force_positive().add()\n\n        # Process the randomization\n        sdf_randomizer.process_data()\n        assert len(sdf_randomizer.get_active_randomizations()) > 0\n\n        # Store and return the randomizer\n        self._sdf_randomizer = sdf_randomizer\n        return self._sdf_randomizer\n\n    @staticmethod\n    def _clean_world(task: SupportedTasks) -> None:\n\n        # Remove the model from the simulation\n        if task.model_name is not None and task.model_name in task.world.model_names():\n\n            if not task.world.to_gazebo().remove_model(task.model_name):\n                raise RuntimeError(\"Failed to remove the cartpole from the world\")\n\n    @staticmethod\n    def _populate_world(task: SupportedTasks, cartpole_model: str = None) -> None:\n\n        # Insert a new cartpole.\n        # It will create a unique name if there are clashing.\n        model = cartpole.CartPole(world=task.world, model_file=cartpole_model)\n\n        # Store the model name in the task\n        task.model_name = model.name()\n\n\nclass CartpoleEnvRandomizer(\n    gazebo_env_randomizer.GazeboEnvRandomizer, CartpoleRandomizersMixin\n):\n    \"\"\"\n    Concrete implementation of cartpole environments randomization.\n    \"\"\"\n\n    def __init__(self, env: MakeEnvCallable, num_physics_rollouts: int = 0):\n\n        # Initialize the mixin\n        CartpoleRandomizersMixin.__init__(\n            self, randomize_physics_after_rollouts=num_physics_rollouts\n        )\n\n        # Initialize the environment randomizer\n        gazebo_env_randomizer.GazeboEnvRandomizer.__init__(\n            self, env=env, physics_randomizer=self\n        )\n"
  },
  {
    "path": "python/gym_ignition_environments/randomizers/cartpole_no_rand.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom typing import Union\n\nfrom gym_ignition.randomizers import gazebo_env_randomizer\nfrom gym_ignition.randomizers.gazebo_env_randomizer import MakeEnvCallable\nfrom gym_ignition_environments import tasks\nfrom gym_ignition_environments.models import cartpole\n\n# Tasks that are supported by this randomizer. Used for type hinting.\nSupportedTasks = Union[\n    tasks.cartpole_discrete_balancing.CartPoleDiscreteBalancing,\n    tasks.cartpole_continuous_swingup.CartPoleContinuousSwingup,\n    tasks.cartpole_continuous_balancing.CartPoleContinuousBalancing,\n]\n\n\nclass CartpoleEnvNoRandomizations(gazebo_env_randomizer.GazeboEnvRandomizer):\n    \"\"\"\n    Dummy environment randomizer for cartpole tasks.\n\n    Check :py:class:`~gym_ignition_environments.randomizers.cartpole.CartpoleRandomizersMixin`\n    for an example that randomizes the task, the physics, and the model.\n    \"\"\"\n\n    def __init__(self, env: MakeEnvCallable):\n\n        super().__init__(env=env)\n\n    def randomize_task(self, task: SupportedTasks, **kwargs) -> None:\n        \"\"\"\n        Prepare the scene for cartpole tasks. It simply removes the cartpole of the\n        previous rollout and inserts a new one in the default state. Then, the active\n        Task will reset the state of the cartpole depending on the implemented\n        decision-making logic.\n        \"\"\"\n\n        if \"gazebo\" not in kwargs:\n            raise ValueError(\"gazebo kwarg not passed to the task randomizer\")\n\n        gazebo = kwargs[\"gazebo\"]\n\n        # Remove the model from the simulation\n        if task.model_name is not None and task.model_name in task.world.model_names():\n\n            if not task.world.to_gazebo().remove_model(task.model_name):\n                raise RuntimeError(\"Failed to remove the cartpole from the world\")\n\n        # Execute a paused run to process model removal\n        if not gazebo.run(paused=True):\n            raise RuntimeError(\"Failed to execute a paused Gazebo run\")\n\n        # Insert a new cartpole model\n        model = cartpole.CartPole(world=task.world)\n\n        # Store the model name in the task\n        task.model_name = model.name()\n\n        # Execute a paused run to process model insertion\n        if not gazebo.run(paused=True):\n            raise RuntimeError(\"Failed to execute a paused Gazebo run\")\n"
  },
  {
    "path": "python/gym_ignition_environments/tasks/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import (\n    cartpole_continuous_balancing,\n    cartpole_continuous_swingup,\n    cartpole_discrete_balancing,\n    pendulum_swingup,\n)\n"
  },
  {
    "path": "python/gym_ignition_environments/tasks/cartpole_continuous_balancing.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Tuple\n\nimport gym\nimport numpy as np\nfrom gym_ignition.base import task\nfrom gym_ignition.utils.typing import (\n    Action,\n    ActionSpace,\n    Observation,\n    ObservationSpace,\n    Reward,\n)\n\nfrom scenario import core as scenario\n\n\nclass CartPoleContinuousBalancing(task.Task, abc.ABC):\n    def __init__(self, agent_rate: float, reward_cart_at_center: bool = True, **kwargs):\n\n        # Initialize the Task base class\n        task.Task.__init__(self, agent_rate=agent_rate)\n\n        # Name of the cartpole model\n        self.model_name = None\n\n        # Space for resetting the task\n        self.reset_space = None\n\n        # Private attributes\n        self._reward_cart_at_center = reward_cart_at_center\n\n        # Variables limits\n        self._x_threshold = 2.4  # m\n        self._dx_threshold = 20.0  # m /s\n        self._q_threshold = np.deg2rad(12)  # rad\n        self._dq_threshold = np.deg2rad(3 * 360)  # rad / s\n\n    def create_spaces(self) -> Tuple[ActionSpace, ObservationSpace]:\n\n        # Create the action space\n        max_force = 50.0  # Nm\n        action_space = gym.spaces.Box(\n            low=np.array([-max_force]), high=np.array([max_force]), dtype=np.float32\n        )\n\n        # Configure reset limits\n        high = np.array(\n            [\n                self._x_threshold,  # x\n                self._dx_threshold,  # dx\n                self._q_threshold,  # q\n                self._dq_threshold,  # dq\n            ]\n        )\n\n        # Configure the reset space\n        self.reset_space = gym.spaces.Box(low=-high, high=high, dtype=np.float32)\n\n        # Configure the observation space\n        obs_high = high.copy() * 1.2\n        observation_space = gym.spaces.Box(\n            low=-obs_high, high=obs_high, dtype=np.float32\n        )\n\n        return action_space, observation_space\n\n    def set_action(self, action: Action) -> None:\n\n        # Get the force value\n        force = action.tolist()[0]\n\n        # Set the force value\n        model = self.world.get_model(self.model_name)\n        ok_force = model.get_joint(\"linear\").set_generalized_force_target(force)\n\n        if not ok_force:\n            raise RuntimeError(\"Failed to set the force to the cart\")\n\n    def get_observation(self) -> Observation:\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the new joint positions and velocities\n        q, x = model.joint_positions([\"pivot\", \"linear\"])\n        dq, dx = model.joint_velocities([\"pivot\", \"linear\"])\n\n        # Create the observation\n        observation = Observation(np.array([x, dx, q, dq]))\n\n        # Return the observation\n        return observation\n\n    def get_reward(self) -> Reward:\n\n        # Calculate the reward\n        reward = 1.0 if not self.is_done() else 0.0\n\n        if self._reward_cart_at_center:\n\n            # Get the observation\n            x, dx, _, _ = self.get_observation()\n\n            reward = (\n                reward\n                - 0.10 * np.abs(x)\n                - 0.10 * np.abs(dx)\n                - 10.0 * (x >= self._x_threshold)\n            )\n\n        return reward\n\n    def is_done(self) -> bool:\n\n        # Get the observation\n        observation = self.get_observation()\n\n        # The environment is done if the observation is outside its space\n        done = not self.reset_space.contains(observation)\n\n        return done\n\n    def reset_task(self) -> None:\n\n        if self.model_name not in self.world.model_names():\n            raise RuntimeError(\"Cartpole model not found in the world\")\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Control the cart in force mode\n        linear = model.get_joint(\"linear\")\n        ok_control_mode = linear.set_control_mode(scenario.JointControlMode_force)\n\n        if not ok_control_mode:\n            raise RuntimeError(\"Failed to change the control mode of the cartpole\")\n\n        # Create a new cartpole state\n        x, dx, q, dq = self.np_random.uniform(low=-0.05, high=0.05, size=(4,))\n\n        # Reset the cartpole state\n        ok_reset_pos = model.to_gazebo().reset_joint_positions(\n            [x, q], [\"linear\", \"pivot\"]\n        )\n        ok_reset_vel = model.to_gazebo().reset_joint_velocities(\n            [dx, dq], [\"linear\", \"pivot\"]\n        )\n\n        if not (ok_reset_pos and ok_reset_vel):\n            raise RuntimeError(\"Failed to reset the cartpole state\")\n"
  },
  {
    "path": "python/gym_ignition_environments/tasks/cartpole_continuous_swingup.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Tuple\n\nimport gym\nimport numpy as np\nfrom gym_ignition.base import task\nfrom gym_ignition.utils.typing import (\n    Action,\n    ActionSpace,\n    Observation,\n    ObservationSpace,\n    Reward,\n)\n\nfrom scenario import core as scenario\n\n\nclass CartPoleContinuousSwingup(task.Task, abc.ABC):\n    def __init__(self, agent_rate: float, reward_cart_at_center: bool = True, **kwargs):\n\n        # Initialize the Task base class\n        task.Task.__init__(self, agent_rate=agent_rate)\n\n        # Name of the cartpole model\n        self.model_name = None\n\n        # Space for resetting the task\n        self.reset_space = None\n\n        # Private attributes\n        self._reward_cart_at_center = reward_cart_at_center\n\n        # Variables limits\n        self._x_threshold = 2.4  # m\n        self._dx_threshold = 20.0  # m /s\n        self._q_threshold = np.deg2rad(5 * 360)  # rad\n        self._dq_threshold = np.deg2rad(3 * 360)  # rad / s\n\n    def create_spaces(self) -> Tuple[ActionSpace, ObservationSpace]:\n\n        # Create the action space\n        max_force = 200.0  # Nm\n        action_space = gym.spaces.Box(\n            low=np.array([-max_force]), high=np.array([max_force]), dtype=np.float32\n        )\n\n        # Configure reset limits\n        high = np.array(\n            [\n                self._x_threshold,  # x\n                self._dx_threshold,  # dx\n                self._q_threshold,  # q\n                self._dq_threshold,  # dq\n            ]\n        )\n\n        # Configure the reset space\n        self.reset_space = gym.spaces.Box(low=-high, high=high, dtype=np.float32)\n\n        # Configure the observation space\n        obs_high = high.copy() * 1.2\n        observation_space = gym.spaces.Box(\n            low=-obs_high, high=obs_high, dtype=np.float32\n        )\n\n        return action_space, observation_space\n\n    def set_action(self, action: Action) -> None:\n\n        # Get the force value\n        force = action.tolist()[0]\n\n        # Set the force value\n        model = self.world.get_model(self.model_name)\n        ok_force = model.get_joint(\"linear\").set_generalized_force_target(force)\n\n        if not ok_force:\n            raise RuntimeError(\"Failed to set the force to the cart\")\n\n    def get_observation(self) -> Observation:\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the new joint positions and velocities\n        q, x = model.joint_positions([\"pivot\", \"linear\"])\n        dq, dx = model.joint_velocities([\"pivot\", \"linear\"])\n\n        # Create the observation\n        observation = Observation(np.array([x, dx, q, dq]))\n\n        # Return the observation\n        return observation\n\n    def get_reward(self) -> Reward:\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the pendulum position\n        q = model.get_joint(\"pivot\").position()\n\n        # Get the cart state\n        x = model.get_joint(\"linear\").position()\n        dx = model.get_joint(\"linear\").velocity()\n\n        # Reward is [0, 1] for q=[0, pi]\n        reward = (np.cos(q) + 1) / 2\n\n        # Penalize cart velocities\n        reward -= 0.1 * (dx ** 2)\n\n        # Penalize positions close to the end of the rail\n        reward -= 10.0 * (x >= 0.8 * self._x_threshold)\n\n        return reward\n\n    def is_done(self) -> bool:\n\n        # Get the observation\n        observation = self.get_observation()\n\n        # The environment is done if the observation is outside its space\n        done = not self.reset_space.contains(observation)\n\n        return done\n\n    def reset_task(self) -> None:\n\n        if self.model_name not in self.world.model_names():\n            raise RuntimeError(\"Cartpole model not found in the world\")\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Control the cart in force mode\n        linear = model.get_joint(\"linear\")\n        ok_control_mode = linear.set_control_mode(scenario.JointControlMode_force)\n\n        if not ok_control_mode:\n            raise RuntimeError(\"Failed to change the control mode of the cartpole\")\n\n        # Create a new cartpole state\n        q = np.pi - np.deg2rad(self.np_random.uniform(low=-60, high=60))\n        x, dx, dq = self.np_random.uniform(low=-0.05, high=0.05, size=(3,))\n\n        # Reset the cartpole state\n        ok_reset_pos = model.to_gazebo().reset_joint_positions(\n            [x, q], [\"linear\", \"pivot\"]\n        )\n        ok_reset_vel = model.to_gazebo().reset_joint_velocities(\n            [dx, dq], [\"linear\", \"pivot\"]\n        )\n\n        if not (ok_reset_pos and ok_reset_vel):\n            raise RuntimeError(\"Failed to reset the cartpole state\")\n"
  },
  {
    "path": "python/gym_ignition_environments/tasks/cartpole_discrete_balancing.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Tuple\n\nimport gym\nimport numpy as np\nfrom gym_ignition.base import task\nfrom gym_ignition.utils.typing import (\n    Action,\n    ActionSpace,\n    Observation,\n    ObservationSpace,\n    Reward,\n)\n\nfrom scenario import core as scenario\n\n\nclass CartPoleDiscreteBalancing(task.Task, abc.ABC):\n    def __init__(\n        self, agent_rate: float, reward_cart_at_center: bool = True, **kwargs\n    ) -> None:\n\n        # Initialize the Task base class\n        task.Task.__init__(self, agent_rate=agent_rate)\n\n        # Name of the cartpole model\n        self.model_name = None\n\n        # Space for resetting the task\n        self.reset_space = None\n\n        # Private attributes\n        self._force_mag = 20.0  # Nm\n        self._reward_cart_at_center = reward_cart_at_center\n\n        # Variables limits\n        self._x_threshold = 2.4  # m\n        self._dx_threshold = 20.0  # m /s\n        self._q_threshold = np.deg2rad(12)  # rad\n        self._dq_threshold = np.deg2rad(3 * 360)  # rad / s\n\n    def create_spaces(self) -> Tuple[ActionSpace, ObservationSpace]:\n\n        # Configure action space: [0, 1]\n        action_space = gym.spaces.Discrete(2)\n\n        # Configure reset limits\n        high = np.array(\n            [\n                self._x_threshold,  # x\n                self._dx_threshold,  # dx\n                self._q_threshold,  # q\n                self._dq_threshold,  # dq\n            ]\n        )\n\n        # Configure the reset space\n        self.reset_space = gym.spaces.Box(low=-high, high=high, dtype=np.float32)\n\n        # Configure the observation space\n        obs_high = high.copy() * 1.2\n        observation_space = gym.spaces.Box(\n            low=-obs_high, high=obs_high, dtype=np.float32\n        )\n\n        return action_space, observation_space\n\n    def set_action(self, action: Action) -> None:\n\n        # Calculate the force\n        force = self._force_mag if action == 1 else -self._force_mag\n\n        # Set the force value\n        model = self.world.get_model(self.model_name)\n        ok_force = model.get_joint(\"linear\").set_generalized_force_target(force)\n\n        if not ok_force:\n            raise RuntimeError(\"Failed to set the force to the cart\")\n\n    def get_observation(self) -> Observation:\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the new joint positions and velocities\n        q, x = model.joint_positions([\"pivot\", \"linear\"])\n        dq, dx = model.joint_velocities([\"pivot\", \"linear\"])\n\n        # Create the observation\n        observation = Observation(np.array([x, dx, q, dq]))\n\n        # Return the observation\n        return observation\n\n    def get_reward(self) -> Reward:\n\n        # Calculate the reward\n        reward = 1.0 if not self.is_done() else 0.0\n\n        if self._reward_cart_at_center:\n\n            # Get the observation\n            x, dx, _, _ = self.get_observation()\n\n            reward = (\n                reward\n                - 0.10 * np.abs(x)\n                - 0.10 * np.abs(dx)\n                - 10.0 * (x >= 0.9 * self._x_threshold)\n            )\n\n        return reward\n\n    def is_done(self) -> bool:\n\n        # Get the observation\n        observation = self.get_observation()\n\n        # The environment is done if the observation is outside its space\n        done = not self.reset_space.contains(observation)\n\n        return done\n\n    def reset_task(self) -> None:\n\n        if self.model_name not in self.world.model_names():\n            raise RuntimeError(\"Cartpole model not found in the world\")\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Control the cart in force mode\n        linear = model.get_joint(\"linear\")\n        ok_control_mode = linear.set_control_mode(scenario.JointControlMode_force)\n\n        if not ok_control_mode:\n            raise RuntimeError(\"Failed to change the control mode of the cartpole\")\n\n        # Create a new cartpole state\n        x, dx, q, dq = self.np_random.uniform(low=-0.05, high=0.05, size=(4,))\n\n        # Reset the cartpole state\n        ok_reset_pos = model.to_gazebo().reset_joint_positions(\n            [x, q], [\"linear\", \"pivot\"]\n        )\n        ok_reset_vel = model.to_gazebo().reset_joint_velocities(\n            [dx, dq], [\"linear\", \"pivot\"]\n        )\n\n        if not (ok_reset_pos and ok_reset_vel):\n            raise RuntimeError(\"Failed to reset the cartpole state\")\n"
  },
  {
    "path": "python/gym_ignition_environments/tasks/pendulum_swingup.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nfrom typing import Tuple\n\nimport gym\nimport numpy as np\nfrom gym_ignition.base import task\nfrom gym_ignition.utils.typing import (\n    Action,\n    ActionSpace,\n    Observation,\n    ObservationSpace,\n    Reward,\n)\n\nfrom scenario import core as scenario\n\n\nclass PendulumSwingUp(task.Task, abc.ABC):\n    def __init__(self, agent_rate: float, **kwargs):\n\n        # Initialize the Task base class\n        task.Task.__init__(self, agent_rate=agent_rate)\n\n        # Name of the pendulum model\n        self.model_name = None\n\n        # Limits\n        self._max_speed = 10.0\n        self._max_torque = 50.0\n\n    def create_spaces(self) -> Tuple[ActionSpace, ObservationSpace]:\n\n        action_space = gym.spaces.Box(\n            low=-self._max_torque, high=self._max_torque, shape=(1,), dtype=np.float32\n        )\n\n        high = np.array([1.0, 1.0, self._max_speed])  # cos(theta)  # sin(theta)\n\n        observation_space = gym.spaces.Box(low=-high, high=high, dtype=np.float32)\n\n        return action_space, observation_space\n\n    def set_action(self, action: Action) -> None:\n\n        # Get the force value\n        force = action.tolist()[0]\n\n        # Set the force value\n        model = self.world.get_model(self.model_name)\n        ok_force = model.get_joint(\"pivot\").set_generalized_force_target(force)\n\n        if not ok_force:\n            raise RuntimeError(\"Failed to set the force to the pendulum\")\n\n    def get_observation(self) -> Observation:\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the new joint position and velocity\n        q = model.get_joint(\"pivot\").position()\n        dq = model.get_joint(\"pivot\").velocity()\n\n        # Create the observation\n        observation = Observation(np.array([np.cos(q), np.sin(q), dq]))\n\n        # Return the observation\n        return observation\n\n    def get_reward(self) -> Reward:\n\n        # This environment is done only if the observation goes outside its limits.\n        # Since it can happen only when velocity is too high, penalize this happening.\n        cost = 100.0 if self.is_done() else 0.0\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Get the pendulum state\n        q = model.get_joint(\"pivot\").position()\n        dq = model.get_joint(\"pivot\").velocity()\n        tau = model.get_joint(\"pivot\").generalized_force_target()\n\n        # Calculate the cost\n        cost += (q ** 2) + 0.1 * (dq ** 2) + 0.001 * (tau ** 2)\n\n        return Reward(-cost)\n\n    def is_done(self) -> bool:\n\n        # Get the observation\n        observation = self.get_observation()\n\n        # The environment is done if the observation is outside its space\n        done = not self.observation_space.contains(observation)\n\n        return done\n\n    def reset_task(self) -> None:\n\n        if self.model_name not in self.world.model_names():\n            raise RuntimeError(\"The cartpole model was not inserted in the world\")\n\n        # Get the model\n        model = self.world.get_model(self.model_name)\n\n        # Control the pendulum in force mode\n        pivot = model.get_joint(\"pivot\")\n        ok_control_mode = pivot.set_control_mode(scenario.JointControlMode_force)\n\n        if not ok_control_mode:\n            raise RuntimeError(\"Failed to change the control mode of the pendulum\")\n\n        # Sample an observation\n        cos_q, sin_q, dq = self.observation_space.sample()\n\n        # Compute the angle\n        q = np.arctan2(sin_q, cos_q)\n\n        # Convert to float\n        q, dq = float(q), float(dq)\n\n        # Reset the pendulum state\n        ok_reset = pivot.to_gazebo().reset(q, dq)\n\n        if not ok_reset:\n            raise RuntimeError(\"Failed to reset the pendulum state\")\n"
  },
  {
    "path": "scenario/CMakeLists.txt",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\ncmake_minimum_required(VERSION 3.16)\nproject(scenario VERSION 1.3.1)\n\n# Add custom functions / macros\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\n\n# C++ standard\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_EXTENSIONS OFF)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n# Include useful features\ninclude(GNUInstallDirs)\n\n# Build type\nif(NOT CMAKE_CONFIGURATION_TYPES)\n    if(NOT CMAKE_BUILD_TYPE)\n        set(CMAKE_BUILD_TYPE \"Release\" CACHE STRING\n            \"Choose the type of build, recommended options are: Debug or Release\" FORCE)\n    endif()\n    set(SCENARIO_BUILD_TYPES \"Debug\" \"Release\" \"MinSizeRel\" \"RelWithDebInfo\")\n    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${SCENARIO_BUILD_TYPES})\nendif()\n\n# Expose shared or static compilation\nset(SCENARIO_BUILD_SHARED_LIBRARY TRUE\n    CACHE BOOL \"Compile libraries as shared libraries\")\nset(BUILD_SHARED_LIBS ${SCENARIO_BUILD_SHARED_LIBRARY})\n\n# Use -fPIC even if statically compiled\nset(CMAKE_POSITION_INDEPENDENT_CODE ON)\n\n# Tweak linker flags in Linux\nif(UNIX AND NOT APPLE)\n    if(\"${CMAKE_BUILD_TYPE}\" STREQUAL \"Debug\")\n        get_filename_component(LINKER_BIN ${CMAKE_LINKER} NAME)\n            if(\"${LINKER_BIN}\" STREQUAL \"ld\")\n                set(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} -Wl,--unresolved-symbols=report-all\")\n            endif()\n    endif()\nendif()\n\n# Control where binaries and libraries are placed in the build folder.\n# This simplifies tests running in Windows.\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}\")\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}\")\n\n# Get include-what-you-use information when compiling\noption(SCENARIO_USE_IWYU \"Get the output of include-what-you-use\" OFF)\nmark_as_advanced(SCENARIO_USE_IWYU)\nif(SCENARIO_USE_IWYU)\n    find_program(IWYU_PATH NAMES include-what-you-use iwyu)\n    if(IWYU_PATH)\n        set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})\n    endif()\nendif()\n\n# Settings for RPATH\nif(NOT MSVC)\n    option(ENABLE_RPATH \"Enable RPATH installation\" TRUE)\n    mark_as_advanced(ENABLE_RPATH)\nendif()\n\n# Dependencies\nadd_subdirectory(deps)\n\nif(${CMAKE_VERSION} VERSION_GREATER 3.15)\n    cmake_policy(SET CMP0094 NEW)\nendif()\n\n# Enable custom options required to package the CMake project from\n# either setup.py or tools like pypa/pip or pypa/build.\nset(SCENARIO_CALL_FROM_SETUP_PY FALSE\n    CACHE BOOL \"Configure the project to be compiled from setuptools\")\n\nfind_package(SWIG 4.0 QUIET)\noption(SCENARIO_ENABLE_BINDINGS \"Enable SWIG bindings\" ${SWIG_FOUND})\n\n# Find Python only if requested or if SWIG was automatically found\nif(SCENARIO_ENABLE_BINDINGS OR SCENARIO_CALL_FROM_SETUP_PY)\n    # Find virtualenv's before system's interpreters\n    set(Python3_FIND_VIRTUALENV \"FIRST\" CACHE STRING\n        \"Configure the detection of virtual environments\")\n    set(Python3_FIND_VIRTUALENV_TYPES \"FIRST\" \"ONLY\" \"STANDARD\")\n    mark_as_advanced(Python3_FIND_VIRTUALENV)\n    set_property(CACHE Python3_FIND_VIRTUALENV PROPERTY STRINGS ${Python3_FIND_VIRTUALENV_TYPES})\n\n    # Find Python3\n    find_package(Python3 COMPONENTS Interpreter Development REQUIRED)\n    message(STATUS \"Using Python: ${Python3_EXECUTABLE}\")\nendif()\n\n# Select the appropriate install prefix used throughout the project\nset(SCENARIO_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR})\nset(SCENARIO_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR})\nset(SCENARIO_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})\n\n# Adjust RPATH dependending on the installation type\nif(SCENARIO_ENABLE_BINDINGS AND NOT SCENARIO_CALL_FROM_SETUP_PY)\n    # Convert folder separators to CMake style (could be necessary in Windows)\n    file(TO_CMAKE_PATH \"${Python3_SITELIB}\" python3_sitelib_cleaned)\n\n    # Add the libraries installed in the Python site-package folder\n    set(EXTRA_RPATH_DIRS\n        \"${python3_sitelib_cleaned}\"\n        \"${python3_sitelib_cleaned}/scenario/bindings\")\n\n    unset(python3_sitelib_cleaned)\nelse()\n    # Add the libraries installed in the Python site-package folder\n    # (that in this case is CMAKE_INSTALL_PREFIX)\n    set(EXTRA_RPATH_DIRS\n        \"${CMAKE_INSTALL_PREFIX}\"\n        \"${CMAKE_INSTALL_PREFIX}/scenario/bindings\")\nendif()\n\n# Configure RPATH\ninclude(AddInstallRPATHSupport)\nadd_install_rpath_support(\n    BIN_DIRS\n    \"${CMAKE_INSTALL_PREFIX}/${SCENARIO_INSTALL_BINDIR}\"\n    LIB_DIRS\n    \"${CMAKE_INSTALL_PREFIX}/${SCENARIO_INSTALL_LIBDIR}\"\n    \"${CMAKE_INSTALL_PREFIX}/${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\"\n    \"${EXTRA_RPATH_DIRS}\"\n    INSTALL_NAME_DIR\n    \"${CMAKE_INSTALL_PREFIX}/${SCENARIO_INSTALL_LIBDIR}\"\n    DEPENDS ENABLE_RPATH\n    USE_LINK_PATH)\n\n# Find a supported Ignition distribution\nif(NOT IGNITION_DISTRIBUTION)\n\n    include(FindIgnitionDistribution)\n    set(SUPPORTED_IGNITION_DISTRIBUTIONS\n        \"Fortress\"\n        \"Edifice\"\n        \"Dome\"\n        \"Citadel\")\n\n    foreach(distribution IN LISTS SUPPORTED_IGNITION_DISTRIBUTIONS)\n\n        find_ignition_distribution(\n            CODENAME ${distribution}\n            PACKAGES\n            ignition-gazebo\n            REQUIRED FALSE)\n\n        if(${${distribution}_FOUND})\n            message(STATUS \"Found Ignition ${distribution}\")\n\n            # Select Ignition distribution\n            set(IGNITION_DISTRIBUTION \"${distribution}\" CACHE\n                STRING \"The Ignition distribution found in the system\")\n            set_property(CACHE IGNITION_DISTRIBUTION PROPERTY\n                STRINGS ${SUPPORTED_IGNITION_DISTRIBUTIONS})\n\n            break()\n        endif()\n\n    endforeach()\n\nendif()\n\nif(NOT IGNITION_DISTRIBUTION OR \"${IGNITION_DISTRIBUTION}\" STREQUAL \"\")\n    set(USE_IGNITION FALSE)\nelse()\n    set(USE_IGNITION TRUE)\nendif()\n\noption(SCENARIO_USE_IGNITION\n       \"Build C++ code depending on Ignition\"\n       ${USE_IGNITION})\n\n# Fail if Ignition is enabled but no compatible distribution was found\nif(SCENARIO_USE_IGNITION AND \"${IGNITION_DISTRIBUTION}\" STREQUAL \"\")\n    message(FATAL_ERROR \"Failed to find a compatible Ignition Gazebo distribution\")\nendif()\n\n# Alias the Ignition targets so that we can link against different distributions\nif(SCENARIO_USE_IGNITION)\n    include(ImportTargets${IGNITION_DISTRIBUTION})\nendif()\n\n# Helper for exporting targets\ninclude(InstallBasicPackageFiles)\n\n# =========\n# SCENARI/O\n# =========\n\nadd_subdirectory(src)\n\n# ========\n# BINDINGS\n# ========\n\n# Require to find Ignition libraries when packaging for PyPI\nif(SCENARIO_CALL_FROM_SETUP_PY AND NOT USE_IGNITION)\n    message(FATAL_ERROR \"Found no Ignition distribution for PyPI package\")\nendif()\n\nif(SCENARIO_ENABLE_BINDINGS)\n    add_subdirectory(bindings)\nendif()\n\n# Add unistall target\ninclude(AddUninstallTarget)\n"
  },
  {
    "path": "scenario/README.md",
    "content": "# ScenarIO\n\n[![C++ standard](https://img.shields.io/badge/standard-C++17-blue.svg?style=flat&logo=c%2B%2B)](https://isocpp.org)\n[![Size](https://img.shields.io/github/languages/code-size/robotology/gym-ignition.svg)][scenario]\n[![Lines](https://img.shields.io/tokei/lines/github/robotology/gym-ignition)][gym-ignition]\n[![Python CI/CD](https://github.com/robotology/gym-ignition/workflows/CI/CD/badge.svg)](https://github.com/robotology/gym-ignition/actions)\n\n[![Version](https://img.shields.io/pypi/v/scenario.svg)][pypi]\n[![Python versions](https://img.shields.io/pypi/pyversions/scenario.svg)][pypi]\n[![Status](https://img.shields.io/pypi/status/scenario.svg)][pypi]\n[![Format](https://img.shields.io/pypi/format/scenario.svg)][pypi]\n[![License](https://img.shields.io/pypi/l/scenario.svg)][pypi]\n\n[pypi]: https://pypi.org/project/scenario/\n[gym-ignition]: https://github.com/robotology/gym-ignition\n[scenario]: https://github.com/robotology/gym-ignition/tree/master/scenario\n\n**SCEN**e interf**A**ces for **R**obot **I**nput / **O**utput.\n\n||||\n|:---:|:---:|:---:|\n| ![][pendulum] | ![][panda] | ![][icub] |\n\n[icub]: https://user-images.githubusercontent.com/469199/99262746-9e021a80-281e-11eb-9df1-d70134b0801a.png\n[panda]: https://user-images.githubusercontent.com/469199/99263111-0cdf7380-281f-11eb-9cfe-338b2aae0503.png\n[pendulum]: https://user-images.githubusercontent.com/469199/99262383-321fb200-281e-11eb-89cc-cc31f590daa3.png\n\n## Description\n\n**ScenarIO** is a C++ abstraction layer to interact with simulated and real robots.\n\nIt mainly provides the following \n[C++ interfaces](https://github.com/robotology/gym-ignition/tree/master/scenario/core/include/scenario/core):\n\n- `scenario::core::World`\n- `scenario::core::Model`\n- `scenario::core::Link`\n- `scenario::core::Joint`\n\nThese interfaces can be implemented to operate on different scenarios, \nincluding robots operating on either simulated worlds or in real-time.\n\nScenarIO currently fully implements **Gazebo ScenarIO**, \na simulated back-end that interacts with [Ignition Gazebo](https://ignitionrobotics.org).\nThe result allows stepping the simulator programmatically, ensuring a fully reproducible behaviour.\nIt relates closely to other projects like\n[pybullet](https://github.com/bulletphysics/bullet3) and [mujoco-py](https://github.com/openai/mujoco-py).\n\nA real-time backend that interacts with the [YARP](https://github.com/robotology/yarp) middleware is under development.\n\nScenarIO can be used either from C++ ([APIs](https://robotology.github.io/gym-ignition/master/breathe/core.html)) \nor from Python ([APIs](https://robotology.github.io/gym-ignition/master/apidoc/scenario/scenario.bindings.html)).\n\nIf you're interested to know the reasons why we started developing ScenarIO and why we selected Ignition Gazebo \nfor our simulations, visit the _Motivations_ section of the \n[website][website].\n\n## Installation\n\nScenarIO only supports a single distribution of the Ignition suite.\nVisit our [Support Policy](https://robotology.github.io/gym-ignition/master/installation/support_policy.html)\nto check the distribution currently supported.\n\nThen, install the supported Ignition suite following the \n[official instructions](https://ignitionrobotics.org/docs/fortress).\n\n### Python\n\nExecute, preferably in a [virtual environment](https://docs.python.org/3.8/tutorial/venv.html):\n\n```bash\npip install scenario\n```\n\n### C++\n\nYou can either clone and install the standalone project:\n\n```cmake\ngit clone https://github.com/robotology/gym-ignition\ncd gym-ignition/scenario\ncmake -S . -B build/\ncmake --build build/ --target install\n```\n\nor include it in your CMake project with\n[`FetchContent`](https://cmake.org/cmake/help/latest/module/FetchContent.html).\n\n## Usage\n\nYou can find some examples that show the usage of ScenarIO in the _Getting Started_ section of the\n[website][website].\n\n## Contributing\n\nPlease visit the _Limitations_ section of the [website][website] and check the \n[`good first issue`](https://github.com/robotology/gym-ignition/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)\nand\n[`help wanted`](https://github.com/robotology/gym-ignition/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)\nissues.\n\nYou can visit our community forum hosted in [GitHub Discussions](https://github.com/robotology/gym-ignition/discussions).\nEven without coding skills, replying user's questions is a great way of contributing.\nIf you use ScenarIO in your application and want to show it off, visit the \n[Show and tell](https://github.com/robotology/gym-ignition/discussions/categories/show-and-tell) section!\n\nPull requests are welcome.\n\nFor major changes, please open a [discussion](https://github.com/robotology/gym-ignition/discussions)\nfirst to propose what you would like to change.\n\n## Citation\n\n```bibtex\n@INPROCEEDINGS{ferigo2020gymignition,\n    title={Gym-Ignition: Reproducible Robotic Simulations for Reinforcement Learning},\n    author={D. {Ferigo} and S. {Traversaro} and G. {Metta} and D. {Pucci}},\n    booktitle={2020 IEEE/SICE International Symposium on System Integration (SII)},\n    year={2020},\n    pages={885-890},\n    doi={10.1109/SII46433.2020.9025951}\n} \n```\n\n## License\n\n[LGPL v2.1](https://choosealicense.com/licenses/lgpl-2.1/) or any later version.\n\nWe vendor some resources from the Ignition code base.\nFor this reason, Gazebo ScenarIO is double-licensed with the \n[Apache License](https://choosealicense.com/licenses/apache-2.0/).\n\n[website]: https://robotology.github.io/gym-ignition\n"
  },
  {
    "path": "scenario/bindings/CMakeLists.txt",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# The SWIG bindings are installed as a standalone <scenario> Python package.\n#\n# We create with CMake the following structure in the build tree:\n#\n# <build>/bindings/scenario/\n# ├── bindings\n# │   ├── core.py\n# │   ├── _core.so\n# │   ├── gazebo.py\n# │   ├── _gazebo.so\n# │   └── __init__.py\n# └── __init__.py\n#\n# That is later installed either in the active virtualenv or packaged\n# as a PyPI package. The former is related to the Develop Installation\n# and the latter to the User Installation.\n#\n# Having a working Python package tree in the build folder has multiple\n# benefit, including the possibility to use it without installing.\n# Beyond this reason, our documentation pipeline requires to import\n# a working package from the build tree.\n\nif(${CMAKE_VERSION} VERSION_GREATER 3.13)\n    cmake_policy(SET CMP0078 NEW)\nendif()\n\nif(${CMAKE_VERSION} VERSION_GREATER 3.14)\n    cmake_policy(SET CMP0086 NEW)\nendif()\n\nfind_package(SWIG 4.0 REQUIRED)\nset(UseSWIG_MODULE_VERSION 2)\ninclude(${SWIG_USE_FILE})\n\n# By default, install ScenarIO in the python site-package directory\nif(NOT BINDINGS_INSTALL_PREFIX)\n    set(BINDINGS_INSTALL_PREFIX ${Python3_SITELIB})\nendif()\n\n# Expose the install prefix as CMake option\nset(BINDINGS_INSTALL_PREFIX \"${BINDINGS_INSTALL_PREFIX}\"\n    CACHE STRING \"Installation prefix of the bindings\")\n\n# Final directory of the \"scenario\" package\nif(NOT SCENARIO_CALL_FROM_SETUP_PY)\n    set(SCENARIO_PACKAGE_INSTALL_DIR \"${BINDINGS_INSTALL_PREFIX}/scenario\")\nelse()\n    # If packaging for PyPI, install ScenarIO in the temp site-package directory\n    # created by either setup.py or pip.\n    # The \"scenario/\" folder is added by cmake_build_extension\n    set(SCENARIO_PACKAGE_INSTALL_DIR \"${CMAKE_INSTALL_PREFIX}\")\nendif()\n\n# Add the SWIG folders\nadd_subdirectory(core)\nif(SCENARIO_USE_IGNITION)\n    add_subdirectory(gazebo)\nendif()\n\n# Move main init.py file to package root of the build tree\nconfigure_file(\n    ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py\n    ${CMAKE_CURRENT_BINARY_DIR}/scenario/__init__.py)\n\n# Make scenario.bindings a package\nfile(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/scenario/bindings)\nfile(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/scenario/bindings/__init__.py)\n\n# Move main init.py file to package root of the install tree\ninstall(\n    FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py\n    DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}\n    COMPONENT python)\n"
  },
  {
    "path": "scenario/bindings/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport os\nimport sys\nfrom enum import Enum, auto\nfrom pathlib import Path\n\nimport packaging.specifiers\nimport packaging.version\n\n\ndef supported_versions_specifier_set() -> packaging.specifiers.SpecifierSet:\n\n    # If 6 is the Ignition distribution major version, the following specifier enables\n    # the compatibility with all the following versions:\n    #\n    # 6.Y.Z.devK\n    # 6.Y.Z.alphaK\n    # 6.Y.Z.betaK\n    # 6.Y.Z.rcK\n    # 6.Y.Z.preK\n    # 6.Y.Z.postK\n    #\n    return packaging.specifiers.SpecifierSet(\">=6.0.0.pre,<7.0.0.dev\")\n\n\nclass InstallMode(Enum):\n    User = auto()\n    CondaBuild = auto()\n    Developer = auto()\n\n\ndef detect_install_mode() -> InstallMode:\n\n    import scenario.bindings.core\n\n    install_prefix = scenario.bindings.core.get_install_prefix()\n\n    # In conda, there are null bytes terminating the returned string\n    install_prefix = install_prefix.replace(\"\\x00\", \"\")\n\n    if \"$PREFIX\" in install_prefix:\n        return InstallMode.CondaBuild\n\n    if install_prefix == \"\":\n        return InstallMode.User\n    else:\n        return InstallMode.Developer\n\n\ndef setup_gazebo_environment() -> None:\n\n    import scenario.bindings.core\n\n    # Configure the environment\n    ign_gazebo_system_plugin_path = \"\"\n\n    if \"IGN_GAZEBO_SYSTEM_PLUGIN_PATH\" in os.environ:\n        ign_gazebo_system_plugin_path = os.environ.get(\"IGN_GAZEBO_SYSTEM_PLUGIN_PATH\")\n\n    # Exporting this env variable is done by the conda \"libscenario\" package\n    if detect_install_mode() is InstallMode.CondaBuild:\n        return\n\n    # Add the plugins path\n    if detect_install_mode() is InstallMode.Developer:\n        install_prefix = scenario.bindings.core.get_install_prefix()\n\n        # In conda, there are null bytes terminating the returned string\n        install_prefix = Path(install_prefix.replace(\"\\x00\", \"\"))\n\n    elif detect_install_mode() is InstallMode.User:\n        install_prefix = Path(os.path.dirname(__file__))\n\n    else:\n        raise ValueError(detect_install_mode())\n\n    plugin_dir = install_prefix / \"lib\" / \"scenario\" / \"plugins\"\n    ign_gazebo_system_plugin_path += f\":{str(plugin_dir)}\"\n\n    os.environ[\"IGN_GAZEBO_SYSTEM_PLUGIN_PATH\"] = ign_gazebo_system_plugin_path\n\n\ndef preload_tensorflow_shared_libraries() -> None:\n\n    # Check if tensorflow is installed\n    import importlib.util\n\n    spec = importlib.util.find_spec(\"tensorflow\")\n\n    if spec is None:\n        return\n\n    # Get the tensorflow __init__ location\n    import pathlib\n\n    init = pathlib.Path(spec.origin)\n\n    # Get the tensorflow top-level folder\n    tensorflow_dir = init.parent\n    assert tensorflow_dir.is_dir()\n\n    # Get the tensorflow/python folder\n    tensorflow_python_dir = tensorflow_dir / \"python\"\n    assert tensorflow_python_dir.is_dir()\n\n    # Load the main shared library\n    for lib in tensorflow_dir.glob(\"*tensorflow*.so*\"):\n        import ctypes\n\n        ctypes.CDLL(str(lib))\n\n    # Load all the shared libraries inside tensorflow/python\n    for lib in tensorflow_python_dir.glob(\"_*.so\"):\n        import ctypes\n\n        ctypes.CDLL(str(lib))\n\n\ndef pre_import_gym() -> None:\n\n    # Check if gym is installed\n    import importlib.util\n\n    spec = importlib.util.find_spec(\"gym\")\n\n    if spec is None:\n        return\n\n    import gym\n\n\ndef check_gazebo_installation() -> None:\n\n    import subprocess\n\n    try:\n        command = [\"ign\", \"gazebo\", \"--versions\"]\n        result = subprocess.run(command, capture_output=True, text=True, check=True)\n    except FileNotFoundError:\n        msg = \"Failed to find the 'ign' command in your PATH. \"\n        msg += \"Make sure that Ignition is installed \"\n        msg += \"and your environment is properly configured.\"\n        raise RuntimeError(msg)\n    except subprocess.CalledProcessError:\n        raise RuntimeError(f\"Failed to execute command: {' '.join(command)}\")  # noqa\n\n    # Strip the command output\n    gazebo_versions_string = result.stdout.strip()\n\n    # Get the gazebo version from the command line.\n    # Since the releases could be in the \"6.0.0~preK\" form, we replace '~' with '.' to\n    # be compatible with the 'packaging' package.\n    gazebo_version_string_normalized = gazebo_versions_string.replace(\"~\", \".\")\n\n    # The output could be multiline, listing all the Ignition Gazebo versions found\n    gazebo_versions = gazebo_version_string_normalized.split(sep=os.linesep)\n\n    try:\n        # Parse the gazebo versions\n        gazebo_versions_parsed = [packaging.version.Version(v) for v in gazebo_versions]\n    except:\n        raise RuntimeError(\n            f\"Failed to parse the output of: {' '.join(command)} ({gazebo_versions})\"\n        )\n\n    for version in gazebo_versions_parsed:\n        if version in supported_versions_specifier_set():\n            return\n\n    msg = f\"Failed to find Ignition Gazebo {supported_versions_specifier_set()} \"\n    msg += f\"(found incompatible version(s): {gazebo_versions_parsed})\"\n    raise RuntimeError(msg)\n\n\ndef import_gazebo() -> None:\n\n    # Check the the module was never loaded by someone else\n    if \"scenario.bindings._gazebo\" in sys.modules:\n        raise ImportError(\"Failed to load ScenarIO Gazebo with custom dlopen flags\")\n\n    # Preload the shared libraries of tensorflow if the package is installed.\n    # If tensorflow is imported after scenario.bindings.gazebo, the application segfaults.\n    if os.environ.get(\"SCENARIO_DISABLE_TENSORFLOW_PRELOAD\") != \"1\":\n        preload_tensorflow_shared_libraries()\n\n    # Import gym before scenario.bindings.gazebo. Similarly to tensorflow, also gym\n    # includes a module that imports protobuf, producing a similar segfault.\n    if os.environ.get(\"SCENARIO_DISABLE_GYM_PREIMPORT\") != \"1\":\n        pre_import_gym()\n\n    # Import SWIG bindings\n    # See https://github.com/robotology/gym-ignition/issues/7\n    #     https://stackoverflow.com/a/45473441/12150968\n    if sys.platform.startswith(\"linux\") or sys.platform.startswith(\"darwin\"):\n\n        # Update the dlopen flags\n        dlopen_flags = sys.getdlopenflags()\n        sys.setdlopenflags(dlopen_flags | os.RTLD_GLOBAL)\n\n        import scenario.bindings.gazebo\n\n        # Restore the flags\n        sys.setdlopenflags(dlopen_flags)\n\n    else:\n        import scenario.bindings.gazebo\n\n\ndef create_home_dot_folder() -> None:\n\n    # Make sure that the dot folder in the user's home exists\n    Path(\"~/.ignition/gazebo\").expanduser().mkdir(\n        mode=0o755, parents=True, exist_ok=True\n    )\n\n\n# ===================\n# Import the bindings\n# ===================\n\n# Find the _gazebo.* shared lib\nif len(list((Path(__file__).parent / \"bindings\").glob(pattern=\"_gazebo.*\"))) == 1:\n\n    check_gazebo_installation()\n    import_gazebo()\n    create_home_dot_folder()\n    setup_gazebo_environment()\n    from .bindings import gazebo\n\n# Find the _yarp.* shared lib\nif len(list((Path(__file__).parent / \"bindings\").glob(pattern=\"_yarp.*\"))) == 1:\n    from .bindings.yarp import yarp\n\nfrom .bindings import core\n"
  },
  {
    "path": "scenario/bindings/core/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nset(scenario_swig_name \"core\")\nset_source_files_properties(${scenario_swig_name}.i PROPERTIES CPLUSPLUS ON)\n\n# The bindings shared library is stored in the Python package of the build tree\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../scenario/bindings)\n\nswig_add_library(${scenario_swig_name}\n    TYPE MODULE\n    LANGUAGE python\n    OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/../scenario/bindings\n    OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/..\n    SOURCES ${scenario_swig_name}.i)\nadd_library(ScenarioSwig::Core ALIAS core)\n\ntarget_link_libraries(${scenario_swig_name} PUBLIC\n    ScenarioCore::ScenarioABC\n    ScenarioCore::CoreUtils\n    Python3::Python)\n\nset_property(TARGET ${scenario_swig_name} PROPERTY\n    SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)\n\nset_property(TARGET ${scenario_swig_name}\n    PROPERTY SWIG_COMPILE_OPTIONS -doxygen)\n\n# Add the to_gazebo() helpers\nif(SCENARIO_USE_IGNITION)\n    set_property(TARGET ${scenario_swig_name} PROPERTY\n        SWIG_COMPILE_DEFINITIONS SCENARIO_HAS_GAZEBO)\n    set_property(TARGET ${scenario_swig_name} PROPERTY\n        SWIG_DEPENDS \"../gazebo/to_gazebo.i\")\n    target_link_libraries(${scenario_swig_name} PUBLIC ScenarioGazebo)\nendif()\n\n# Get the core.py wrapper file\nget_property(WRAPPER_PY_FILE TARGET ${scenario_swig_name} PROPERTY SWIG_SUPPORT_FILES)\n\ninstall(\n    TARGETS ${scenario_swig_name}\n    COMPONENT python\n    LIBRARY DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    ARCHIVE DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    RUNTIME DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings)\n\ninstall(\n    FILES ${WRAPPER_PY_FILE}\n    DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    COMPONENT python)\n"
  },
  {
    "path": "scenario/bindings/core/core.i",
    "content": "%module(package=\"scenario.bindings\") core\n\n%{\n#define SWIG_FILE_WITH_INIT\n#include \"scenario/core/Joint.h\"\n#include \"scenario/core/Link.h\"\n#include \"scenario/core/Model.h\"\n#include \"scenario/core/World.h\"\n#include \"scenario/core/utils/utils.h\"\n%}\n\n%naturalvar;\n\n// Convert all exceptions to RuntimeError\n%include \"exception.i\"\n%exception {\n  try {\n    $action\n  } catch (const std::exception& e) {\n    SWIG_exception(SWIG_RuntimeError, e.what());\n  }\n}\n\n// STL classes\n%include <stdint.i>\n%include <std_pair.i>\n%include <std_array.i>\n%include <std_string.i>\n%include <std_vector.i>\n%include <std_shared_ptr.i>\n\n// Convert python list to std::vector\n%template(VectorI) std::vector<int>;\n%template(VectorU) std::vector<size_t>;\n%template(VectorF) std::vector<float>;\n%template(VectorD) std::vector<double>;\n%template(VectorS) std::vector<std::string>;\n\n// Convert python list to std::array\n%template(Array3d) std::array<double, 3>;\n%template(Array4d) std::array<double, 4>;\n%template(Array6d) std::array<double, 6>;\n\n// Pair instantiation\n%template(PosePair) std::pair<std::array<double, 3>, std::array<double, 4>>;\n\n// ScenarI/O templates\n%template(VectorOfLinks) std::vector<scenario::core::LinkPtr>;\n%template(VectorOfJoints) std::vector<scenario::core::JointPtr>;\n%template(VectorOfContacts) std::vector<scenario::core::Contact>;\n%template(VectorOfContactPoints) std::vector<scenario::core::ContactPoint>;\n\n// Doxygen typemaps\n%typemap(doctype) std::array<double, 3> \"Tuple[float, float, float]\";\n%typemap(doctype) std::array<double, 4> \"Tuple[float, float, float, float]\";\n%typemap(doctype) std::array<double, 6> \"Tuple[float, float, float, float, float, float]\";\n%typemap(doctype) std::vector<double> \"Tuple[float]\";\n%typemap(doctype) std::vector<std::string> \"Tuple[string]\";\n%typemap(doctype) std::vector<scenario::core::LinkPtr> \"Tuple[Link]\";\n%typemap(doctype) std::vector<scenario::core::JointPtr> \"Tuple[Joint]\";\n%typemap(doctype) std::vector<scenario::core::Contact> \"Tuple[Contact]\";\n%typemap(doctype) std::vector<scenario::core::ContactPoint> \"Tuple[ContactPoint]\";\n\n%pythonbegin %{\nfrom typing import Tuple\n%}\n\n// NOTE: Keep all template instantiations above.\n// Rename all methods to undercase with _ separators excluding the classes.\n%rename(\"%(undercase)s\") \"\";\n%rename(\"\") PID;\n%rename(\"\") Pose;\n%rename(\"\") Link;\n%rename(\"\") Joint;\n%rename(\"\") Model;\n%rename(\"\") World;\n%rename(\"\") Limit;\n%rename(\"\") Contact;\n%rename(\"\") JointType;\n%rename(\"\") JointLimit;\n%rename(\"\") ContactPoint;\n%rename(\"\") JointControlMode;\n\n// Public helpers\n%include \"scenario/core/utils/utils.h\"\n\n// Other templates for ScenarI/O APIs\n%shared_ptr(scenario::core::Joint)\n%shared_ptr(scenario::core::Link)\n%shared_ptr(scenario::core::Model)\n%shared_ptr(scenario::core::World)\n\n// ScenarI/O core headers\n%include \"scenario/core/Joint.h\"\n%include \"scenario/core/Link.h\"\n%include \"scenario/core/Model.h\"\n%include \"scenario/core/World.h\"\n\n// Downcast pointers to the implementation classes\n#if defined (SCENARIO_HAS_GAZEBO)\n%include \"../gazebo/to_gazebo.i\"\n#endif\n"
  },
  {
    "path": "scenario/bindings/gazebo/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nset(scenario_swig_name \"gazebo\")\nset_source_files_properties(${scenario_swig_name}.i PROPERTIES CPLUSPLUS ON)\n\n# The bindings shared library is stored in the Python package of the build tree\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../scenario/bindings)\n\nswig_add_library(${scenario_swig_name}\n    TYPE MODULE\n    LANGUAGE python\n    OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/../scenario/bindings\n    OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/..\n    SOURCES ${scenario_swig_name}.i)\n\ntarget_link_libraries(${scenario_swig_name}\n    PUBLIC\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioGazebo::GazeboSimulator\n    Python3::Python)\nadd_library(ScenarioSwig::Gazebo ALIAS gazebo)\n\nset_property(TARGET ${scenario_swig_name} PROPERTY\n    SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)\n\n# https://github.com/swig/swig/issues/672#issuecomment-400577864\nset_property(TARGET ${scenario_swig_name} PROPERTY\n    SWIG_COMPILE_OPTIONS -doxygen -Dfinal)\n\n# Disable SWIG debug code due to the following error:\n#   int SWIG_Python_ConvertPtrAndOwn(PyObject *, void **, swig_type_info *, int, int *):\n#   Assertion `own' failed.\n# https://github.com/swig/swig/issues/731\n# https://github.com/swig/swig/issues/773\ntarget_compile_definitions(${scenario_swig_name} PRIVATE NDEBUG)\n\n# Get the gazebo.py wrapper file\nget_property(WRAPPER_PY_FILE TARGET ${scenario_swig_name} PROPERTY SWIG_SUPPORT_FILES)\n\ninstall(\n    TARGETS ${scenario_swig_name}\n    COMPONENT python\n    LIBRARY DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    ARCHIVE DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    RUNTIME DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings)\n\ninstall(\n    FILES ${WRAPPER_PY_FILE}\n    DESTINATION ${SCENARIO_PACKAGE_INSTALL_DIR}/bindings\n    COMPONENT python)\n"
  },
  {
    "path": "scenario/bindings/gazebo/gazebo.i",
    "content": "%module(package=\"scenario.bindings\") gazebo\n\n%{\n#define SWIG_FILE_WITH_INIT\n#include \"scenario/gazebo/GazeboEntity.h\"\n#include \"scenario/gazebo/GazeboSimulator.h\"\n#include \"scenario/gazebo/Joint.h\"\n#include \"scenario/gazebo/Link.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/utils.h\"\n#include \"scenario/gazebo/World.h\"\n#include <cstdint>\n%}\n\n%naturalvar;\n\n// Keep templated functions above the %rename directive\n%inline %{\nnamespace scenario::gazebo::utils {\n    template <typename Base, typename Derived>\n    std::shared_ptr<Derived> ToGazebo(const std::shared_ptr<Base>& base)\n    {\n        return std::dynamic_pointer_cast<Derived>(base);\n    }\n}\n%}\n\n// Helpers for downcasting to Gazebo classes\n%template(ToGazeboWorld) scenario::gazebo::utils::ToGazebo<scenario::core::World, scenario::gazebo::World>;\n%template(ToGazeboModel) scenario::gazebo::utils::ToGazebo<scenario::core::Model, scenario::gazebo::Model>;\n%template(ToGazeboJoint) scenario::gazebo::utils::ToGazebo<scenario::core::Joint, scenario::gazebo::Joint>;\n%template(ToGazeboLink) scenario::gazebo::utils::ToGazebo<scenario::core::Link, scenario::gazebo::Link>;\n\n// STL classes\n%include <stdint.i>\n%include <std_pair.i>\n%include <std_array.i>\n%include <std_string.i>\n%include <std_vector.i>\n%include <std_shared_ptr.i>\n\n// Import the module with core classes\n// From http://www.swig.org/Doc4.0/Modules.html\n%import \"../core/core.i\"\n\n// NOTE: Keep all template instantiations above.\n// Rename all methods to undercase with _ separators excluding the classes.\n%rename(\"%(undercase)s\") \"\";\n%rename(\"\") PID;\n%rename(\"\") Pose;\n%rename(\"\") Link;\n%rename(\"\") Joint;\n%rename(\"\") Model;\n%rename(\"\") World;\n%rename(\"\") Limit;\n%rename(\"\") Contact;\n%rename(\"\") JointType;\n%rename(\"\") Verbosity;\n%rename(\"\") JointLimit;\n%rename(\"\") ContactPoint;\n%rename(\"\") GazeboEntity;\n%rename(\"\") PhysicsEngine;\n%rename(\"\") GazeboSimulator;\n%rename(\"\") JointControlMode;\n\n// Other templates for ScenarI/O APIs\n%shared_ptr(scenario::gazebo::Joint)\n%shared_ptr(scenario::gazebo::Link)\n%shared_ptr(scenario::gazebo::Model)\n%shared_ptr(scenario::gazebo::World)\n%shared_ptr(scenario::gazebo::GazeboEntity)\n\n// Ignored methods\n%ignore scenario::gazebo::GazeboEntity::ecm;\n%ignore scenario::gazebo::GazeboEntity::initialize;\n%ignore scenario::gazebo::GazeboEntity::validEntity;\n%ignore scenario::gazebo::GazeboEntity::eventManager;\n%ignore scenario::gazebo::GazeboEntity::createECMResources;\n\n// Workaround for https://github.com/swig/swig/issues/1830\n%feature(\"pythonprepend\") scenario::gazebo::World::getModel %{\n    r\"\"\"\n    Get a model part of the world.\n\n    :type modelName: string\n    :param modelName: The name of the model to get.\n    :rtype: :py:class:`scenario.core.Model`\n    :return: The model if it is part of the world, None otherwise.\n    \"\"\"\n%}\n\n// Interface of Gazebo entities\n%include \"scenario/gazebo/GazeboEntity.h\"\n\n// Public helpers\n%include \"scenario/gazebo/utils.h\"\n\n// ScenarI/O headers\n%include \"scenario/gazebo/Joint.h\"\n%include \"scenario/gazebo/Link.h\"\n%include \"scenario/gazebo/Model.h\"\n%include \"scenario/gazebo/World.h\"\n\n// GazeboSimulator\n%include \"scenario/gazebo/GazeboSimulator.h\"\n"
  },
  {
    "path": "scenario/bindings/gazebo/to_gazebo.i",
    "content": "%pythonbegin %{\nfrom typing import Union\n%}\n\n%extend scenario::core::World {\n  %pythoncode %{\n    def to_gazebo(self) -> Union[\"scenario.bindings.gazebo.World\", \"scenario.bindings.core.World\"]:\n        import scenario.bindings.gazebo\n        return scenario.bindings.gazebo.ToGazeboWorld(self)\n  %}\n}\n\n%extend scenario::core::Model {\n  %pythoncode %{\n    def to_gazebo(self) -> Union[\"scenario.bindings.gazebo.Model\", \"scenario.bindings.core.Model\"]:\n        import scenario.bindings.gazebo\n        return scenario.bindings.gazebo.ToGazeboModel(self)\n  %}\n}\n\n%extend scenario::core::Joint {\n  %pythoncode %{\n    def to_gazebo(self) -> Union[\"scenario.bindings.gazebo.Joint\", \"scenario.bindings.core.Joint\"]:\n        import scenario.bindings.gazebo\n        return scenario.bindings.gazebo.ToGazeboJoint(self)\n  %}\n}\n\n%extend scenario::core::Link {\n  %pythoncode %{\n    def to_gazebo(self) -> Union[\"scenario.bindings.gazebo.Link\", \"scenario.bindings.core.Link\"]:\n        import scenario.bindings.gazebo\n        return scenario.bindings.gazebo.ToGazeboLink(self)\n  %}\n}\n"
  },
  {
    "path": "scenario/cmake/AddUninstallTarget.cmake",
    "content": "#.rst:\n# AddUninstallTarget\n# ------------------\n#\n# Add the \"uninstall\" target for your project::\n#\n#   include(AddUninstallTarget)\n#\n#\n# will create a file ``cmake_uninstall.cmake`` in the build directory and add a\n# custom target ``uninstall`` (or ``UNINSTALL`` on Visual Studio and Xcode) that\n# will remove the files installed by your package (using\n# ``install_manifest.txt``).\n# See also\n# https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake\n#\n# The :module:`AddUninstallTarget` module must be included in your main\n# ``CMakeLists.txt``. If included in a subdirectory it does nothing.\n# This allows you to use it safely in your main ``CMakeLists.txt`` and include\n# your project using ``add_subdirectory`` (for example when using it with\n# :cmake:module:`FetchContent`).\n#\n# If the ``uninstall`` target already exists, the module does nothing.\n\n#=============================================================================\n# Copyright 2008-2013 Kitware, Inc.\n# Copyright 2013 Istituto Italiano di Tecnologia (IIT)\n#   Authors: Daniele E. Domenichelli <daniele.domenichelli@iit.it>\n#\n# Distributed under the OSI-approved BSD License (the \"License\");\n# see accompanying file Copyright.txt for details.\n#\n# This software is distributed WITHOUT ANY WARRANTY; without even the\n# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the License for more information.\n#=============================================================================\n# (To distribute this file outside of CMake, substitute the full\n#  License text for the above reference.)\n\n\n# AddUninstallTarget works only when included in the main CMakeLists.txt\nif(NOT \"${CMAKE_CURRENT_BINARY_DIR}\" STREQUAL \"${CMAKE_BINARY_DIR}\")\n  return()\nendif()\n\n# The name of the target is uppercase in MSVC and Xcode (for coherence with the\n# other standard targets)\nif(\"${CMAKE_GENERATOR}\" MATCHES \"^(Visual Studio|Xcode)\")\n  set(_uninstall \"UNINSTALL\")\nelse()\n  set(_uninstall \"uninstall\")\nendif()\n\n# If target is already defined don't do anything\nif(TARGET ${_uninstall})\n  return()\nendif()\n\n\nset(_filename cmake_uninstall.cmake)\n\nfile(WRITE \"${CMAKE_CURRENT_BINARY_DIR}/${_filename}\"\n\"if(NOT EXISTS \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\")\n  message(WARNING \\\"Cannot find install manifest: \\\\\\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\\\\\"\\\")\n  return()\nendif()\nfile(READ \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\" files)\nstring(STRIP \\\"\\${files}\\\" files)\nstring(REGEX REPLACE \\\"\\\\n\\\" \\\";\\\" files \\\"\\${files}\\\")\nlist(REVERSE files)\nforeach(file \\${files})\n  if(IS_SYMLINK \\\"\\$ENV{DESTDIR}\\${file}\\\" OR EXISTS \\\"\\$ENV{DESTDIR}\\${file}\\\")\n    message(STATUS \\\"Uninstalling: \\$ENV{DESTDIR}\\${file}\\\")\n    execute_process(\n      COMMAND \\${CMAKE_COMMAND} -E remove \\\"\\$ENV{DESTDIR}\\${file}\\\"\n      OUTPUT_VARIABLE rm_out\n      RESULT_VARIABLE rm_retval)\n    if(NOT \\\"\\${rm_retval}\\\" EQUAL 0)\n      message(FATAL_ERROR \\\"Problem when removing \\\\\\\"\\$ENV{DESTDIR}\\${file}\\\\\\\"\\\")\n    endif()\n  else()\n    message(STATUS \\\"Not-found: \\$ENV{DESTDIR}\\${file}\\\")\n  endif()\nendforeach(file)\n\")\n\nset(_desc \"Uninstall the project...\")\nif(CMAKE_GENERATOR STREQUAL \"Unix Makefiles\")\n  set(_comment COMMAND \\$\\(CMAKE_COMMAND\\) -E cmake_echo_color --switch=$\\(COLOR\\) --cyan \"${_desc}\")\nelse()\n  set(_comment COMMENT \"${_desc}\")\nendif()\nadd_custom_target(${_uninstall}\n                  ${_comment}\n                  COMMAND ${CMAKE_COMMAND} -P ${_filename}\n                  USES_TERMINAL\n                  BYPRODUCTS uninstall_byproduct\n                  WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")\nset_property(SOURCE uninstall_byproduct PROPERTY SYMBOLIC 1)\n\nset_property(TARGET ${_uninstall} PROPERTY FOLDER \"CMakePredefinedTargets\")\n\n"
  },
  {
    "path": "scenario/cmake/AliasImportedTarget.cmake",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nmacro(alias_imported_target)\n\n    set(_prefix \"ait\")\n    string(TOUPPER ${_prefix} _prefix)\n\n    set(_oneValueArgs\n        PACKAGE_ORIG\n        PACKAGE_DEST\n        NAMESPACE_ORIG\n        NAMESPACE_DEST\n        REQUIRED)\n\n    set(_multiValueArgs\n        COMPONENTS\n        TARGETS_ORIG\n        TARGETS_DEST)\n\n    set(_options)\n\n    # For each {one,multi}value variable FOO, this command creates\n    # the variable ${_prefix}_FOO with the passed arg(s)\n    cmake_parse_arguments(${_prefix}\n        \"${_options}\"\n        \"${_oneValueArgs}\"\n        \"${_multiValueArgs}\"\n        \"${ARGN}\")\n\n    unset(_options)\n    unset(_oneValueArgs)\n    unset(_multiValueArgs)\n\n    if(${${_prefix}_REQUIRED})\n        find_package(\n            ${${_prefix}_PACKAGE_ORIG}\n            COMPONENTS ${${_prefix}_COMPONENTS}\n            REQUIRED)\n    else()\n        find_package(\n            ${${_prefix}_PACKAGE_ORIG}\n            COMPONENTS ${${_prefix}_COMPONENTS}\n            QUIET)\n    endif()\n\n    # Example:\n    #  ${${_prefix}_PACKAGE_ORIG} = ign-gazebo3\n    if(${${_prefix}_PACKAGE_ORIG}_FOUND)\n\n        message(DEBUG \"Processing package: ${${_prefix}_PACKAGE_ORIG}\")\n\n        # Check length of lists\n        list(LENGTH ${_prefix}_TARGETS_ORIG _num_targets_orig)\n        list(LENGTH ${_prefix}_TARGETS_DEST _num_targets_dest)\n        math(EXPR _comparison \"${_num_targets_orig} - ${_num_targets_dest}\"\n             OUTPUT_FORMAT DECIMAL)\n\n         if(${_num_targets_orig} STREQUAL 0)\n             message(FATAL_ERROR \"No targets passed\")\n         endif()\n\n        if(NOT ${_comparison} STREQUAL 0)\n            message(FATAL_ERROR \"Number or TARGETS_ elements do not match\")\n        endif()\n\n        # Example:\n        # ${_package_name} = ignition-gazebo3\n        set(_package_name ${${_prefix}_PACKAGE_ORIG})\n\n        # Example:\n        # ${_variable_name} = ignition-gazebo\n        set(_variable_name ${${_prefix}_PACKAGE_DEST})\n\n        message(DEBUG \"  Setting: ${_variable_name}=${_package_name}\")\n        set(${_variable_name} ${_package_name})\n\n        # TODO Use ZIP_LISTS with CMake > 3.17\n        math(EXPR _num_targets \"${_num_targets_orig} - 1\")\n        foreach(idx RANGE ${_num_targets})\n\n            list(GET ${_prefix}_TARGETS_ORIG ${idx} _target_orig)\n            list(GET ${_prefix}_TARGETS_DEST ${idx} _target_dest)\n\n            # Example:\n            # ${_target_name} = ignition-gazebo3::core\n            set(_target_name ${${_prefix}_NAMESPACE_ORIG}::${_target_orig})\n\n            # Example:\n            # ${_target_name} = ignition-gazebo.core\n            set(_variable_name ${${_prefix}_NAMESPACE_DEST}.${_target_dest})\n\n            if(NOT TARGET ${_target_name})\n                message(FATAL_ERROR \"Could not find target ${_target_name}\")\n            endif()\n\n            message(DEBUG \"  Setting: ${_variable_name}=${_target_name}\")\n            set(${_variable_name} ${_target_name})\n\n        endforeach()\n\n    endif()\n\n    unset(_prefix)\n    unset(_num_targets_orig)\n    unset(_num_targets_dest)\n    unset(_comparison)\n    unset(_package_name)\n    unset(_num_targets)\n    unset(_target_orig)\n    unset(_target_dest)\n    unset(_target_name)\n    unset(_variable_name)\n\nendmacro()\n"
  },
  {
    "path": "scenario/cmake/FindIgnitionDistribution.cmake",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# In this initial implementation, we support only specifying\n# the Ignition Gazebo version to determine the Ignition distribution.\n# In the future we could pull and parse the tags.yaml file.\nset(IGNITION-GAZEBO_CITADEL_VER 3)\nset(IGNITION-GAZEBO_DOME_VER 4)\nset(IGNITION-GAZEBO_EDIFICE_VER 5)\nset(IGNITION-GAZEBO_FORTRESS_VER 6)\n\nmacro(find_ignition_distribution)\n\n    set(_prefix \"fid\")\n    string(TOUPPER ${_prefix} _prefix)\n\n    set(_oneValueArgs\n        CODENAME\n        REQUIRED)\n\n    set(_multiValueArgs\n        PACKAGES)\n\n    # For each {one,multi}value variable FOO, this command creates\n    # the variable ${_prefix}_FOO with the passed arg(s)\n    cmake_parse_arguments(${_prefix}\n        \"${_options}\"\n        \"${_oneValueArgs}\"\n        \"${_multiValueArgs}\"\n        \"${ARGN}\")\n\n    unset(_options)\n    unset(_oneValueArgs)\n    unset(_multiValueArgs)\n\n    # Example:\n    # ${Citadel_FOUND}=TRUE\n    set(${${_prefix}_CODENAME}_FOUND TRUE)\n    set(IGNITION_FOUND FALSE)\n\n    set(_pkgs_not_found)\n\n    # Example:\n    # ${PKG}=ignition-gazebo\n    foreach(PKG IN LISTS ${_prefix}_PACKAGES)\n\n        # Example:\n        # ${_codename_upper}=CITADEL\n        string(TOUPPER ${${_prefix}_CODENAME} _codename_upper)\n\n        # Example:\n        # ${_pkg_upper}=IGNITION-GAZEBO\n        string(TOUPPER ${PKG} _pkg_upper)\n\n        # Example:\n        # ${_rel_variable_name}=IGNITION-GAZEBO_CITADEL_VER\n        set(_rel_variable_name ${_pkg_upper}_${_codename_upper}_VER)\n\n        if(NOT ${_rel_variable_name})\n            message(FATAL_ERROR \"Failed to find variable ${_rel_variable_name}\")\n        endif()\n\n        # Example:\n        # ${_pkg_name}=ignition-gazebo3\n        set(_pkg_name ${PKG}${${_rel_variable_name}})\n\n        # Find the package\n        if(${${_prefix}_REQUIRED})\n            find_package(${_pkg_name} REQUIRED)\n        else()\n            find_package(${_pkg_name} QUIET)\n        endif()\n\n        if(NOT ${_pkg_name}_FOUND)\n            # Example:\n            # ${Citadel_FOUND}=FALSE\n            set(${${_prefix}_CODENAME}_FOUND FALSE)\n            list(APPEND _pkgs_not_found ${_pkg_name})\n        endif()\n\n    endforeach()\n\n    # Print missing packages\n    if(NOT ${${_prefix}_CODENAME}_FOUND)\n        message(DEBUG \"Missing packages of Ignition ${${_prefix}_CODENAME}:\")\n        foreach(PKG IN LISTS _pkgs_not_found)\n            message(DEBUG \"  ${PKG}\")\n        endforeach()\n    endif()\n\n    if(${${_prefix}_CODENAME}_FOUND)\n        set(IGNITION_FOUND TRUE)\n    endif()\n\n    unset(_prefix)\n    unset(_codename_upper)\n    unset(_pkg_upper)\n    unset(_rel_variable_name)\n    unset(_pkg_name)\n    unset(_pkgs_not_found)\n\nendmacro()\n"
  },
  {
    "path": "scenario/cmake/FindPackageHandleStandardArgs.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindPackageHandleStandardArgs\n-----------------------------\n\nThis module provides functions intended to be used in :ref:`Find Modules`\nimplementing :command:`find_package(<PackageName>)` calls.\n\n.. command:: find_package_handle_standard_args\n\n  This command handles the ``REQUIRED``, ``QUIET`` and version-related\n  arguments of :command:`find_package`.  It also sets the\n  ``<PackageName>_FOUND`` variable.  The package is considered found if all\n  variables listed contain valid results, e.g. valid filepaths.\n\n  There are two signatures:\n\n  .. code-block:: cmake\n\n    find_package_handle_standard_args(<PackageName>\n      (DEFAULT_MSG|<custom-failure-message>)\n      <required-var>...\n      )\n\n    find_package_handle_standard_args(<PackageName>\n      [FOUND_VAR <result-var>]\n      [REQUIRED_VARS <required-var>...]\n      [VERSION_VAR <version-var>]\n      [HANDLE_VERSION_RANGE]\n      [HANDLE_COMPONENTS]\n      [CONFIG_MODE]\n      [NAME_MISMATCHED]\n      [REASON_FAILURE_MESSAGE <reason-failure-message>]\n      [FAIL_MESSAGE <custom-failure-message>]\n      )\n\n  The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all\n  the variables ``<required-var>...`` are valid and any optional\n  constraints are satisfied, and ``FALSE`` otherwise.  A success or\n  failure message may be displayed based on the results and on\n  whether the ``REQUIRED`` and/or ``QUIET`` option was given to\n  the :command:`find_package` call.\n\n  The options are:\n\n  ``(DEFAULT_MSG|<custom-failure-message>)``\n    In the simple signature this specifies the failure message.\n    Use ``DEFAULT_MSG`` to ask for a default message to be computed\n    (recommended).  Not valid in the full signature.\n\n  ``FOUND_VAR <result-var>``\n    .. deprecated:: 3.3\n\n    Specifies either ``<PackageName>_FOUND`` or\n    ``<PACKAGENAME>_FOUND`` as the result variable.  This exists only\n    for compatibility with older versions of CMake and is now ignored.\n    Result variables of both names are always set for compatibility.\n\n  ``REQUIRED_VARS <required-var>...``\n    Specify the variables which are required for this package.\n    These may be named in the generated failure message asking the\n    user to set the missing variable values.  Therefore these should\n    typically be cache entries such as ``FOO_LIBRARY`` and not output\n    variables like ``FOO_LIBRARIES``.\n\n    .. versionchanged:: 3.18\n      If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.\n\n  ``VERSION_VAR <version-var>``\n    Specify the name of a variable that holds the version of the package\n    that has been found.  This version will be checked against the\n    (potentially) specified required version given to the\n    :command:`find_package` call, including its ``EXACT`` option.\n    The default messages include information about the required\n    version and the version which has been actually found, both\n    if the version is ok or not.\n\n  ``HANDLE_VERSION_RANGE``\n    .. versionadded:: 3.19\n\n    Enable handling of a version range, if one is specified. Without this\n    option, a developer warning will be displayed if a version range is\n    specified.\n\n  ``HANDLE_COMPONENTS``\n    Enable handling of package components.  In this case, the command\n    will report which components have been found and which are missing,\n    and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``\n    if any of the required components (i.e. not the ones listed after\n    the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are\n    missing.\n\n  ``CONFIG_MODE``\n    Specify that the calling find module is a wrapper around a\n    call to ``find_package(<PackageName> NO_MODULE)``.  This implies\n    a ``VERSION_VAR`` value of ``<PackageName>_VERSION``.  The command\n    will automatically check whether the package configuration file\n    was found.\n\n  ``REASON_FAILURE_MESSAGE <reason-failure-message>``\n    .. versionadded:: 3.16\n\n    Specify a custom message of the reason for the failure which will be\n    appended to the default generated message.\n\n  ``FAIL_MESSAGE <custom-failure-message>``\n    Specify a custom failure message instead of using the default\n    generated message.  Not recommended.\n\n  ``NAME_MISMATCHED``\n    .. versionadded:: 3.17\n\n    Indicate that the ``<PackageName>`` does not match\n    ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a\n    warning, but it may be intentional for usage of the command for components\n    of a larger package.\n\nExample for the simple signature:\n\n.. code-block:: cmake\n\n  find_package_handle_standard_args(LibXml2 DEFAULT_MSG\n    LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)\n\nThe ``LibXml2`` package is considered to be found if both\n``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.\nThen also ``LibXml2_FOUND`` is set to ``TRUE``.  If it is not found\nand ``REQUIRED`` was used, it fails with a\n:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was\nused or not.  If it is found, success will be reported, including\nthe content of the first ``<required-var>``.  On repeated CMake runs,\nthe same message will not be printed again.\n\n.. note::\n\n  If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the\n  calling module, a warning that there is a mismatch is given. The\n  ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using\n  the old signature and the ``NAME_MISMATCHED`` argument using the new\n  signature. To avoid forcing the caller to require newer versions of CMake for\n  usage, the variable's value will be used if defined when the\n  ``NAME_MISMATCHED`` argument is not passed for the new signature (but using\n  both is an error)..\n\nExample for the full signature:\n\n.. code-block:: cmake\n\n  find_package_handle_standard_args(LibArchive\n    REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR\n    VERSION_VAR LibArchive_VERSION)\n\nIn this case, the ``LibArchive`` package is considered to be found if\nboth ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.\nAlso the version of ``LibArchive`` will be checked by using the version\ncontained in ``LibArchive_VERSION``.  Since no ``FAIL_MESSAGE`` is given,\nthe default messages will be printed.\n\nAnother example for the full signature:\n\n.. code-block:: cmake\n\n  find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)\n  find_package_handle_standard_args(Automoc4  CONFIG_MODE)\n\nIn this case, a ``FindAutmoc4.cmake`` module wraps a call to\n``find_package(Automoc4 NO_MODULE)`` and adds an additional search\ndirectory for ``automoc4``.  Then the call to\n``find_package_handle_standard_args`` produces a proper success/failure\nmessage.\n\n.. command:: find_package_check_version\n\n  .. versionadded:: 3.19\n\n  Helper function which can be used to check if a ``<version>`` is valid\n  against version-related arguments of :command:`find_package`.\n\n  .. code-block:: cmake\n\n    find_package_check_version(<version> <result-var>\n      [HANDLE_VERSION_RANGE]\n      [RESULT_MESSAGE_VARIABLE <message-var>]\n      )\n\n  The ``<result-var>`` will hold a boolean value giving the result of the check.\n\n  The options are:\n\n  ``HANDLE_VERSION_RANGE``\n    Enable handling of a version range, if one is specified. Without this\n    option, a developer warning will be displayed if a version range is\n    specified.\n\n  ``RESULT_MESSAGE_VARIABLE <message-var>``\n    Specify a variable to get back a message describing the result of the check.\n\nExample for the usage:\n\n.. code-block:: cmake\n\n  find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE\n    RESULT_MESSAGE_VARIABLE reason)\n  if (result)\n    message (STATUS \"${reason}\")\n  else()\n    message (FATAL_ERROR \"${reason}\")\n  endif()\n#]=======================================================================]\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)\n\n\ncmake_policy(PUSH)\n# numbers and boolean constants\ncmake_policy (SET CMP0012 NEW)\n# IN_LIST operator\ncmake_policy (SET CMP0057 NEW)\n\n\n# internal helper macro\nmacro(_FPHSA_FAILURE_MESSAGE _msg)\n  set (__msg \"${_msg}\")\n  if (FPHSA_REASON_FAILURE_MESSAGE)\n    string(APPEND __msg \"\\n    Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\\n\")\n  endif()\n  if (${_NAME}_FIND_REQUIRED)\n    message(FATAL_ERROR \"${__msg}\")\n  else ()\n    if (NOT ${_NAME}_FIND_QUIETLY)\n      message(STATUS \"${__msg}\")\n    endif ()\n  endif ()\nendmacro()\n\n\n# internal helper macro to generate the failure message when used in CONFIG_MODE:\nmacro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)\n  # <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:\n  if(${_NAME}_CONFIG)\n    _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})\")\n  else()\n    # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.\n    # List them all in the error message:\n    if(${_NAME}_CONSIDERED_CONFIGS)\n      set(configsText \"\")\n      list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)\n      math(EXPR configsCount \"${configsCount} - 1\")\n      foreach(currentConfigIndex RANGE ${configsCount})\n        list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)\n        list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)\n        string(APPEND configsText \"\\n    ${filename} (version ${version})\")\n      endforeach()\n      if (${_NAME}_NOT_FOUND_MESSAGE)\n        if (FPHSA_REASON_FAILURE_MESSAGE)\n          string(PREPEND FPHSA_REASON_FAILURE_MESSAGE \"${${_NAME}_NOT_FOUND_MESSAGE}\\n    \")\n        else()\n          set(FPHSA_REASON_FAILURE_MESSAGE \"${${_NAME}_NOT_FOUND_MESSAGE}\")\n        endif()\n      else()\n        string(APPEND configsText \"\\n\")\n      endif()\n      _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}\")\n\n    else()\n      # Simple case: No Config-file was found at all:\n      _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}\")\n    endif()\n  endif()\nendmacro()\n\n\nfunction(FIND_PACKAGE_CHECK_VERSION version result)\n  cmake_parse_arguments (PARSE_ARGV 2 FPCV \"HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE\" \"RESULT_MESSAGE_VARIABLE\" \"\")\n\n  if (FPCV_UNPARSED_ARGUMENTS)\n    message (FATAL_ERROR \"find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments\")\n  endif()\n  if (\"RESULT_MESSAGE_VARIABLE\" IN_LIST FPCV_KEYWORDS_MISSING_VALUES)\n    message (FATAL_ERROR \"find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument\")\n  endif()\n\n  set (${result} FALSE PARENT_SCOPE)\n  if (FPCV_RESULT_MESSAGE_VARIABLE)\n    unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE)\n  endif()\n\n  if (_CMAKE_FPHSA_PACKAGE_NAME)\n    set (package \"${_CMAKE_FPHSA_PACKAGE_NAME}\")\n  elseif (CMAKE_FIND_PACKAGE_NAME)\n    set (package \"${CMAKE_FIND_PACKAGE_NAME}\")\n  else()\n    message (FATAL_ERROR \"find_package_check_version(): Cannot be used outside a 'Find Module'\")\n  endif()\n\n  if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE\n      AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE)\n    message(AUTHOR_WARNING\n      \"`find_package()` specify a version range but the option \"\n      \"HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. \"\n      \"Only the lower endpoint of the range will be used.\")\n  endif()\n\n\n  set (version_ok FALSE)\n  unset (version_msg)\n\n  if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)\n    if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL \"INCLUDE\"\n          AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)\n        AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL \"INCLUDE\"\n            AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX)\n          OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL \"EXCLUDE\"\n            AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))\n      set (version_ok TRUE)\n      set(version_msg \"(found suitable version \\\"${version}\\\", required range is \\\"${${package}_FIND_VERSION_RANGE}\\\")\")\n    else()\n      set(version_msg \"Found unsuitable version \\\"${version}\\\", required range is \\\"${${package}_FIND_VERSION_RANGE}\\\"\")\n    endif()\n  elseif (DEFINED ${package}_FIND_VERSION)\n    if(${package}_FIND_VERSION_EXACT)       # exact version required\n      # count the dots in the version string\n      string(REGEX REPLACE \"[^.]\" \"\" version_dots \"${version}\")\n      # add one dot because there is one dot more than there are components\n      string(LENGTH \"${version_dots}.\" version_dots)\n      if (version_dots GREATER ${package}_FIND_VERSION_COUNT)\n        # Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT\n        # is at most 4 here. Therefore a simple lookup table is used.\n        if (${package}_FIND_VERSION_COUNT EQUAL 1)\n          set(version_regex \"[^.]*\")\n        elseif (${package}_FIND_VERSION_COUNT EQUAL 2)\n          set(version_regex \"[^.]*\\\\.[^.]*\")\n        elseif (${package}_FIND_VERSION_COUNT EQUAL 3)\n          set(version_regex \"[^.]*\\\\.[^.]*\\\\.[^.]*\")\n        else()\n          set(version_regex \"[^.]*\\\\.[^.]*\\\\.[^.]*\\\\.[^.]*\")\n        endif()\n        string(REGEX REPLACE \"^(${version_regex})\\\\..*\" \"\\\\1\" version_head \"${version}\")\n        if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head)\n          set(version_msg \"Found unsuitable version \\\"${version}\\\", but required is exact version \\\"${${package}_FIND_VERSION}\\\"\")\n        else ()\n          set(version_ok TRUE)\n          set(version_msg \"(found suitable exact version \\\"${_FOUND_VERSION}\\\")\")\n        endif ()\n      else ()\n        if (NOT ${package}_FIND_VERSION VERSION_EQUAL version)\n          set(version_msg \"Found unsuitable version \\\"${version}\\\", but required is exact version \\\"${${package}_FIND_VERSION}\\\"\")\n        else ()\n          set(version_ok TRUE)\n          set(version_msg \"(found suitable exact version \\\"${version}\\\")\")\n        endif ()\n      endif ()\n    else()     # minimum version\n      if (${package}_FIND_VERSION VERSION_GREATER version)\n        set(version_msg \"Found unsuitable version \\\"${version}\\\", but required is at least \\\"${${package}_FIND_VERSION}\\\"\")\n      else()\n        set(version_ok TRUE)\n        set(version_msg \"(found suitable version \\\"${version}\\\", minimum required is \\\"${${package}_FIND_VERSION}\\\")\")\n      endif()\n    endif()\n  else ()\n    set(version_ok TRUE)\n    set(version_msg \"(found version \\\"${version}\\\")\")\n  endif()\n\n  set (${result} ${version_ok} PARENT_SCOPE)\n  if (FPCV_RESULT_MESSAGE_VARIABLE)\n    set (${FPCV_RESULT_MESSAGE_VARIABLE} \"${version_msg}\" PARENT_SCOPE)\n  endif()\nendfunction()\n\n\nfunction(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)\n\n  # Set up the arguments for `cmake_parse_arguments`.\n  set(options  CONFIG_MODE  HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE)\n  set(oneValueArgs  FAIL_MESSAGE  REASON_FAILURE_MESSAGE VERSION_VAR  FOUND_VAR)\n  set(multiValueArgs REQUIRED_VARS)\n\n  # Check whether we are in 'simple' or 'extended' mode:\n  set(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )\n  list(FIND _KEYWORDS_FOR_EXTENDED_MODE \"${_FIRST_ARG}\" INDEX)\n\n  unset(FPHSA_NAME_MISMATCHED_override)\n  if (DEFINED FPHSA_NAME_MISMATCHED)\n    # If the variable NAME_MISMATCHED variable is set, error if it is passed as\n    # an argument. The former is for old signatures, the latter is for new\n    # signatures.\n    list(FIND ARGN \"NAME_MISMATCHED\" name_mismatched_idx)\n    if (NOT name_mismatched_idx EQUAL \"-1\")\n      message(FATAL_ERROR\n        \"The `NAME_MISMATCHED` argument may only be specified by the argument or \"\n        \"the variable, not both.\")\n    endif ()\n\n    # But use the variable if it is not an argument to avoid forcing minimum\n    # CMake version bumps for calling modules.\n    set(FPHSA_NAME_MISMATCHED_override \"${FPHSA_NAME_MISMATCHED}\")\n  endif ()\n\n  if(${INDEX} EQUAL -1)\n    set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})\n    set(FPHSA_REQUIRED_VARS ${ARGN})\n    set(FPHSA_VERSION_VAR)\n  else()\n    cmake_parse_arguments(FPHSA \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\"  ${_FIRST_ARG} ${ARGN})\n\n    if(FPHSA_UNPARSED_ARGUMENTS)\n      message(FATAL_ERROR \"Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \\\"${FPHSA_UNPARSED_ARGUMENTS}\\\"\")\n    endif()\n\n    if(NOT FPHSA_FAIL_MESSAGE)\n      set(FPHSA_FAIL_MESSAGE  \"DEFAULT_MSG\")\n    endif()\n\n    # In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()\n    # when it successfully found the config-file, including version checking:\n    if(FPHSA_CONFIG_MODE)\n      list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)\n      list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)\n      set(FPHSA_VERSION_VAR ${_NAME}_VERSION)\n    endif()\n\n    if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS)\n      message(FATAL_ERROR \"No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()\")\n    endif()\n  endif()\n\n  if (DEFINED FPHSA_NAME_MISMATCHED_override)\n    set(FPHSA_NAME_MISMATCHED \"${FPHSA_NAME_MISMATCHED_override}\")\n  endif ()\n\n  if (DEFINED CMAKE_FIND_PACKAGE_NAME\n      AND NOT FPHSA_NAME_MISMATCHED\n      AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)\n    message(AUTHOR_WARNING\n      \"The package name passed to `find_package_handle_standard_args` \"\n      \"(${_NAME}) does not match the name of the calling package \"\n      \"(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling \"\n      \"code that expects `find_package` result variables (e.g., `_FOUND`) \"\n      \"to follow a certain pattern.\")\n  endif ()\n\n  if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE)\n    message(AUTHOR_WARNING\n      \"`find_package()` specify a version range but the module ${_NAME} does \"\n      \"not support this capability. Only the lower endpoint of the range \"\n      \"will be used.\")\n  endif()\n\n  # to propagate package name to FIND_PACKAGE_CHECK_VERSION\n  set(_CMAKE_FPHSA_PACKAGE_NAME \"${_NAME}\")\n\n  # now that we collected all arguments, process them\n\n  if(\"x${FPHSA_FAIL_MESSAGE}\" STREQUAL \"xDEFAULT_MSG\")\n    set(FPHSA_FAIL_MESSAGE \"Could NOT find ${_NAME}\")\n  endif()\n\n  if (FPHSA_REQUIRED_VARS)\n    list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)\n  endif()\n\n  string(TOUPPER ${_NAME} _NAME_UPPER)\n  string(TOLOWER ${_NAME} _NAME_LOWER)\n\n  if(FPHSA_FOUND_VAR)\n    set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)\n    set(_FOUND_VAR_MIXED ${_NAME}_FOUND)\n    if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED  OR  FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)\n      set(_FOUND_VAR ${FPHSA_FOUND_VAR})\n    else()\n      message(FATAL_ERROR \"The argument for FOUND_VAR is \\\"${FPHSA_FOUND_VAR}\\\", but only \\\"${_FOUND_VAR_MIXED}\\\" and \\\"${_FOUND_VAR_UPPER}\\\" are valid names.\")\n    endif()\n  else()\n    set(_FOUND_VAR ${_NAME_UPPER}_FOUND)\n  endif()\n\n  # collect all variables which were not found, so they can be printed, so the\n  # user knows better what went wrong (#6375)\n  set(MISSING_VARS \"\")\n  set(DETAILS \"\")\n  # check if all passed variables are valid\n  set(FPHSA_FOUND_${_NAME} TRUE)\n  foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})\n    if(NOT ${_CURRENT_VAR})\n      set(FPHSA_FOUND_${_NAME} FALSE)\n      string(APPEND MISSING_VARS \" ${_CURRENT_VAR}\")\n    else()\n      string(APPEND DETAILS \"[${${_CURRENT_VAR}}]\")\n    endif()\n  endforeach()\n  if(FPHSA_FOUND_${_NAME})\n    set(${_NAME}_FOUND TRUE)\n    set(${_NAME_UPPER}_FOUND TRUE)\n  else()\n    set(${_NAME}_FOUND FALSE)\n    set(${_NAME_UPPER}_FOUND FALSE)\n  endif()\n\n  # component handling\n  unset(FOUND_COMPONENTS_MSG)\n  unset(MISSING_COMPONENTS_MSG)\n\n  if(FPHSA_HANDLE_COMPONENTS)\n    foreach(comp ${${_NAME}_FIND_COMPONENTS})\n      if(${_NAME}_${comp}_FOUND)\n\n        if(NOT DEFINED FOUND_COMPONENTS_MSG)\n          set(FOUND_COMPONENTS_MSG \"found components:\")\n        endif()\n        string(APPEND FOUND_COMPONENTS_MSG \" ${comp}\")\n\n      else()\n\n        if(NOT DEFINED MISSING_COMPONENTS_MSG)\n          set(MISSING_COMPONENTS_MSG \"missing components:\")\n        endif()\n        string(APPEND MISSING_COMPONENTS_MSG \" ${comp}\")\n\n        if(${_NAME}_FIND_REQUIRED_${comp})\n          set(${_NAME}_FOUND FALSE)\n          string(APPEND MISSING_VARS \" ${comp}\")\n        endif()\n\n      endif()\n    endforeach()\n    set(COMPONENT_MSG \"${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}\")\n    string(APPEND DETAILS \"[c${COMPONENT_MSG}]\")\n  endif()\n\n  # version handling:\n  set(VERSION_MSG \"\")\n  set(VERSION_OK TRUE)\n\n  # check with DEFINED here as the requested or found version may be \"0\"\n  if (DEFINED ${_NAME}_FIND_VERSION)\n    if(DEFINED ${FPHSA_VERSION_VAR})\n      set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})\n      if (FPHSA_HANDLE_VERSION_RANGE)\n        set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE)\n      else()\n        set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE)\n      endif()\n      find_package_check_version (\"${_FOUND_VERSION}\" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG\n        ${FPCV_HANDLE_VERSION_RANGE})\n    else()\n      # if the package was not found, but a version was given, add that to the output:\n      if(${_NAME}_FIND_VERSION_EXACT)\n        set(VERSION_MSG \"(Required is exact version \\\"${${_NAME}_FIND_VERSION}\\\")\")\n      elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE)\n        set(VERSION_MSG \"(Required is version range \\\"${${_NAME}_FIND_VERSION_RANGE}\\\")\")\n      else()\n        set(VERSION_MSG \"(Required is at least version \\\"${${_NAME}_FIND_VERSION}\\\")\")\n      endif()\n    endif()\n  else ()\n    # Check with DEFINED as the found version may be 0.\n    if(DEFINED ${FPHSA_VERSION_VAR})\n      set(VERSION_MSG \"(found version \\\"${${FPHSA_VERSION_VAR}}\\\")\")\n    endif()\n  endif ()\n\n  if(VERSION_OK)\n    string(APPEND DETAILS \"[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]\")\n  else()\n    set(${_NAME}_FOUND FALSE)\n  endif()\n\n\n  # print the result:\n  if (${_NAME}_FOUND)\n    FIND_PACKAGE_MESSAGE(${_NAME} \"Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}\" \"${DETAILS}\")\n  else ()\n\n    if(FPHSA_CONFIG_MODE)\n      _FPHSA_HANDLE_FAILURE_CONFIG_MODE()\n    else()\n      if(NOT VERSION_OK)\n        set(RESULT_MSG)\n        if (_FIRST_REQUIRED_VAR)\n          string (APPEND RESULT_MSG \"found ${${_FIRST_REQUIRED_VAR}}\")\n        endif()\n        if (COMPONENT_MSG)\n          if (RESULT_MSG)\n            string (APPEND RESULT_MSG \", \")\n          endif()\n          string (APPEND RESULT_MSG \"${FOUND_COMPONENTS_MSG}\")\n        endif()\n        _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})\")\n      else()\n        _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}\")\n      endif()\n    endif()\n\n  endif ()\n\n  set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)\n  set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)\nendfunction()\n\n\ncmake_policy(POP)\n"
  },
  {
    "path": "scenario/cmake/FindPackageMessage.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindPackageMessage\n------------------\n\n.. code-block:: cmake\n\n  find_package_message(<name> \"message for user\" \"find result details\")\n\nThis function is intended to be used in FindXXX.cmake modules files.\nIt will print a message once for each unique find result.  This is\nuseful for telling the user where a package was found.  The first\nargument specifies the name (XXX) of the package.  The second argument\nspecifies the message to display.  The third argument lists details\nabout the find result so that if they change the message will be\ndisplayed again.  The macro also obeys the QUIET argument to the\nfind_package command.\n\nExample:\n\n.. code-block:: cmake\n\n  if(X11_FOUND)\n    find_package_message(X11 \"Found X11: ${X11_X11_LIB}\"\n      \"[${X11_X11_LIB}][${X11_INCLUDE_DIR}]\")\n  else()\n   ...\n  endif()\n#]=======================================================================]\n\nfunction(find_package_message pkg msg details)\n  # Avoid printing a message repeatedly for the same find result.\n  if(NOT ${pkg}_FIND_QUIETLY)\n    string(REPLACE \"\\n\" \"\" details \"${details}\")\n    set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})\n    if(NOT \"${details}\" STREQUAL \"${${DETAILS_VAR}}\")\n      # The message has not yet been printed.\n      message(STATUS \"${msg}\")\n\n      # Save the find details in the cache to avoid printing the same\n      # message again.\n      set(\"${DETAILS_VAR}\" \"${details}\"\n        CACHE INTERNAL \"Details about finding ${pkg}\")\n    endif()\n  endif()\nendfunction()\n"
  },
  {
    "path": "scenario/cmake/FindPython/Support.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#\n# This file is a \"template\" file used by various FindPython modules.\n#\n\n#\n# Initial configuration\n#\n\ncmake_policy(PUSH)\n# numbers and boolean constants\ncmake_policy (SET CMP0012 NEW)\n# IN_LIST operator\ncmake_policy (SET CMP0057 NEW)\n\nif (NOT DEFINED _PYTHON_PREFIX)\n  message (FATAL_ERROR \"FindPython: INTERNAL ERROR\")\nendif()\nif (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n  message (FATAL_ERROR \"FindPython: INTERNAL ERROR\")\nendif()\nif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL \"3\")\n  set(_${_PYTHON_PREFIX}_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)\nelseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL \"2\")\n  set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)\nelse()\n  message (FATAL_ERROR \"FindPython: INTERNAL ERROR\")\nendif()\n\nget_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE)\n\ninclude (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)\n\n#\n# helper commands\n#\nmacro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG)\n  if (${_PYTHON_PREFIX}_FIND_REQUIRED)\n    message (FATAL_ERROR \"${_PYTHON_MSG}\")\n  else()\n    if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY)\n      message(STATUS \"${_PYTHON_MSG}\")\n    endif ()\n  endif()\n\n  set (${_PYTHON_PREFIX}_FOUND FALSE)\n  string (TOUPPER \"${_PYTHON_PREFIX}\" _${_PYTHON_PREFIX}_UPPER_PREFIX)\n  set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE)\nendmacro()\n\n\nfunction (_PYTHON_MARK_AS_INTERNAL)\n  foreach (var IN LISTS ARGV)\n    if (DEFINED CACHE{${var}})\n      set_property (CACHE ${var} PROPERTY TYPE INTERNAL)\n    endif()\n  endforeach()\nendfunction()\n\n\nmacro (_PYTHON_SELECT_LIBRARY_CONFIGURATIONS _PYTHON_BASENAME)\n  if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_RELEASE)\n    set(${_PYTHON_BASENAME}_LIBRARY_RELEASE \"${_PYTHON_BASENAME}_LIBRARY_RELEASE-NOTFOUND\")\n  endif()\n  if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_DEBUG)\n    set(${_PYTHON_BASENAME}_LIBRARY_DEBUG \"${_PYTHON_BASENAME}_LIBRARY_DEBUG-NOTFOUND\")\n  endif()\n\n  get_property(_PYTHON_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\n  if (${_PYTHON_BASENAME}_LIBRARY_DEBUG AND ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND\n      NOT ${_PYTHON_BASENAME}_LIBRARY_DEBUG STREQUAL ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND\n      (_PYTHON_isMultiConfig OR CMAKE_BUILD_TYPE))\n    # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for\n    # single-config generators, set optimized and debug libraries\n    set (${_PYTHON_BASENAME}_LIBRARIES \"\")\n    foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_RELEASE)\n      list( APPEND ${_PYTHON_BASENAME}_LIBRARIES optimized \"${_PYTHON_libname}\")\n    endforeach()\n    foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_DEBUG)\n      list( APPEND ${_PYTHON_BASENAME}_LIBRARIES debug \"${_PYTHON_libname}\")\n    endforeach()\n  elseif (${_PYTHON_BASENAME}_LIBRARY_RELEASE)\n    set (${_PYTHON_BASENAME}_LIBRARIES \"${${_PYTHON_BASENAME}_LIBRARY_RELEASE}\")\n  elseif (${_PYTHON_BASENAME}_LIBRARY_DEBUG)\n    set (${_PYTHON_BASENAME}_LIBRARIES \"${${_PYTHON_BASENAME}_LIBRARY_DEBUG}\")\n  else()\n    set (${_PYTHON_BASENAME}_LIBRARIES \"${_PYTHON_BASENAME}_LIBRARY-NOTFOUND\")\n  endif()\nendmacro()\n\n\nmacro (_PYTHON_FIND_FRAMEWORKS)\n  if (CMAKE_HOST_APPLE OR APPLE)\n    file(TO_CMAKE_PATH \"$ENV{CMAKE_FRAMEWORK_PATH}\" _pff_CMAKE_FRAMEWORK_PATH)\n    set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH}\n                         ${_pff_CMAKE_FRAMEWORK_PATH}\n                         ~/Library/Frameworks\n                         /usr/local/Frameworks\n                         ${CMAKE_SYSTEM_FRAMEWORK_PATH})\n    list (REMOVE_DUPLICATES _pff_frameworks)\n    foreach (_pff_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n      unset (_${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS)\n      if (_pff_implementation STREQUAL \"CPython\")\n        foreach (_pff_framework IN LISTS _pff_frameworks)\n          if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)\n            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)\n          endif()\n          if (EXISTS ${_pff_framework}/Python.framework)\n            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python.framework)\n          endif()\n        endforeach()\n      elseif (_pff_implementation STREQUAL \"IronPython\")\n        foreach (_pff_framework IN LISTS _pff_frameworks)\n          if (EXISTS ${_pff_framework}/IronPython.framework)\n            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/IronPython.framework)\n          endif()\n        endforeach()\n      endif()\n    endforeach()\n    unset (_pff_implementation)\n    unset (_pff_frameworks)\n    unset (_pff_framework)\n  endif()\nendmacro()\n\nfunction (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS)\n  cmake_parse_arguments (PARSE_ARGV 1 _PGF \"\" \"\" \"IMPLEMENTATIONS;VERSION\")\n\n  if (NOT _PGF_IMPLEMENTATIONS)\n    set (_PGF_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})\n  endif()\n\n  set (framework_paths)\n\n  foreach (implementation IN LISTS _PGF_IMPLEMENTATIONS)\n    if (implementation STREQUAL \"CPython\")\n      foreach (version IN LISTS _PGF_VERSION)\n        foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)\n          if (EXISTS \"${framework}/Versions/${version}\")\n            list (APPEND framework_paths \"${framework}/Versions/${version}\")\n          endif()\n        endforeach()\n      endforeach()\n    elseif (implementation STREQUAL \"IronPython\")\n      foreach (version IN LISTS _PGF_VERSION)\n        foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)\n          # pick-up all available versions\n          file (GLOB versions LIST_DIRECTORIES true RELATIVE \"${framework}/Versions/\"\n                              \"${framework}/Versions/${version}*\")\n          list (SORT versions ORDER DESCENDING)\n          list (TRANSFORM versions PREPEND \"${framework}/Versions/\")\n          list (APPEND framework_paths ${versions})\n        endforeach()\n      endforeach()\n    endif()\n  endforeach()\n\n  set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${framework_paths} PARENT_SCOPE)\nendfunction()\n\nfunction (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS)\n  cmake_parse_arguments (PARSE_ARGV 1 _PGR \"\" \"\" \"IMPLEMENTATIONS;VERSION\")\n\n  if (NOT _PGR_IMPLEMENTATIONS)\n    set (_PGR_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})\n  endif()\n\n  set (registries)\n\n  foreach (implementation IN LISTS _PGR_IMPLEMENTATIONS)\n    if (implementation STREQUAL \"CPython\")\n      foreach (version IN LISTS _PGR_VERSION)\n        string (REPLACE \".\" \"\" version_no_dots ${version})\n        list (APPEND registries\n                     [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\\\InstallPath]\n                     [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\\\InstallPath])\n        if (version VERSION_GREATER_EQUAL \"3.5\")\n          get_filename_component (arch \"[HKEY_CURRENT_USER\\\\Software\\\\Python\\\\PythonCore\\\\${version};SysArchitecture]\" NAME)\n          if (arch MATCHES \"(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit\")\n            list (APPEND registries\n                         [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}\\\\InstallPath])\n          endif()\n        else()\n          list (APPEND registries\n                       [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}\\\\InstallPath])\n        endif()\n        list (APPEND registries\n                     [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\ContinuumAnalytics\\\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\\\InstallPath]\n                     [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\ContinuumAnalytics\\\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\\\InstallPath]\n                     [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\\\InstallPath]\n                     [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\\\InstallPath]\n                     [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${version}\\\\InstallPath]\n                     [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\ContinuumAnalytics\\\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\\\InstallPath]\n                     [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\ContinuumAnalytics\\\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\\\InstallPath])\n      endforeach()\n    elseif (implementation STREQUAL \"IronPython\")\n      foreach (version  IN LISTS _PGR_VERSION)\n        list (APPEND registries [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\IronPython\\\\${version}\\\\InstallPath])\n      endforeach()\n    endif()\n  endforeach()\n\n  set (${_PYTHON_PGR_REGISTRY_PATHS} \"${registries}\" PARENT_SCOPE)\nendfunction()\n\n\nfunction (_PYTHON_GET_ABIFLAGS _PGABIFLAGS)\n  set (abiflags)\n  list (GET _${_PYTHON_PREFIX}_FIND_ABI 0 pydebug)\n  list (GET _${_PYTHON_PREFIX}_FIND_ABI 1 pymalloc)\n  list (GET _${_PYTHON_PREFIX}_FIND_ABI 2 unicode)\n\n  if (pymalloc STREQUAL \"ANY\" AND unicode STREQUAL \"ANY\")\n    set (abiflags \"mu\" \"m\" \"u\" \"\")\n  elseif (pymalloc STREQUAL \"ANY\" AND unicode STREQUAL \"ON\")\n    set (abiflags \"mu\" \"u\")\n  elseif (pymalloc STREQUAL \"ANY\" AND unicode STREQUAL \"OFF\")\n    set (abiflags \"m\" \"\")\n  elseif (pymalloc STREQUAL \"ON\" AND unicode STREQUAL \"ANY\")\n    set (abiflags \"mu\" \"m\")\n  elseif (pymalloc STREQUAL \"ON\" AND unicode STREQUAL \"ON\")\n    set (abiflags \"mu\")\n  elseif (pymalloc STREQUAL \"ON\" AND unicode STREQUAL \"OFF\")\n    set (abiflags \"m\")\n  elseif (pymalloc STREQUAL \"ON\" AND unicode STREQUAL \"ANY\")\n    set (abiflags \"u\" \"\")\n  elseif (pymalloc STREQUAL \"OFF\" AND unicode STREQUAL \"ON\")\n    set (abiflags \"u\")\n  endif()\n\n  if (pydebug STREQUAL \"ON\")\n    if (abiflags)\n      list (TRANSFORM abiflags PREPEND \"d\")\n    else()\n      set (abiflags \"d\")\n    endif()\n  elseif (pydebug STREQUAL \"ANY\")\n    if (abiflags)\n      set (flags \"${abiflags}\")\n      list (TRANSFORM flags PREPEND \"d\")\n      list (APPEND abiflags \"${flags}\")\n    else()\n      set (abiflags \"\" \"d\")\n    endif()\n  endif()\n\n  set (${_PGABIFLAGS} \"${abiflags}\" PARENT_SCOPE)\nendfunction()\n\nfunction (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES)\n  cmake_parse_arguments (PARSE_ARGV 1 _PGPS \"INTERPRETER;COMPILER;LIBRARY;INCLUDE\" \"\" \"IMPLEMENTATIONS;VERSION\")\n\n  if (NOT _PGPS_IMPLEMENTATIONS)\n    set (_PGPS_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})\n  endif()\n\n  if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)\n    set (abi \"${_${_PYTHON_PREFIX}_ABIFLAGS}\")\n  else()\n    set (abi \"mu\" \"m\" \"u\" \"\")\n  endif()\n\n  set (path_suffixes)\n\n  foreach (implementation IN LISTS _PGPS_IMPLEMENTATIONS)\n    if (implementation STREQUAL \"CPython\")\n      if (_PGPS_INTERPRETER)\n        list (APPEND path_suffixes bin Scripts)\n      else()\n        foreach (version IN LISTS _PGPS_VERSION)\n          if (_PGPS_LIBRARY)\n            if (CMAKE_LIBRARY_ARCHITECTURE)\n              list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE})\n            endif()\n            list (APPEND path_suffixes lib libs)\n\n            if (CMAKE_LIBRARY_ARCHITECTURE)\n              set (suffixes \"${abi}\")\n              if (suffixes)\n                list (TRANSFORM suffixes PREPEND \"lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}\")\n                list (TRANSFORM suffixes APPEND \"-${CMAKE_LIBRARY_ARCHITECTURE}\")\n              else()\n                set (suffixes \"lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}-${CMAKE_LIBRARY_ARCHITECTURE}\")\n              endif()\n              list (APPEND path_suffixes ${suffixes})\n            endif()\n            set (suffixes \"${abi}\")\n            if (suffixes)\n              list (TRANSFORM suffixes PREPEND \"lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}\")\n            else()\n              set (suffixes \"lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}\")\n            endif()\n            list (APPEND path_suffixes ${suffixes})\n          elseif (_PGPS_INCLUDE)\n            set (suffixes \"${abi}\")\n            if (suffixes)\n              list (TRANSFORM suffixes PREPEND \"include/python${_PGPS_VERSION}\")\n            else()\n              set (suffixes \"include/python${_PGPS_VERSION}\")\n            endif()\n            list (APPEND path_suffixes ${suffixes} include)\n          endif()\n        endforeach()\n      endif()\n    elseif (implementation STREQUAL \"IronPython\")\n      if (_PGPS_INTERPRETER OR _PGPS_COMPILER)\n        foreach (version IN LISTS _PGPS_VERSION)\n          list (APPEND path_suffixes \"share/ironpython${version}\")\n        endforeach()\n        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})\n      endif()\n    elseif (implementation STREQUAL \"PyPy\")\n      if (_PGPS_INTERPRETER)\n        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES})\n      elseif (_PGPS_LIBRARY)\n        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES})\n      elseif (_PGPS_INCLUDE)\n        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES})\n      endif()\n    endif()\n  endforeach()\n  list (REMOVE_DUPLICATES path_suffixes)\n\n  set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE)\nendfunction()\n\nfunction (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)\n  cmake_parse_arguments (PARSE_ARGV 1 _PGN \"POSIX;INTERPRETER;COMPILER;CONFIG;LIBRARY;WIN32;DEBUG\" \"\" \"IMPLEMENTATIONS;VERSION\")\n\n  if (NOT _PGN_IMPLEMENTATIONS)\n    set (_PGN_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})\n  endif()\n\n  set (names)\n\n  foreach (implementation IN LISTS _PGN_IMPLEMENTATIONS)\n    if (implementation STREQUAL \"CPython\")\n      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL \"FIRST\")\n        list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)\n      endif()\n      foreach (version IN LISTS _PGN_VERSION)\n        if (_PGN_WIN32)\n          string (REPLACE \".\" \"\" version_no_dots ${version})\n\n          set (name python${version_no_dots})\n          if (_PGN_DEBUG)\n            string (APPEND name \"_d\")\n          endif()\n\n          list (APPEND names \"${name}\")\n        endif()\n\n        if (_PGN_POSIX)\n          if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)\n            set (abi \"${_${_PYTHON_PREFIX}_ABIFLAGS}\")\n          else()\n            if (_PGN_INTERPRETER OR _PGN_CONFIG)\n              set (abi \"\")\n            else()\n              set (abi \"mu\" \"m\" \"u\" \"\")\n            endif()\n          endif()\n\n          if (abi)\n            if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)\n              set (abinames \"${abi}\")\n              list (TRANSFORM abinames PREPEND \"${CMAKE_LIBRARY_ARCHITECTURE}-python${version}\")\n              list (TRANSFORM abinames APPEND \"-config\")\n              list (APPEND names ${abinames})\n            endif()\n            set (abinames \"${abi}\")\n            list (TRANSFORM abinames PREPEND \"python${version}\")\n            if (_PGN_CONFIG)\n              list (TRANSFORM abinames APPEND \"-config\")\n            endif()\n            list (APPEND names ${abinames})\n          else()\n            unset (abinames)\n            if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)\n              set (abinames \"${CMAKE_LIBRARY_ARCHITECTURE}-python${version}\")\n            endif()\n            list (APPEND abinames \"python${version}\")\n            if (_PGN_CONFIG)\n              list (TRANSFORM abinames APPEND \"-config\")\n            endif()\n            list (APPEND names ${abinames})\n          endif()\n        endif()\n      endforeach()\n      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL \"LAST\")\n        list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)\n      endif()\n    elseif (implementation STREQUAL \"IronPython\")\n      if (_PGN_INTERPRETER)\n        if (NOT CMAKE_SYSTEM_NAME STREQUAL \"Linux\")\n          # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used\n          foreach (version IN LISTS _PGN_VERSION)\n            list (APPEND names \"ipy${version}\")\n          endforeach()\n        endif()\n        list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES})\n      elseif (_PGN_COMPILER)\n        list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES})\n      endif()\n    elseif (implementation STREQUAL \"PyPy\")\n      if (_PGN_INTERPRETER)\n        list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_NAMES})\n      elseif (_PGN_LIBRARY)\n        if (_PGN_WIN32)\n          foreach (version IN LISTS _PGN_VERSION)\n            string (REPLACE \".\" \"\" version_no_dots ${version})\n\n            set (name \"python${version_no_dots}\")\n            if (_PGN_DEBUG)\n              string (APPEND name \"_d\")\n            endif()\n            list (APPEND names \"${name}\")\n          endforeach()\n        endif()\n        list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_LIB_NAMES})\n      endif()\n    endif()\n  endforeach()\n\n  set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE)\nendfunction()\n\nfunction (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)\n  unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE)\n\n  if (NOT NAME MATCHES \"^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI)$\")\n    return()\n  endif()\n\n  if (_${_PYTHON_PREFIX}_CONFIG)\n    if (NAME STREQUAL \"SOABI\")\n      set (config_flag \"--extension-suffix\")\n    else()\n      set (config_flag \"--${NAME}\")\n    endif()\n    string (TOLOWER \"${config_flag}\" config_flag)\n    execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" ${config_flag}\n                     RESULT_VARIABLE _result\n                     OUTPUT_VARIABLE _values\n                     ERROR_QUIET\n                     OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (_result)\n      unset (_values)\n    else()\n      if (NAME STREQUAL \"INCLUDES\")\n        # do some clean-up\n        string (REGEX MATCHALL \"(-I|-iwithsysroot)[ ]*[^ ]+\" _values \"${_values}\")\n        string (REGEX REPLACE \"(-I|-iwithsysroot)[ ]*\" \"\" _values \"${_values}\")\n        list (REMOVE_DUPLICATES _values)\n      elseif (NAME STREQUAL \"SOABI\")\n        # clean-up: remove prefix character and suffix\n        if (_values MATCHES \"^(\\\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\\\.so|\\\\.pyd)$\")\n          set(_values \"\")\n        else()\n          string (REGEX REPLACE \"^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\\\.(so|pyd))$\" \"\\\\1\" _values \"${_values}\")\n        endif()\n      endif()\n    endif()\n  endif()\n\n  if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING)\n    if (NAME STREQUAL \"PREFIX\")\n      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c \"import sys\\ntry:\\n   from distutils import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\\nexcept Exception:\\n   import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))\"\n                       RESULT_VARIABLE _result\n                       OUTPUT_VARIABLE _values\n                       ERROR_QUIET\n                       OUTPUT_STRIP_TRAILING_WHITESPACE)\n      if (_result)\n        unset (_values)\n      else()\n        list (REMOVE_DUPLICATES _values)\n      endif()\n    elseif (NAME STREQUAL \"INCLUDES\")\n      if (WIN32)\n        set (_scheme \"nt\")\n      else()\n        set (_scheme \"posix_prefix\")\n      endif()\n      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                               \"import sys\\ntry:\\n   from distutils import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\\nexcept Exception:\\n   import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))\"\n                       RESULT_VARIABLE _result\n                       OUTPUT_VARIABLE _values\n                       ERROR_QUIET\n                       OUTPUT_STRIP_TRAILING_WHITESPACE)\n      if (_result)\n        unset (_values)\n      else()\n        list (REMOVE_DUPLICATES _values)\n      endif()\n    elseif (NAME STREQUAL \"SOABI\")\n      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                               \"import sys\\ntry:\\n   from distutils import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))\\nexcept Exception:\\n   import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))\"\n                       RESULT_VARIABLE _result\n                       OUTPUT_VARIABLE _soabi\n                       ERROR_QUIET\n                       OUTPUT_STRIP_TRAILING_WHITESPACE)\n      if (_result)\n        unset (_values)\n      else()\n        foreach (_item IN LISTS _soabi)\n          if (_item)\n            set (_values \"${_item}\")\n            break()\n          endif()\n        endforeach()\n        if (_values)\n          # clean-up: remove prefix character and suffix\n          if (_values MATCHES \"^(\\\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\\\.so|\\\\.pyd)$\")\n            set(_values \"\")\n          else()\n            string (REGEX REPLACE \"^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\\\.(so|pyd))$\" \"\\\\1\" _values \"${_values}\")\n          endif()\n        endif()\n      endif()\n    else()\n      set (config_flag \"${NAME}\")\n      if (NAME STREQUAL \"CONFIGDIR\")\n        set (config_flag \"LIBPL\")\n      endif()\n      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                               \"import sys\\ntry:\\n   from distutils import sysconfig\\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\\nexcept Exception:\\n   import sysconfig\\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\"\n                       RESULT_VARIABLE _result\n                       OUTPUT_VARIABLE _values\n                       ERROR_QUIET\n                       OUTPUT_STRIP_TRAILING_WHITESPACE)\n      if (_result)\n        unset (_values)\n      endif()\n    endif()\n  endif()\n\n  if (NAME STREQUAL \"ABIFLAGS\" OR NAME STREQUAL \"SOABI\")\n    set (${_PYTHON_PGCV_VALUE} \"${_values}\" PARENT_SCOPE)\n    return()\n  endif()\n\n  if (NOT _values OR _values STREQUAL \"None\")\n    return()\n  endif()\n\n  if (NAME STREQUAL \"LIBS\")\n    # do some clean-up\n    string (REGEX MATCHALL \"-(l|framework)[ ]*[^ ]+\" _values \"${_values}\")\n    # remove elements relative to python library itself\n    list (FILTER _values EXCLUDE REGEX \"-lpython\")\n    list (REMOVE_DUPLICATES _values)\n  endif()\n\n  if (WIN32 AND NAME MATCHES \"^(PREFIX|CONFIGDIR|INCLUDES)$\")\n    file (TO_CMAKE_PATH \"${_values}\" _values)\n  endif()\n\n  set (${_PYTHON_PGCV_VALUE} \"${_values}\" PARENT_SCOPE)\nendfunction()\n\nfunction (_PYTHON_GET_VERSION)\n  cmake_parse_arguments (PARSE_ARGV 0 _PGV \"LIBRARY;INCLUDE\" \"PREFIX\" \"\")\n\n  unset (${_PGV_PREFIX}VERSION PARENT_SCOPE)\n  unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE)\n  unset (${_PGV_PREFIX}VERSION_MINOR PARENT_SCOPE)\n  unset (${_PGV_PREFIX}VERSION_PATCH PARENT_SCOPE)\n  unset (${_PGV_PREFIX}ABI PARENT_SCOPE)\n\n  if (_PGV_LIBRARY)\n    # retrieve version and abi from library name\n    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n      get_filename_component (library_name \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" NAME)\n      # extract version from library name\n      if (library_name MATCHES \"python([23])([0-9]+)\")\n        set (${_PGV_PREFIX}VERSION_MAJOR \"${CMAKE_MATCH_1}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}VERSION_MINOR \"${CMAKE_MATCH_2}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}VERSION \"${CMAKE_MATCH_1}.${CMAKE_MATCH_2}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}ABI \"\" PARENT_SCOPE)\n      elseif (library_name MATCHES \"python([23])\\\\.([0-9]+)([dmu]*)\")\n        set (${_PGV_PREFIX}VERSION_MAJOR \"${CMAKE_MATCH_1}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}VERSION_MINOR \"${CMAKE_MATCH_2}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}VERSION \"${CMAKE_MATCH_1}.${CMAKE_MATCH_2}\" PARENT_SCOPE)\n        set (${_PGV_PREFIX}ABI \"${CMAKE_MATCH_3}\" PARENT_SCOPE)\n      elseif (library_name MATCHES \"pypy(3)?-c\")\n        set (version \"${CMAKE_MATCH_1}\")\n        if (version EQUAL \"3\")\n          set (${_PGV_PREFIX}VERSION_MAJOR \"3\" PARENT_SCOPE)\n          set (${_PGV_PREFIX}VERSION \"3\" PARENT_SCOPE)\n        else()\n          set (${_PGV_PREFIX}VERSION_MAJOR \"2\" PARENT_SCOPE)\n          set (${_PGV_PREFIX}VERSION \"2\" PARENT_SCOPE)\n        endif()\n        set (${_PGV_PREFIX}ABI \"\" PARENT_SCOPE)\n      endif()\n    endif()\n  else()\n    if (_${_PYTHON_PREFIX}_INCLUDE_DIR)\n      # retrieve version from header file\n      file (STRINGS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h\" version\n            REGEX \"^#define[ \\t]+PY_VERSION[ \\t]+\\\"[^\\\"]+\\\"\")\n      string (REGEX REPLACE \"^#define[ \\t]+PY_VERSION[ \\t]+\\\"([^\\\"]+)\\\".*\" \"\\\\1\"\n                            version \"${version}\")\n      string (REGEX MATCHALL \"[0-9]+\" versions \"${version}\")\n      list (GET versions 0 version_major)\n      list (GET versions 1 version_minor)\n      list (GET versions 2 version_patch)\n\n      set (${_PGV_PREFIX}VERSION \"${version_major}.${version_minor}.${version_patch}\" PARENT_SCOPE)\n      set (${_PGV_PREFIX}VERSION_MAJOR ${version_major} PARENT_SCOPE)\n      set (${_PGV_PREFIX}VERSION_MINOR ${version_minor} PARENT_SCOPE)\n      set (${_PGV_PREFIX}VERSION_PATCH ${version_patch} PARENT_SCOPE)\n\n      # compute ABI flags\n      if (version_major VERSION_GREATER \"2\")\n        file (STRINGS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}/pyconfig.h\" config REGEX \"(Py_DEBUG|WITH_PYMALLOC|Py_UNICODE_SIZE|MS_WIN32)\")\n        set (abi)\n        if (config MATCHES \"#[ ]*define[ ]+MS_WIN32\")\n          # ABI not used on Windows\n          set (abi \"\")\n        else()\n          if (NOT config)\n            # pyconfig.h can be a wrapper to a platform specific pyconfig.h\n            # In this case, try to identify ABI from include directory\n            if (_${_PYTHON_PREFIX}_INCLUDE_DIR MATCHES \"python${version_major}\\\\.${version_minor}+([dmu]*)\")\n              set (abi \"${CMAKE_MATCH_1}\")\n            else()\n              set (abi \"\")\n            endif()\n          else()\n            if (config MATCHES \"#[ ]*define[ ]+Py_DEBUG[ ]+1\")\n              string (APPEND abi \"d\")\n            endif()\n            if (config MATCHES \"#[ ]*define[ ]+WITH_PYMALLOC[ ]+1\")\n              string (APPEND abi \"m\")\n            endif()\n            if (config MATCHES \"#[ ]*define[ ]+Py_UNICODE_SIZE[ ]+4\")\n              string (APPEND abi \"u\")\n            endif()\n          endif()\n          set (${_PGV_PREFIX}ABI \"${abi}\" PARENT_SCOPE)\n        endif()\n      else()\n        # ABI not supported\n        set (${_PGV_PREFIX}ABI \"\" PARENT_SCOPE)\n      endif()\n    endif()\n  endif()\nendfunction()\n\nfunction (_PYTHON_GET_LAUNCHER _PYTHON_PGL_NAME)\n  cmake_parse_arguments (PARSE_ARGV 1 _PGL \"INTERPRETER;COMPILER\" \"\" \"\")\n\n  unset ({_PYTHON_PGL_NAME} PARENT_SCOPE)\n\n  if ((_PGL_INTERPRETER AND NOT _${_PYTHON_PREFIX}_EXECUTABLE)\n      OR (_PGL_COMPILER AND NOT _${_PYTHON_PREFIX}_COMPILER))\n    return()\n  endif()\n\n  if (\"IronPython\" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS\n      AND NOT SYSTEM_NAME MATCHES \"Windows|Linux\")\n    if (_PGL_INTERPRETER)\n      get_filename_component (name \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" NAME)\n      get_filename_component (ext \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" LAST_EXT)\n      if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES\n          AND ext STREQUAL \".exe\")\n        set (${_PYTHON_PGL_NAME} \"${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}\" PARENT_SCOPE)\n      endif()\n    else()\n      get_filename_component (name \"${_${_PYTHON_PREFIX}_COMPILER}\" NAME)\n      get_filename_component (ext \"${_${_PYTHON_PREFIX}_COMPILER}\" LAST_EXT)\n      if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES\n          AND ext STREQUAL \".exe\")\n        set (${_PYTHON_PGL_NAME} \"${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}\" PARENT_SCOPE)\n      endif()\n    endif()\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_VALIDATE_INTERPRETER)\n  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)\n    return()\n  endif()\n\n  cmake_parse_arguments (PARSE_ARGV 0 _PVI \"IN_RANGE;EXACT;CHECK_EXISTS\" \"VERSION\" \"\")\n\n  if (_PVI_CHECK_EXISTS AND NOT EXISTS \"${_${_PYTHON_PREFIX}_EXECUTABLE}\")\n    # interpreter does not exist anymore\n    set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Cannot find the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n    return()\n  endif()\n\n  _python_get_launcher (launcher INTERPRETER)\n\n  # validate ABI compatibility\n  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI)\n    execute_process (COMMAND ${launcher} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                             \"import sys; sys.stdout.write(sys.abiflags)\"\n                     RESULT_VARIABLE result\n                     OUTPUT_VARIABLE abi\n                     ERROR_QUIET\n                     OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (result)\n      # assume ABI is not supported\n      set (abi \"\")\n    endif()\n    if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)\n      # incompatible ABI\n      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong ABI for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n      return()\n    endif()\n  endif()\n\n  if (_PVI_IN_RANGE OR _PVI_VERSION)\n    # retrieve full version\n    execute_process (COMMAND ${launcher} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                             \"import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\"\n                     RESULT_VARIABLE result\n                     OUTPUT_VARIABLE version\n                     ERROR_QUIET\n                     OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (result)\n      # interpreter is not usable\n      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Cannot use the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n      return()\n    endif()\n\n    if (_PVI_VERSION)\n      # check against specified version\n      ## compute number of components for version\n      string (REGEX REPLACE \"[^.]\" \"\" dots \"${_PVI_VERSION}\")\n      ## add one dot because there is one dot less than there are components\n      string (LENGTH \"${dots}.\" count)\n      if (count GREATER 3)\n        set (count 3)\n      endif()\n      set (version_regex \"^[0-9]+\")\n      if (count EQUAL 3)\n        string (APPEND version_regex \"\\\\.[0-9]+\\\\.[0-9]+\")\n      elseif (count EQUAL 2)\n        string (APPEND version_regex \"\\\\.[0-9]+\")\n      endif()\n      # extract needed range\n      string (REGEX MATCH \"${version_regex}\" version \"${version}\")\n\n      if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION)\n        # interpreter has wrong version\n        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong version for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n        return()\n      else()\n        # check that version is OK\n        string(REGEX REPLACE \"^([0-9]+)\\\\.?.*$\" \"\\\\1\" major_version \"${version}\")\n        string(REGEX REPLACE \"^([0-9]+)\\\\.?.*$\" \"\\\\1\" expected_major_version \"${_PVI_VERSION}\")\n        if (NOT major_version VERSION_EQUAL expected_major_version\n            OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION)\n          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong version for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n          return()\n        endif()\n      endif()\n    endif()\n\n    if (_PVI_IN_RANGE)\n      # check if version is in the requested range\n      find_package_check_version (\"${version}\" in_range HANDLE_VERSION_RANGE)\n      if (NOT in_range)\n        # interpreter has invalid version\n        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong version for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n        return()\n      endif()\n    endif()\n  else()\n    get_filename_component (python_name \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" NAME)\n    if (NOT python_name STREQUAL \"python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}\")\n      # executable found do not have version in name\n      # ensure major version is OK\n      execute_process (COMMAND ${launcher} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                               \"import sys; sys.stdout.write(str(sys.version_info[0]))\"\n                       RESULT_VARIABLE result\n                       OUTPUT_VARIABLE version\n                       ERROR_QUIET\n                       OUTPUT_STRIP_TRAILING_WHITESPACE)\n      if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n        # interpreter not usable or has wrong major version\n        if (result)\n          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Cannot use the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n        else()\n          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong major version for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n        endif()\n        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n        return()\n      endif()\n    endif()\n  endif()\n\n  if (CMAKE_SIZEOF_VOID_P AND (\"Development.Module\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n        OR \"Development.Embed\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n      AND NOT CMAKE_CROSSCOMPILING)\n    # In this case, interpreter must have same architecture as environment\n    execute_process (COMMAND ${launcher} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                             \"import sys, struct; sys.stdout.write(str(struct.calcsize(\\\"P\\\")))\"\n                     RESULT_VARIABLE result\n                     OUTPUT_VARIABLE size\n                     ERROR_QUIET\n                     OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P)\n      # interpreter not usable or has wrong architecture\n      if (result)\n        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Cannot use the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n      else()\n        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Wrong architecture for the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\" PARENT_SCOPE)\n      endif()\n      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE \"${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND\")\n      return()\n    endif()\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_VALIDATE_COMPILER)\n  if (NOT _${_PYTHON_PREFIX}_COMPILER)\n    return()\n  endif()\n\n  cmake_parse_arguments (PARSE_ARGV 0 _PVC \"IN_RANGE;EXACT;CHECK_EXISTS\" \"VERSION\" \"\")\n\n  if (_PVC_CHECK_EXISTS AND NOT EXISTS \"${_${_PYTHON_PREFIX}_COMPILER}\")\n    # Compiler does not exist anymore\n    set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Cannot find the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n    return()\n  endif()\n\n  _python_get_launcher (launcher COMPILER)\n\n  # retrieve python environment version from compiler\n  set (working_dir \"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir\")\n  file (WRITE \"${working_dir}/version.py\" \"import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\\n\")\n  execute_process (COMMAND ${launcher} \"${_${_PYTHON_PREFIX}_COMPILER}\"\n                           ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}\n                           /target:exe /embed \"${working_dir}/version.py\"\n                   WORKING_DIRECTORY \"${working_dir}\"\n                   OUTPUT_QUIET\n                   ERROR_QUIET\n                   OUTPUT_STRIP_TRAILING_WHITESPACE)\n  get_filename_component (ir_dir \"${_${_PYTHON_PREFIX}_COMPILER}\" DIRECTORY)\n  execute_process (COMMAND \"${CMAKE_COMMAND}\" -E env \"MONO_PATH=${ir_dir}\"\n                                              ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} \"${working_dir}/version.exe\"\n                   WORKING_DIRECTORY \"${working_dir}\"\n                   RESULT_VARIABLE result\n                   OUTPUT_VARIABLE version\n                   ERROR_QUIET)\n  file (REMOVE_RECURSE \"${working_dir}\")\n  if (result)\n    # compiler is not usable\n    set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Cannot use the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n    return()\n  endif()\n\n  if (_PVC_VERSION OR _PVC_IN_RANGE)\n    if (_PVC_VERSION)\n      # check against specified version\n      ## compute number of components for version\n      string (REGEX REPLACE \"[^.]\" \"\" dots \"${_PVC_VERSION}\")\n      ## add one dot because there is one dot less than there are components\n      string (LENGTH \"${dots}.\" count)\n      if (count GREATER 3)\n        set (count 3)\n      endif()\n      set (version_regex \"^[0-9]+\")\n      if (count EQUAL 3)\n        string (APPEND version_regex \"\\\\.[0-9]+\\\\.[0-9]+\")\n      elseif (count EQUAL 2)\n        string (APPEND version_regex \"\\\\.[0-9]+\")\n      endif()\n      # extract needed range\n      string (REGEX MATCH \"${version_regex}\" version \"${version}\")\n\n      if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION)\n        # interpreter has wrong version\n        set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Wrong version for the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n        return()\n      else()\n        # check that version is OK\n        string(REGEX REPLACE \"^([0-9]+)\\\\.?.*$\" \"\\\\1\" major_version \"${version}\")\n        string(REGEX REPLACE \"^([0-9]+)\\\\.?.*$\" \"\\\\1\" expected_major_version \"${_PVC_VERSION}\")\n        if (NOT major_version VERSION_EQUAL expected_major_version\n            OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION)\n          set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Wrong version for the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n          return()\n        endif()\n      endif()\n    endif()\n\n    if (_PVC_IN_RANGE)\n      # check if version is in the requested range\n      find_package_check_version (\"${version}\" in_range HANDLE_VERSION_RANGE)\n      if (NOT in_range)\n        # interpreter has invalid version\n        set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Wrong version for the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n        return()\n      endif()\n    endif()\n  else()\n    string(REGEX REPLACE \"^([0-9]+)\\\\.?.*$\" \"\\\\1\" major_version \"${version}\")\n    if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n      # Compiler has wrong major version\n      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Wrong major version for the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\" PARENT_SCOPE)\n      set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE \"${_PYTHON_PREFIX}_COMPILER-NOTFOUND\")\n      return()\n    endif()\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_VALIDATE_LIBRARY)\n  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n    unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)\n    return()\n  endif()\n\n  cmake_parse_arguments (PARSE_ARGV 0 _PVL \"IN_RANGE;EXACT;CHECK_EXISTS\" \"VERSION\" \"\")\n\n  if (_PVL_CHECK_EXISTS AND NOT EXISTS \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\")\n    # library does not exist anymore\n    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Cannot find the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n    if (WIN32)\n      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND\")\n    endif()\n    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n    return()\n  endif()\n\n  # retrieve version and abi from library name\n  _python_get_version (LIBRARY PREFIX lib_)\n\n  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)\n    # incompatible ABI\n    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong ABI for the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n  else()\n    if (_PVL_VERSION OR _PVL_IN_RANGE)\n      if (_PVL_VERSION)\n        # library have only major.minor information\n        string (REGEX MATCH \"[0-9](\\\\.[0-9]+)?\" version \"${_PVL_VERSION}\")\n        if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version))\n          # library has wrong version\n          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong version for the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n        endif()\n      endif()\n\n      if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND _PVL_IN_RANGE)\n        # check if library version is in the requested range\n        find_package_check_version (\"${lib_VERSION}\" in_range HANDLE_VERSION_RANGE)\n        if (NOT in_range)\n          # library has wrong version\n          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong version for the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n        endif()\n      endif()\n    else()\n      if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n        # library has wrong major version\n        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong major version for the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n      endif()\n    endif()\n  endif()\n\n  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n    if (WIN32)\n      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND\")\n    endif()\n    unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE CACHE)\n    unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG CACHE)\n    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_VALIDATE_INCLUDE_DIR)\n  if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)\n    return()\n  endif()\n\n  cmake_parse_arguments (PARSE_ARGV 0 _PVID \"IN_RANGE;EXACT;CHECK_EXISTS\" \"VERSION\" \"\")\n\n  if (_PVID_CHECK_EXISTS AND NOT EXISTS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\")\n    # include file does not exist anymore\n    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Cannot find the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n    return()\n  endif()\n\n  # retrieve version from header file\n  _python_get_version (INCLUDE PREFIX inc_)\n\n  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)\n    # incompatible ABI\n    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong ABI for the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\" PARENT_SCOPE)\n    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n  else()\n    if (_PVID_VERSION OR _PVID_IN_RANGE)\n      if (_PVID_VERSION)\n        if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))\n          # include dir has wrong version\n          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong version for the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n        endif()\n      endif()\n\n      if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND PVID_IN_RANGE)\n        # check if include dir is in the request range\n        find_package_check_version (\"${inc_VERSION}\" in_range HANDLE_VERSION_RANGE)\n        if (NOT in_range)\n          # include dir has wrong version\n          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong version for the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\" PARENT_SCOPE)\n          set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n        endif()\n      endif()\n    else()\n      if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n        # include dir has wrong major version\n        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Wrong major version for the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\" PARENT_SCOPE)\n        set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n      endif()\n    endif()\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB)\n  string (REPLACE \"_RUNTIME\" \"\" _PYTHON_LIB \"${_PYTHON_LIB}\")\n  # look at runtime part on systems supporting it\n  if (CMAKE_SYSTEM_NAME STREQUAL \"Windows\" OR\n      (CMAKE_SYSTEM_NAME MATCHES \"MSYS|CYGWIN\"\n        AND ${_PYTHON_LIB} MATCHES \"${CMAKE_IMPORT_LIBRARY_SUFFIX}$\"))\n    set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX})\n    # MSYS has a special syntax for runtime libraries\n    if (CMAKE_SYSTEM_NAME MATCHES \"MSYS\")\n      list (APPEND CMAKE_FIND_LIBRARY_PREFIXES \"msys-\")\n    endif()\n    find_library (${ARGV})\n  endif()\nendfunction()\n\n\nfunction (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT)\n  unset (_PYTHON_DIRS)\n  set (_PYTHON_LIBS ${ARGN})\n  foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS)\n    if (${_PYTHON_LIB})\n      get_filename_component (_PYTHON_DIR \"${${_PYTHON_LIB}}\" DIRECTORY)\n      list (APPEND _PYTHON_DIRS \"${_PYTHON_DIR}\")\n    endif()\n  endforeach()\n  list (REMOVE_DUPLICATES _PYTHON_DIRS)\n  set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE)\nendfunction()\n\n\nfunction (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)\n  if (\"Development.${module}\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n    string(TOUPPER \"${module}\" id)\n    set (module_found TRUE)\n\n    if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS\n        AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n      set (module_found FALSE)\n    endif()\n    if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS\n        AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)\n      set (module_found FALSE)\n    endif()\n\n    set (${_PYTHON_PREFIX}_Development.${module}_FOUND ${module_found} PARENT_SCOPE)\n  endif()\nendfunction()\n\n\nif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n  # range must include internal major version\n  if (${_PYTHON_PREFIX}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR\n      OR ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL \"INCLUDE\"\n          AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n        OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL \"EXCLUDE\"\n          AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)))\n    _python_display_failure (\"Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \\\"${${_PYTHON_PREFIX}_FIND_VERSION_RANGE}\\\", but expected version range must include major version \\\"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\\\"\")\n\n    cmake_policy(POP)\n    return()\n  endif()\nelse()\n  if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR\n      AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n    # If major version is specified, it must be the same as internal major version\n    _python_display_failure (\"Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \\\"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\\\", but expected major version is \\\"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\\\"\")\n\n    cmake_policy(POP)\n    return()\n  endif()\nendif()\n\n\n# handle components\nif (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter)\n  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE)\nendif()\nif (\"NumPy\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS \"Interpreter\" \"Development.Module\")\nendif()\nif (\"Development\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS \"Development.Module\" \"Development.Embed\")\nendif()\nlist (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS)\nforeach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.Embed NumPy)\n  set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE)\nendforeach()\nif (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)\n  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE)\n  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed TRUE)\nendif()\n\nunset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\nunset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)\nunset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)\nif (\"Development.Module\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  if (CMAKE_SYSTEM_NAME MATCHES \"^(Windows.*|CYGWIN|MSYS)$\")\n    list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS \"LIBRARY\")\n  endif()\n  list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS \"INCLUDE_DIR\")\nendif()\nif (\"Development.Embed\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS \"LIBRARY\" \"INCLUDE_DIR\")\nendif()\nset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS})\nlist (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n\n# Set versions to search\n## default: search any version\nset (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS})\nunset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n\nif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n  unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)\n  foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)\n    if ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MIN STREQUAL \"INCLUDE\"\n          AND _${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MIN)\n        AND ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL \"INCLUDE\"\n            AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MAX)\n          OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL \"EXCLUDE\"\n            AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION_MAX)))\n      list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})\n    endif()\n  endforeach()\nelse()\n  if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)\n    if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n      set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT \"EXACT\")\n      set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR})\n    else()\n      unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)\n      # add all compatible versions\n      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)\n        if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}\")\n          list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})\n        endif()\n      endforeach()\n    endif()\n  endif()\nendif()\n\n# Set ABIs to search\n## default: search any ABI\nif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_LESS \"3\")\n  # ABI not supported\n  unset (_${_PYTHON_PREFIX}_FIND_ABI)\n  set (_${_PYTHON_PREFIX}_ABIFLAGS \"\")\nelse()\n  unset (_${_PYTHON_PREFIX}_FIND_ABI)\n  unset (_${_PYTHON_PREFIX}_ABIFLAGS)\n  if (DEFINED ${_PYTHON_PREFIX}_FIND_ABI)\n    # normalization\n    string (TOUPPER \"${${_PYTHON_PREFIX}_FIND_ABI}\" _${_PYTHON_PREFIX}_FIND_ABI)\n    list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE \"^(TRUE|Y(ES)?|1)$\" \"ON\")\n    list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE \"^(FALSE|N(O)?|0)$\" \"OFF\")\n    if (NOT _${_PYTHON_PREFIX}_FIND_ABI MATCHES \"^(ON|OFF|ANY);(ON|OFF|ANY);(ON|OFF|ANY)$\")\n      message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_ABI}: invalid value for '${_PYTHON_PREFIX}_FIND_ABI'. Ignore it\")\n      unset (_${_PYTHON_PREFIX}_FIND_ABI)\n    endif()\n    _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS)\n  endif()\nendif()\nunset (${_PYTHON_PREFIX}_SOABI)\n\n# Define lookup strategy\ncmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY)\nif (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL \"NEW\")\n  set (_${_PYTHON_PREFIX}_FIND_STRATEGY \"LOCATION\")\nelse()\n  set (_${_PYTHON_PREFIX}_FIND_STRATEGY \"VERSION\")\nendif()\nif (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY)\n  if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES \"^(VERSION|LOCATION)$\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.\")\n    set (_${_PYTHON_PREFIX}_FIND_STRATEGY \"VERSION\")\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_STRATEGY \"${${_PYTHON_PREFIX}_FIND_STRATEGY}\")\n  endif()\nendif()\n\n# Python and Anaconda distributions: define which architectures can be used\nif (CMAKE_SIZEOF_VOID_P)\n  # In this case, search only for 64bit or 32bit\n  math (EXPR _${_PYTHON_PREFIX}_ARCH \"${CMAKE_SIZEOF_VOID_P} * 8\")\n  set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})\nelse()\n  # architecture unknown, search for both 64bit and 32bit\n  set (_${_PYTHON_PREFIX}_ARCH 64)\n  set (_${_PYTHON_PREFIX}_ARCH2 32)\nendif()\n\n# IronPython support\nunset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES)\nunset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES)\nunset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS)\nif (CMAKE_SIZEOF_VOID_P)\n  if (_${_PYTHON_PREFIX}_ARCH EQUAL \"32\")\n    set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS \"/platform:x86\")\n  else()\n    set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS \"/platform:x64\")\n  endif()\nendif()\nif (NOT CMAKE_SYSTEM_NAME STREQUAL \"Linux\")\n  # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used\n  list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES \"ipy${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\" \"ipy64\" \"ipy32\" \"ipy\")\n  list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES \"ipyc\")\nendif()\nlist (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES \"ipy.exe\")\nlist (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES \"ipyc.exe\")\nset (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40 bin)\n\n# PyPy support\nif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL \"3\")\n  set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy3)\n  set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy3-c)\n  if (WIN32)\n    # special name for runtime part\n    list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy3-c)\n  endif()\n  set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy3)\nelse()\n  set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy)\n  set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy-c)\n  if (WIN32)\n    # special name for runtime part\n    list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy-c)\n  endif()\n  set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy)\nendif()\nset (_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES bin)\nset (_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES lib libs bin)\nlist (APPEND _${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES include)\n\n# Python Implementations handling\nunset (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\nif (DEFINED ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n  foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n    if (NOT _${_PYTHON_PREFIX}_IMPLEMENTATION MATCHES \"^(CPython|IronPython|PyPy)$\")\n      message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_IMPLEMENTATION}: invalid value for '${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS'. 'CPython', 'IronPython' or 'PyPy' expected. Value will be ignored.\")\n    else()\n      list (APPEND _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_IMPLEMENTATION})\n    endif()\n  endforeach()\nelse()\n  if (WIN32)\n    set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython IronPython)\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython)\n  endif()\nendif()\n\n# compute list of names for header file\nunset (_${_PYTHON_PREFIX}_INCLUDE_NAMES)\nforeach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n  if (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL \"CPython\")\n    list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES \"Python.h\")\n  elseif (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL \"PyPy\")\n    list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES \"PyPy.h\")\n  endif()\nendforeach()\n\n\n# Apple frameworks handling\n_python_find_frameworks ()\n\nset (_${_PYTHON_PREFIX}_FIND_FRAMEWORK \"FIRST\")\n\nif (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK)\n  if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES \"^(FIRST|LAST|NEVER)$\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.\")\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK})\n  endif()\nelseif (DEFINED CMAKE_FIND_FRAMEWORK)\n  if (CMAKE_FIND_FRAMEWORK STREQUAL \"ONLY\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.\")\n  elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES \"^(FIRST|LAST|NEVER)$\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.\")\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})\n  endif()\nendif()\n\n# Save CMAKE_FIND_APPBUNDLE\nif (DEFINED CMAKE_FIND_APPBUNDLE)\n  set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE})\nelse()\n  unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)\nendif()\n# To avoid app bundle lookup\nset (CMAKE_FIND_APPBUNDLE \"NEVER\")\n\n# Save CMAKE_FIND_FRAMEWORK\nif (DEFINED CMAKE_FIND_FRAMEWORK)\n  set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})\nelse()\n  unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)\nendif()\n# To avoid framework lookup\nset (CMAKE_FIND_FRAMEWORK \"NEVER\")\n\n# Windows Registry handling\nif (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY)\n  if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES \"^(FIRST|LAST|NEVER)$\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.\")\n    set (_${_PYTHON_PREFIX}_FIND_REGISTRY \"FIRST\")\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY})\n  endif()\nelse()\n  set (_${_PYTHON_PREFIX}_FIND_REGISTRY \"FIRST\")\nendif()\n\n# virtual environments recognition\nif (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})\n  if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)\n    if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY|STANDARD)$\")\n      message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.\")\n      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV \"FIRST\")\n    else()\n      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV})\n    endif()\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST)\n  endif()\nelse()\n  set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)\nendif()\n\n\n# Python naming handling\nif (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES)\n  if (NOT ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES MATCHES \"^(FIRST|LAST|NEVER)$\")\n    message (AUTHOR_WARNING \"Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}: invalid value for '${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES'. 'FIRST', 'LAST' or 'NEVER' expected. 'LAST' will be used instead.\")\n    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)\n  else()\n    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES ${${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES})\n  endif()\nelse()\n  set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)\nendif()\n\n\n# Compute search signature\n# This signature will be used to check validity of cached variables on new search\nset (_${_PYTHON_PREFIX}_SIGNATURE \"${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}\")\nif (NOT WIN32)\n  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE \":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:\")\nendif()\nif (CMAKE_HOST_APPLE)\n  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE \":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}\")\nendif()\nif (CMAKE_HOST_WIN32)\n  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE \":${_${_PYTHON_PREFIX}_FIND_REGISTRY}\")\nendif()\n\nfunction (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)\n  if (\"Development.${module}\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n    string (TOUPPER \"${module}\" id)\n    set (signature \"${_${_PYTHON_PREFIX}_SIGNATURE}:\")\n    if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n      list (APPEND signature \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:\")\n    endif()\n    if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n      list (APPEND signature \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}:\")\n    endif()\n    string (MD5 signature \"${signature}\")\n    if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE)\n      if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n        if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n          _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)\n        elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n          _python_validate_library (IN_RANGE CHECK_EXISTS)\n        elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)\n          _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)\n        else()\n          _python_validate_library (CHECK_EXISTS)\n        endif()\n      endif()\n      if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n        if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n          _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)\n        elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n          _python_validate_include_dir (IN_RANGE CHECK_EXISTS)\n        elseif (${_PYTHON_PREFIX}_FIND_VERSION)\n          _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)\n        else()\n          _python_validate_include_dir (CHECK_EXISTS)\n        endif()\n      endif()\n    else()\n      if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n        unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE)\n        unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)\n      endif()\n      if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n        unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)\n      endif()\n    endif()\n    if ((\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS\n          AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n        OR (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS\n          AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR))\n      unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n      unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)\n    endif()\n  endif()\nendfunction()\n\nfunction (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module)\n  string (TOUPPER \"${module}\" id)\n  if (${_PYTHON_PREFIX}_Development.${module}_FOUND)\n    set (signature \"${_${_PYTHON_PREFIX}_SIGNATURE}:\")\n    if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n      list (APPEND signature \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:\")\n    endif()\n    if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)\n      list (APPEND signature \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}:\")\n    endif()\n    string (MD5 signature \"${signature}\")\n    set (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE \"${signature}\" CACHE INTERNAL \"\")\n  else()\n    unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)\n  endif()\nendfunction()\n\n\nunset (_${_PYTHON_PREFIX}_REQUIRED_VARS)\nunset (_${_PYTHON_PREFIX}_CACHED_VARS)\nunset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)\nunset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)\nunset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)\nunset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)\n\n\n# preamble\n## For IronPython on platforms other than Windows, search for the .Net interpreter\nif (\"IronPython\" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS\n    AND NOT WIN32)\n  find_program (${_PYTHON_PREFIX}_DOTNET_LAUNCHER\n                NAMES \"mono\")\nendif()\n\n\n# first step, search for the interpreter\nif (\"Interpreter\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE\n                                              _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)\n  if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE)\n  endif()\n\n  if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE\n      AND IS_ABSOLUTE \"${${_PYTHON_PREFIX}_EXECUTABLE}\")\n    if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE)\n      # invalidate cache properties\n      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)\n    endif()\n    set (_${_PYTHON_PREFIX}_EXECUTABLE \"${${_PYTHON_PREFIX}_EXECUTABLE}\" CACHE INTERNAL \"\")\n  elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE)\n    # compute interpreter signature and check validity of definition\n    string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE \"${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}\")\n    if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)\n      # check version validity\n      if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n        _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)\n      elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        _python_validate_interpreter (IN_RANGE CHECK_EXISTS)\n      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)\n        _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)\n      else()\n        _python_validate_interpreter (CHECK_EXISTS)\n      endif()\n    else()\n      unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE)\n    endif()\n    if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)\n      unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)\n      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)\n    endif()\n  endif()\n\n  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)\n    set (_${_PYTHON_PREFIX}_HINTS \"${${_PYTHON_PREFIX}_ROOT_DIR}\" ENV ${_PYTHON_PREFIX}_ROOT_DIR)\n\n    if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL \"LOCATION\")\n      # build all executable names\n      _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX INTERPRETER)\n      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} INTERPRETER)\n\n      # Framework Paths\n      _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})\n      # Registry Paths\n      _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})\n\n      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})\n      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)\n      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})\n      endif()\n\n      while (TRUE)\n        # Virtual environments handling\n        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY)$\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n\n          _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL \"ONLY\")\n            break()\n          endif()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n        endif()\n\n        # try using HINTS\n        find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                      NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                      NO_SYSTEM_ENVIRONMENT_PATH\n                      NO_CMAKE_SYSTEM_PATH)\n        _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n        # try using standard paths\n        find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                      NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                      NAMES_PER_DIR\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n        _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n        endif()\n\n        break()\n      endwhile()\n    else()\n      # look-up for various versions and locations\n      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)\n      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)\n      endif()\n\n      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)\n        _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX INTERPRETER)\n        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INTERPRETER)\n\n        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})\n        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})\n\n        # Virtual environments handling\n        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY)$\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_EXECUTABLE)\n            break()\n          endif()\n          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL \"ONLY\")\n            continue()\n          endif()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n        endif()\n\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n        endif()\n\n        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n\n        # try using HINTS\n        find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                      NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                      NO_SYSTEM_ENVIRONMENT_PATH\n                      NO_CMAKE_SYSTEM_PATH)\n        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n        # try using standard paths.\n        # NAMES_PER_DIR is not defined on purpose to have a chance to find\n        # expected version.\n        # For example, typical systems have 'python' for version 2.* and 'python3'\n        # for version 3.*. So looking for names per dir will find, potentially,\n        # systematically 'python' (i.e. version 2) even if version 3 is searched.\n        find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                      NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n        endif()\n\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                        NAMES ${_${_PYTHON_PREFIX}_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n        endif()\n\n        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_EXECUTABLE)\n          break()\n        endif()\n      endforeach()\n\n      if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND\n          NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL \"ONLY\")\n        # No specific version found. Retry with generic names and standard paths.\n        # NAMES_PER_DIR is not defined on purpose to have a chance to find\n        # expected version.\n        # For example, typical systems have 'python' for version 2.* and 'python3'\n        # for version 3.*. So looking for names per dir will find, potentially,\n        # systematically 'python' (i.e. version 2) even if version 3 is searched.\n        _python_get_names (_${_PYTHON_PREFIX}_NAMES POSIX INTERPRETER)\n        find_program (_${_PYTHON_PREFIX}_EXECUTABLE\n                      NAMES ${_${_PYTHON_PREFIX}_NAMES})\n        _python_validate_interpreter ()\n      endif()\n    endif()\n  endif()\n\n  set (${_PYTHON_PREFIX}_EXECUTABLE \"${_${_PYTHON_PREFIX}_EXECUTABLE}\")\n  _python_get_launcher (_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER INTERPRETER)\n\n  # retrieve exact version of executable found\n  if (_${_PYTHON_PREFIX}_EXECUTABLE)\n    execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                             \"import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\"\n                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                     OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION\n                     ERROR_QUIET\n                     OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (NOT _${_PYTHON_PREFIX}_RESULT)\n      set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE)\n    else()\n      # Interpreter is not usable\n      set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE)\n      unset (${_PYTHON_PREFIX}_VERSION)\n      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE \"Cannot run the interpreter \\\"${_${_PYTHON_PREFIX}_EXECUTABLE}\\\"\")\n    endif()\n  endif()\n\n  if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE)\n    if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)\n      set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)\n\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID)\n\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH)\n\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH)\n      set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})\n\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI)\n\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_STDLIB)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDARCH)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_SITELIB)\n      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITEARCH)\n    else()\n      string (REGEX MATCHALL \"[0-9]+\" _${_PYTHON_PREFIX}_VERSIONS \"${${_PYTHON_PREFIX}_VERSION}\")\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR)\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR)\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH)\n\n      if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n        set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)\n\n        # Use interpreter version and ABI for future searches to ensure consistency\n        set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})\n        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETR_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                                 \"import sys; sys.stdout.write(sys.abiflags)\"\n                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS\n                         ERROR_QUIET\n                         OUTPUT_STRIP_TRAILING_WHITESPACE)\n        if (_${_PYTHON_PREFIX}_RESULT)\n          # assunme ABI is not supported\n          set (_${_PYTHON_PREFIX}_ABIFLAGS \"\")\n        endif()\n      endif()\n\n      if (${_PYTHON_PREFIX}_Interpreter_FOUND)\n        unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)\n\n        # compute and save interpreter signature\n        string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE \"${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}\")\n        set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE \"${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}\" CACHE INTERNAL \"\")\n\n        if (NOT CMAKE_SIZEOF_VOID_P)\n          # determine interpreter architecture\n          execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                                   \"import sys; sys.stdout.write(str(sys.maxsize > 2**32))\"\n                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                           OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT\n                           ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)\n          if (NOT _${_PYTHON_PREFIX}_RESULT)\n            if (${_PYTHON_PREFIX}_IS64BIT)\n              set (_${_PYTHON_PREFIX}_ARCH 64)\n              set (_${_PYTHON_PREFIX}_ARCH2 64)\n            else()\n              set (_${_PYTHON_PREFIX}_ARCH 32)\n              set (_${_PYTHON_PREFIX}_ARCH2 32)\n            endif()\n          endif()\n        endif()\n\n        # retrieve interpreter identity\n        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -V\n                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                         OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID\n                         ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)\n        if (NOT _${_PYTHON_PREFIX}_RESULT)\n          if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES \"Anaconda\")\n            set (${_PYTHON_PREFIX}_INTERPRETER_ID \"Anaconda\")\n          elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES \"Enthought\")\n            set (${_PYTHON_PREFIX}_INTERPRETER_ID \"Canopy\")\n          elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES \"PyPy ([0-9.]+)\")\n            set (${_PYTHON_PREFIX}_INTERPRETER_ID \"PyPy\")\n            set  (${_PYTHON_PREFIX}_PyPy_VERSION \"${CMAKE_MATCH_1}\")\n          else()\n            string (REGEX REPLACE \"^([^ ]+).*\" \"\\\\1\" ${_PYTHON_PREFIX}_INTERPRETER_ID \"${${_PYTHON_PREFIX}_INTERPRETER_ID}\")\n            if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL \"Python\")\n              # try to get a more precise ID\n              execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                                       \"import sys; sys.stdout.write(sys.copyright)\"\n                               RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                               OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT\n                               ERROR_QUIET)\n              if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES \"ActiveState\")\n                set (${_PYTHON_PREFIX}_INTERPRETER_ID \"ActivePython\")\n              endif()\n            endif()\n          endif()\n        else()\n          set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)\n        endif()\n\n        # retrieve various package installation directories\n        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                                 \"import sys\\ntry:\\n   from distutils import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\\nexcept Exception:\\n   import sysconfig\\n   sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))\"\n                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS\n                         ERROR_QUIET)\n        if (NOT _${_PYTHON_PREFIX}_RESULT)\n          list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)\n          list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)\n          list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)\n          list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)\n        else()\n          unset (${_PYTHON_PREFIX}_STDLIB)\n          unset (${_PYTHON_PREFIX}_STDARCH)\n          unset (${_PYTHON_PREFIX}_SITELIB)\n          unset (${_PYTHON_PREFIX}_SITEARCH)\n        endif()\n\n        _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)\n\n        # store properties in the cache to speed-up future searches\n        set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES\n          \"${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}\" CACHE INTERNAL \"${_PYTHON_PREFIX} Properties\")\n      else()\n        unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)\n        unset (${_PYTHON_PREFIX}_INTERPRETER_ID)\n      endif()\n    endif()\n  endif()\n\n  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)\n    set (${_PYTHON_PREFIX}_EXECUTABLE \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" CACHE FILEPATH \"${_PYTHON_PREFIX} Interpreter\")\n  endif()\n\n  _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE\n                            _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES\n                            _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)\nendif()\n\n\n# second step, search for compiler (IronPython)\nif (\"Compiler\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER)\n  if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER)\n  endif()\n\n  if (NOT \"IronPython\" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n    unset (_${_PYTHON_PREFIX}_COMPILER CACHE)\n    unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)\n  elseif (DEFINED ${_PYTHON_PREFIX}_COMPILER\n      AND IS_ABSOLUTE \"${${_PYTHON_PREFIX}_COMPILER}\")\n    set (_${_PYTHON_PREFIX}_COMPILER \"${${_PYTHON_PREFIX}_COMPILER}\" CACHE INTERNAL \"\")\n  elseif (DEFINED _${_PYTHON_PREFIX}_COMPILER)\n    # compute compiler signature and check validity of definition\n    string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE \"${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}\")\n    if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)\n      # check version validity\n      if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)\n        _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)\n      elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        _python_validate_compiler (IN_RANGE CHECK_EXISTS)\n      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)\n        _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)\n      else()\n        _python_validate_compiler (CHECK_EXISTS)\n      endif()\n    else()\n      unset (_${_PYTHON_PREFIX}_COMPILER CACHE)\n      unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)\n    endif()\n  endif()\n\n  if (\"IronPython\" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS\n      AND NOT _${_PYTHON_PREFIX}_COMPILER)\n    # IronPython specific artifacts\n    # If IronPython interpreter is found, use its path\n    unset (_${_PYTHON_PREFIX}_IRON_ROOT)\n    if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL \"IronPython\")\n      get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT \"${${_PYTHON_PREFIX}_EXECUTABLE}\" DIRECTORY)\n    endif()\n\n    if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL \"LOCATION\")\n      _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES\n                         IMPLEMENTATIONS IronPython\n                         VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}\n                         COMPILER)\n\n      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES\n                                 IMPLEMENTATIONS IronPython\n                                 VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}\n                                 COMPILER)\n\n      _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS\n                              IMPLEMENTATIONS IronPython\n                              VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})\n      _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS\n                              IMPLEMENTATIONS IronPython\n                              VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})\n\n      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})\n      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)\n      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})\n      endif()\n\n      while (TRUE)\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n\n        # try using HINTS\n        find_program (_${_PYTHON_PREFIX}_COMPILER\n                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                      NO_SYSTEM_ENVIRONMENT_PATH\n                      NO_CMAKE_SYSTEM_PATH)\n        _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_COMPILER)\n          break()\n        endif()\n\n        # try using standard paths\n        find_program (_${_PYTHON_PREFIX}_COMPILER\n                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                      NAMES_PER_DIR\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n        _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_COMPILER)\n          break()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n\n        break()\n      endwhile()\n    else()\n      # try using root dir and registry\n      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)\n      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)\n        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)\n      endif()\n\n      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)\n        _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES\n                           IMPLEMENTATIONS IronPython\n                           VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}\n                           COMPILER)\n\n        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES\n                                   IMPLEMENTATIONS IronPython\n                                   VERSION ${_${_PYTHON_PREFIX}_FIND_VERSION}\n                                   COMPILER)\n\n        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS\n                                IMPLEMENTATIONS IronPython\n                                VERSION ${_${_PYTHON_PREFIX}_VERSION})\n        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS\n                                IMPLEMENTATIONS IronPython\n                                VERSION ${_${_PYTHON_PREFIX}_VERSION})\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n\n        # try using HINTS\n        find_program (_${_PYTHON_PREFIX}_COMPILER\n                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                      NO_SYSTEM_ENVIRONMENT_PATH\n                      NO_CMAKE_SYSTEM_PATH)\n        _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n        if (_${_PYTHON_PREFIX}_COMPILER)\n          break()\n        endif()\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n        # Windows registry\n        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_COMPILER\n                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_DEFAULT_PATH)\n          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})\n          if (_${_PYTHON_PREFIX}_COMPILER)\n            break()\n          endif()\n        endif()\n      endforeach()\n\n      # no specific version found, re-try in standard paths\n      _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES\n                         IMPLEMENTATIONS IronPython\n                         VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}\n                         COMPILER)\n      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES\n                                 IMPLEMENTATIONS IronPython\n                                 VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}\n                                 COMPILER)\n      find_program (_${_PYTHON_PREFIX}_COMPILER\n                    NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}\n                    HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}\n                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n      _python_validate_compiler ()\n    endif()\n  endif()\n\n  set (${_PYTHON_PREFIX}_COMPILER \"${_${_PYTHON_PREFIX}_COMPILER}\")\n\n  if (_${_PYTHON_PREFIX}_COMPILER)\n    # retrieve python environment version from compiler\n    _python_get_launcher (_${_PYTHON_PREFIX}_COMPILER_LAUNCHER COMPILER)\n    set (_${_PYTHON_PREFIX}_VERSION_DIR \"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir\")\n    file (WRITE \"${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py\" \"import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\\n\")\n    execute_process (COMMAND ${_${_PYTHON_PREFIX}_COMPILER_LAUNCHER} \"${_${_PYTHON_PREFIX}_COMPILER}\"\n                             ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}\n                             /target:exe /embed \"${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py\"\n                     WORKING_DIRECTORY \"${_${_PYTHON_PREFIX}_VERSION_DIR}\"\n                     OUTPUT_QUIET\n                     ERROR_QUIET)\n    get_filename_component (_${_PYTHON_PREFIX}_IR_DIR \"${_${_PYTHON_PREFIX}_COMPILER}\" DIRECTORY)\n    execute_process (COMMAND \"${CMAKE_COMMAND}\" -E env \"MONO_PATH=${_${_PYTHON_PREFIX}_IR_DIR}\"\n                             ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} \"${_${_PYTHON_PREFIX}_VERSION_DIR}/version.exe\"\n                     WORKING_DIRECTORY \"${_${_PYTHON_PREFIX}_VERSION_DIR}\"\n                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION\n                     ERROR_QUIET)\n    if (NOT _${_PYTHON_PREFIX}_RESULT)\n      set (_${_PYTHON_PREFIX}_COMPILER_USABLE TRUE)\n      string (REGEX MATCHALL \"[0-9]+\" _${_PYTHON_PREFIX}_VERSIONS \"${_${_PYTHON_PREFIX}_VERSION}\")\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR)\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR)\n      list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH)\n\n      if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND)\n        # set public version information\n        set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})\n        set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})\n        set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})\n        set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})\n      endif()\n    else()\n      # compiler not usable\n      set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE)\n      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE \"Cannot run the compiler \\\"${_${_PYTHON_PREFIX}_COMPILER}\\\"\")\n    endif()\n    file (REMOVE_RECURSE \"${_${_PYTHON_PREFIX}_VERSION_DIR}\")\n  endif()\n\n  if (_${_PYTHON_PREFIX}_COMPILER AND _${_PYTHON_PREFIX}_COMPILER_USABLE)\n    if (${_PYTHON_PREFIX}_Interpreter_FOUND)\n      # Compiler must be compatible with interpreter\n      if (\"${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}\" VERSION_EQUAL \"${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}\")\n        set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)\n      endif()\n    elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n      set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)\n      # Use compiler version for future searches to ensure consistency\n      set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})\n    endif()\n  endif()\n\n  if (${_PYTHON_PREFIX}_Compiler_FOUND)\n    unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)\n\n    # compute and save compiler signature\n    string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE \"${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}\")\n    set (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE \"${__${_PYTHON_PREFIX}_COMPILER_SIGNATURE}\" CACHE INTERNAL \"\")\n\n    set (${_PYTHON_PREFIX}_COMPILER_ID IronPython)\n  else()\n    unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)\n    unset (${_PYTHON_PREFIX}_COMPILER_ID)\n  endif()\n\n  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)\n    set (${_PYTHON_PREFIX}_COMPILER \"${_${_PYTHON_PREFIX}_COMPILER}\" CACHE FILEPATH \"${_PYTHON_PREFIX} Compiler\")\n  endif()\n\n  _python_mark_as_internal (_${_PYTHON_PREFIX}_COMPILER\n                            _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)\nendif()\n\n# third step, search for the development artifacts\nif (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)\n  if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)\n  endif()\n  if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)\n  endif()\nendif()\nif (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed)\n  if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)\n  endif()\n  if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)\n    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)\n  endif()\nendif()\nlist (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS)\n## Development environment is not compatible with IronPython interpreter\nif ((\"Development.Module\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n      OR \"Development.Embed\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)\n    AND ((${_PYTHON_PREFIX}_Interpreter_FOUND\n        AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL \"IronPython\")\n      OR NOT ${_PYTHON_PREFIX}_Interpreter_FOUND))\n  if (${_PYTHON_PREFIX}_Interpreter_FOUND)\n    # reduce possible implementations to the interpreter one\n    if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL \"PyPy\")\n      set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS \"PyPy\")\n    else()\n      set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS \"CPython\")\n    endif()\n  else()\n    list (REMOVE_ITEM _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS \"IronPython\")\n  endif()\n  if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                                              _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE\n                                              _${_PYTHON_PREFIX}_LIBRARY_DEBUG\n                                              _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)\n  endif()\n  if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n    list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_INCLUDE_DIR)\n  endif()\n\n  _python_check_development_signature (Module)\n  _python_check_development_signature (Embed)\n\n  if (DEFINED ${_PYTHON_PREFIX}_LIBRARY\n      AND IS_ABSOLUTE \"${${_PYTHON_PREFIX}_LIBRARY}\")\n    set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE \"${${_PYTHON_PREFIX}_LIBRARY}\" CACHE INTERNAL \"\")\n    unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)\n    unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)\n  endif()\n  if (DEFINED ${_PYTHON_PREFIX}_INCLUDE_DIR\n      AND IS_ABSOLUTE \"${${_PYTHON_PREFIX}_INCLUDE_DIR}\")\n    set (_${_PYTHON_PREFIX}_INCLUDE_DIR \"${${_PYTHON_PREFIX}_INCLUDE_DIR}\" CACHE INTERNAL \"\")\n  endif()\n\n  # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES\n  unset (_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES)\n  if (DEFINED ${_PYTHON_PREFIX}_USE_STATIC_LIBS AND NOT WIN32)\n    set(_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})\n    if(${_PYTHON_PREFIX}_USE_STATIC_LIBS)\n      set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})\n    else()\n      list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})\n    endif()\n  endif()\n\n  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)\n    # if python interpreter is found, use it to look-up for artifacts\n    # to ensure consistency between interpreter and development environments.\n    # If not, try to locate a compatible config tool\n    if ((NOT ${_PYTHON_PREFIX}_Interpreter_FOUND OR CMAKE_CROSSCOMPILING)\n        AND \"CPython\" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n      set (_${_PYTHON_PREFIX}_HINTS \"${${_PYTHON_PREFIX}_ROOT_DIR}\" ENV ${_PYTHON_PREFIX}_ROOT_DIR)\n      unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)\n      if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY)$\")\n        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)\n      endif()\n\n      if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL \"LOCATION\")\n        _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX CONFIG)\n          # Framework Paths\n        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_program (_${_PYTHON_PREFIX}_CONFIG\n                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                              ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES bin\n                        NO_CMAKE_PATH\n                        NO_CMAKE_ENVIRONMENT_PATH\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n        endif()\n\n        find_program (_${_PYTHON_PREFIX}_CONFIG\n                      NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                      PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                      PATH_SUFFIXES bin)\n\n        # Apple frameworks handling\n        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          find_program (_${_PYTHON_PREFIX}_CONFIG\n                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                        PATH_SUFFIXES bin\n                        NO_DEFAULT_PATH)\n        endif()\n\n        if (_${_PYTHON_PREFIX}_CONFIG)\n          execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --help\n                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP\n                           ERROR_QUIET\n                           OUTPUT_STRIP_TRAILING_WHITESPACE)\n          if (_${_PYTHON_PREFIX}_RESULT)\n            # assume config tool is not usable\n            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n          endif()\n        endif()\n\n        if (_${_PYTHON_PREFIX}_CONFIG)\n          execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --abiflags\n                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS\n                           ERROR_QUIET\n                           OUTPUT_STRIP_TRAILING_WHITESPACE)\n          if (_${_PYTHON_PREFIX}_RESULT)\n            # assume ABI is not supported\n            set (__${_PYTHON_PREFIX}_ABIFLAGS \"\")\n          endif()\n          if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)\n            # Wrong ABI\n            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n          endif()\n        endif()\n\n        if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)\n          # check that config tool match library architecture\n          execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --configdir\n                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                           OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR\n                           ERROR_QUIET\n                           OUTPUT_STRIP_TRAILING_WHITESPACE)\n          if (_${_PYTHON_PREFIX}_RESULT)\n            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n          else()\n            string(FIND \"${_${_PYTHON_PREFIX}_CONFIGDIR}\" \"${CMAKE_LIBRARY_ARCHITECTURE}\" _${_PYTHON_PREFIX}_RESULT)\n            if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)\n              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n            endif()\n          endif()\n        endif()\n      else()\n        foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)\n          # try to use pythonX.Y-config tool\n          _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG)\n\n          # Framework Paths\n          _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})\n\n          # Apple frameworks handling\n          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n            find_program (_${_PYTHON_PREFIX}_CONFIG\n                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                          NAMES_PER_DIR\n                          HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                                ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                          PATH_SUFFIXES bin\n                          NO_CMAKE_PATH\n                          NO_CMAKE_ENVIRONMENT_PATH\n                          NO_SYSTEM_ENVIRONMENT_PATH\n                          NO_CMAKE_SYSTEM_PATH)\n          endif()\n\n          find_program (_${_PYTHON_PREFIX}_CONFIG\n                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                        PATH_SUFFIXES bin)\n\n          # Apple frameworks handling\n          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n            find_program (_${_PYTHON_PREFIX}_CONFIG\n                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}\n                          NAMES_PER_DIR\n                          PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                          PATH_SUFFIXES bin\n                          NO_DEFAULT_PATH)\n          endif()\n\n          unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)\n\n          if (_${_PYTHON_PREFIX}_CONFIG)\n            execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --help\n                             RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                             OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP\n                             ERROR_QUIET\n                             OUTPUT_STRIP_TRAILING_WHITESPACE)\n            if (_${_PYTHON_PREFIX}_RESULT)\n              # assume config tool is not usable\n              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n            endif()\n          endif()\n\n          if (NOT _${_PYTHON_PREFIX}_CONFIG)\n            continue()\n          endif()\n\n          execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --abiflags\n                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS\n                           ERROR_QUIET\n                           OUTPUT_STRIP_TRAILING_WHITESPACE)\n          if (_${_PYTHON_PREFIX}_RESULT)\n            # assume ABI is not supported\n            set (__${_PYTHON_PREFIX}_ABIFLAGS \"\")\n          endif()\n          if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)\n            # Wrong ABI\n            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n            continue()\n          endif()\n\n          if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)\n            # check that config tool match library architecture\n            execute_process (COMMAND \"${_${_PYTHON_PREFIX}_CONFIG}\" --configdir\n                             RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                             OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR\n                             ERROR_QUIET\n                             OUTPUT_STRIP_TRAILING_WHITESPACE)\n            if (_${_PYTHON_PREFIX}_RESULT)\n              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n              continue()\n            endif()\n            string (FIND \"${_${_PYTHON_PREFIX}_CONFIGDIR}\" \"${CMAKE_LIBRARY_ARCHITECTURE}\" _${_PYTHON_PREFIX}_RESULT)\n            if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)\n              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)\n              continue()\n            endif()\n          endif()\n\n          if (_${_PYTHON_PREFIX}_CONFIG)\n            break()\n          endif()\n        endforeach()\n      endif()\n    endif()\n  endif()\n\n  if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n    if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n      if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)\n        # retrieve root install directory\n        _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX)\n\n        # enforce current ABI\n        _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS)\n\n        set (_${_PYTHON_PREFIX}_HINTS \"${_${_PYTHON_PREFIX}_PREFIX}\")\n\n        # retrieve library\n        ## compute some paths and artifact names\n        if (_${_PYTHON_PREFIX}_CONFIG)\n          string (REGEX REPLACE \"^.+python([0-9.]+)[a-z]*-config\" \"\\\\1\" _${_PYTHON_PREFIX}_VERSION \"${_${_PYTHON_PREFIX}_CONFIG}\")\n        else()\n          set (_${_PYTHON_PREFIX}_VERSION \"${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}\")\n        endif()\n        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY)\n        _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)\n\n        _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR)\n        list (APPEND _${_PYTHON_PREFIX}_HINTS \"${_${_PYTHON_PREFIX}_CONFIGDIR}\")\n\n        list (APPEND _${_PYTHON_PREFIX}_HINTS \"${${_PYTHON_PREFIX}_ROOT_DIR}\" ENV ${_PYTHON_PREFIX}_ROOT_DIR)\n\n        find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                      NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                      NAMES_PER_DIR\n                      HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                      NO_SYSTEM_ENVIRONMENT_PATH\n                      NO_CMAKE_SYSTEM_PATH)\n      endif()\n\n      # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts\n      if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n        set (_${_PYTHON_PREFIX}_HINTS \"${${_PYTHON_PREFIX}_ROOT_DIR}\" ENV ${_PYTHON_PREFIX}_ROOT_DIR)\n\n        unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)\n        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY)$\")\n          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)\n        endif()\n\n        if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL \"LOCATION\")\n          # library names\n          _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 POSIX LIBRARY)\n          _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 DEBUG)\n          # Paths suffixes\n          _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} LIBRARY)\n\n          # Framework Paths\n          _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_FIND_VERSIONS})\n          # Registry Paths\n          _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} )\n\n          if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                          NAMES_PER_DIR\n                          HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                                ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                          NO_CMAKE_PATH\n                          NO_CMAKE_ENVIRONMENT_PATH\n                          NO_SYSTEM_ENVIRONMENT_PATH\n                          NO_CMAKE_SYSTEM_PATH)\n          endif()\n\n          if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                          NAMES_PER_DIR\n                          HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                                ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                          NO_SYSTEM_ENVIRONMENT_PATH\n                          NO_CMAKE_SYSTEM_PATH)\n          endif()\n\n          # search in HINTS locations\n          find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                        NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                        NAMES_PER_DIR\n                        HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                        NO_SYSTEM_ENVIRONMENT_PATH\n                        NO_CMAKE_SYSTEM_PATH)\n\n          if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n            set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})\n          else()\n            unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)\n          endif()\n\n          if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n            set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})\n          else()\n            unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)\n          endif()\n\n          # search in all default paths\n          find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                        NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                        NAMES_PER_DIR\n                        PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                              ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n        else()\n          foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)\n            _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY)\n            _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG)\n\n            _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})\n            _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})\n\n            _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)\n\n            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n              find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                            NAMES_PER_DIR\n                            HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                                  ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                            NO_CMAKE_PATH\n                            NO_CMAKE_ENVIRONMENT_PATH\n                            NO_SYSTEM_ENVIRONMENT_PATH\n                            NO_CMAKE_SYSTEM_PATH)\n            endif()\n\n            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n              find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                            NAMES_PER_DIR\n                            HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                                  ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                            NO_SYSTEM_ENVIRONMENT_PATH\n                            NO_CMAKE_SYSTEM_PATH)\n            endif()\n\n            # search in HINTS locations\n            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                          NAMES_PER_DIR\n                          HINTS ${_${_PYTHON_PREFIX}_HINTS}\n                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                          NO_SYSTEM_ENVIRONMENT_PATH\n                          NO_CMAKE_SYSTEM_PATH)\n\n            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n              set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})\n            else()\n              unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)\n            endif()\n\n            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n              set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})\n            else()\n              unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)\n            endif()\n\n            # search in all default paths\n            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                          NAMES_PER_DIR\n                          PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                                ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})\n\n            if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n              break()\n            endif()\n          endforeach()\n        endif()\n      endif()\n    endif()\n\n    # finalize library version information\n    _python_get_version (LIBRARY PREFIX _${_PYTHON_PREFIX}_)\n    if (_${_PYTHON_PREFIX}_VERSION EQUAL \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\")\n      # not able to extract full version from library name\n      if (${_PYTHON_PREFIX}_Interpreter_FOUND)\n        # update from interpreter\n        set (_${_PYTHON_PREFIX}_VERSION ${${_PYTHON_PREFIX}_VERSION})\n        set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${${_PYTHON_PREFIX}_VERSION_MAJOR})\n        set (_${_PYTHON_PREFIX}_VERSION_MINOR ${${_PYTHON_PREFIX}_VERSION_MINOR})\n        set (_${_PYTHON_PREFIX}_VERSION_PATCH ${${_PYTHON_PREFIX}_VERSION_PATCH})\n      endif()\n    endif()\n\n    set (${_PYTHON_PREFIX}_LIBRARY_RELEASE \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\")\n\n    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\")\n      set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Cannot find the library \\\"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\\\"\")\n      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE \"${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND\")\n    endif()\n\n    set (_${_PYTHON_PREFIX}_HINTS \"${${_PYTHON_PREFIX}_ROOT_DIR}\" ENV ${_PYTHON_PREFIX}_ROOT_DIR)\n\n    if (WIN32 AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n      # search for debug library\n      # use release library location as a hint\n      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)\n      get_filename_component (_${_PYTHON_PREFIX}_PATH \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" DIRECTORY)\n      find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG\n                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}\n                    NAMES_PER_DIR\n                    HINTS \"${_${_PYTHON_PREFIX}_PATH}\" ${_${_PYTHON_PREFIX}_HINTS}\n                    NO_DEFAULT_PATH)\n      # second try including CMAKE variables to catch-up non conventional layouts\n      find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG\n                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}\n                    NAMES_PER_DIR\n                    NO_SYSTEM_ENVIRONMENT_PATH\n                    NO_CMAKE_SYSTEM_PATH)\n    endif()\n\n    # retrieve runtime libraries\n    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)\n      get_filename_component (_${_PYTHON_PREFIX}_PATH \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" DIRECTORY)\n      get_filename_component (_${_PYTHON_PREFIX}_PATH2 \"${_${_PYTHON_PREFIX}_PATH}\" DIRECTORY)\n      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE\n                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}\n                                    NAMES_PER_DIR\n                                    HINTS \"${_${_PYTHON_PREFIX}_PATH}\"\n                                          \"${_${_PYTHON_PREFIX}_PATH2}\" ${_${_PYTHON_PREFIX}_HINTS}\n                                    PATH_SUFFIXES bin)\n    endif()\n    if (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)\n      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)\n      get_filename_component (_${_PYTHON_PREFIX}_PATH \"${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}\" DIRECTORY)\n      get_filename_component (_${_PYTHON_PREFIX}_PATH2 \"${_${_PYTHON_PREFIX}_PATH}\" DIRECTORY)\n      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG\n                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}\n                                    NAMES_PER_DIR\n                                    HINTS \"${_${_PYTHON_PREFIX}_PATH}\"\n                                          \"${_${_PYTHON_PREFIX}_PATH2}\" ${_${_PYTHON_PREFIX}_HINTS}\n                                    PATH_SUFFIXES bin)\n    endif()\n  endif()\n\n  if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n    while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)\n      if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS\n          AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n        # Don't search for include dir if no library was founded\n        break()\n      endif()\n\n      if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)\n        _python_get_config_var (_${_PYTHON_PREFIX}_INCLUDE_DIRS INCLUDES)\n\n        find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR\n                   NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}\n                   HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS}\n                   NO_SYSTEM_ENVIRONMENT_PATH\n                   NO_CMAKE_SYSTEM_PATH)\n      endif()\n\n      # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts\n      if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)\n        unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)\n        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES \"^(FIRST|ONLY)$\")\n          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)\n        endif()\n        unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)\n\n        if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n          # Use the library's install prefix as a hint\n          if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES \"^(.+/Frameworks/Python.framework/Versions/[0-9.]+)\")\n            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS \"${CMAKE_MATCH_1}\")\n          elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES \"^(.+)/lib(64|32)?/python[0-9.]+/config\")\n            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS \"${CMAKE_MATCH_1}\")\n          elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIBRARY_RELEASE} MATCHES \"^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}\")\n            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS \"${CMAKE_MATCH_1}\")\n          else()\n            # assume library is in a directory under root\n            get_filename_component (_${_PYTHON_PREFIX}_PREFIX \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" DIRECTORY)\n            get_filename_component (_${_PYTHON_PREFIX}_PREFIX \"${_${_PYTHON_PREFIX}_PREFIX}\" DIRECTORY)\n            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS \"${_${_PYTHON_PREFIX}_PREFIX}\")\n          endif()\n        endif()\n\n        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})\n        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})\n        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INCLUDE)\n\n        if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"FIRST\")\n          find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR\n                     NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}\n                     HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}\n                     PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                           ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                     PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                     NO_CMAKE_PATH\n                     NO_CMAKE_ENVIRONMENT_PATH\n                     NO_SYSTEM_ENVIRONMENT_PATH\n                     NO_CMAKE_SYSTEM_PATH)\n        endif()\n\n        if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"FIRST\")\n          find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR\n                     NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}\n                     HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}\n                     PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                           ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                     PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                     NO_SYSTEM_ENVIRONMENT_PATH\n                     NO_CMAKE_SYSTEM_PATH)\n        endif()\n\n        if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL \"LAST\")\n          set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})\n        else()\n          unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)\n        endif()\n\n        if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL \"LAST\")\n          set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})\n        else()\n          unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)\n        endif()\n\n        find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR\n                   NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}\n                   HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}\n                   PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}\n                         ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}\n                         ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}\n                   PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}\n                   NO_SYSTEM_ENVIRONMENT_PATH\n                   NO_CMAKE_SYSTEM_PATH)\n      endif()\n\n      # search header file in standard locations\n      find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR\n                 NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES})\n\n      break()\n    endwhile()\n\n    set (${_PYTHON_PREFIX}_INCLUDE_DIRS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\")\n\n    if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\")\n      set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE \"Cannot find the directory \\\"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\\\"\")\n      set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND\")\n    endif()\n\n    if (_${_PYTHON_PREFIX}_INCLUDE_DIR)\n      # retrieve version from header file\n      _python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_)\n      if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)\n        if (\"${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}\"\n            VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION)\n          # update versioning\n          set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})\n          set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})\n        endif()\n      else()\n        set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})\n        set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR})\n        set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR})\n        set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})\n      endif()\n    endif()\n  endif()\n\n  if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND)\n    # set public version information\n    set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})\n    set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})\n    set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})\n    set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})\n  endif()\n\n  # define public variables\n  if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n    set (${_PYTHON_PREFIX}_LIBRARY_DEBUG \"${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}\")\n    _python_select_library_configurations (${_PYTHON_PREFIX})\n\n    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE \"${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}\")\n    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG \"${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}\")\n\n    if (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)\n      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY \"${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}\")\n    elseif (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)\n      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY \"${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}\")\n    else()\n      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY \"${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND\")\n    endif()\n\n    _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS\n                              _${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                              _${_PYTHON_PREFIX}_LIBRARY_DEBUG)\n    if (UNIX)\n      if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES \"${CMAKE_SHARED_LIBRARY_SUFFIX}$\")\n        set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})\n      endif()\n    else()\n      _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS\n                                _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE\n                                _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)\n    endif()\n  endif()\n\n  if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR)\n    if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND)\n      # development environment must be compatible with interpreter/compiler\n      if (\"${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}\" VERSION_EQUAL \"${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}\"\n          AND \"${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}\" VERSION_EQUAL \"${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}\")\n        _python_set_development_module_found (Module)\n        _python_set_development_module_found (Embed)\n      endif()\n    elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR\n        AND \"${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}\" VERSION_EQUAL \"${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}\")\n      _python_set_development_module_found (Module)\n      _python_set_development_module_found (Embed)\n    endif()\n    if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND\n        (NOT _${_PYTHON_PREFIX}_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS\n          OR NOT _${_PYTHON_PREFIX}_INC_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS))\n      set (${_PYTHON_PREFIX}_Development.Module_FOUND FALSE)\n      set (${_PYTHON_PREFIX}_Development.Embed_FOUND FALSE)\n    endif()\n  endif()\n\n  if (( ${_PYTHON_PREFIX}_Development.Module_FOUND\n        AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)\n      OR (NOT \"Development.Module\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n        AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)\n      OR (NOT \"Development.Embed\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n        AND ${_PYTHON_PREFIX}_Development.Module_FOUND))\n    unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)\n  endif()\n\n  if (\"Development\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n      AND ${_PYTHON_PREFIX}_Development.Module_FOUND\n      AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)\n    set (${_PYTHON_PREFIX}_Development_FOUND TRUE)\n  endif()\n\n  if ((${_PYTHON_PREFIX}_Development.Module_FOUND\n      OR ${_PYTHON_PREFIX}_Development.Embed_FOUND)\n    AND EXISTS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}/PyPy.h\")\n  # retrieve PyPy version\n  file (STRINGS \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h\" ${_PYTHON_PREFIX}_PyPy_VERSION\n                REGEX \"^#define[ \\t]+PYPY_VERSION[ \\t]+\\\"[^\\\"]+\\\"\")\n  string (REGEX REPLACE \"^#define[ \\t]+PYPY_VERSION[ \\t]+\\\"([^\\\"]+)\\\".*\" \"\\\\1\"\n                ${_PYTHON_PREFIX}_PyPy_VERSION \"${${_PYTHON_PREFIX}_PyPy_VERSION}\")\n  endif()\n\n  unset(${_PYTHON_PREFIX}_LINK_OPTIONS)\n  if (${_PYTHON_PREFIX}_Development.Embed_FOUND AND APPLE\n      AND ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES \"${CMAKE_SHARED_LIBRARY_SUFFIX}$\")\n    # rpath must be specified if python is part of a framework\n    unset(_${_PYTHON_PREFIX}_is_prefix)\n    foreach (_${_PYTHON_PREFIX}_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)\n      foreach (_${_PYTHON_PREFIX}_framework IN LISTS _${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_implementation}_FRAMEWORKS)\n        cmake_path (IS_PREFIX _${_PYTHON_PREFIX}_framework \"${${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" _${_PYTHON_PREFIX}_is_prefix)\n        if (_${_PYTHON_PREFIX}_is_prefix)\n          cmake_path (GET _${_PYTHON_PREFIX}_framework PARENT_PATH _${_PYTHON_PREFIX}_framework)\n          set (${_PYTHON_PREFIX}_LINK_OPTIONS \"LINKER:-rpath,${_${_PYTHON_PREFIX}_framework}\")\n          break()\n        endif()\n      endforeach()\n      if (_${_PYTHON_PREFIX}_is_prefix)\n        break()\n      endif()\n    endforeach()\n    unset(_${_PYTHON_PREFIX}_implementation)\n    unset(_${_PYTHON_PREFIX}_framework)\n    unset(_${_PYTHON_PREFIX}_is_prefix)\n  endif()\n\n  if (NOT DEFINED ${_PYTHON_PREFIX}_SOABI)\n    _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)\n  endif()\n\n  _python_compute_development_signature (Module)\n  _python_compute_development_signature (Embed)\n\n  # Restore the original find library ordering\n  if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES)\n    set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES})\n  endif()\n\n  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)\n    if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n      set (${_PYTHON_PREFIX}_LIBRARY \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\" CACHE FILEPATH \"${_PYTHON_PREFIX} Library\")\n    endif()\n    if (\"INCLUDE_DIR\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)\n      set (${_PYTHON_PREFIX}_INCLUDE_DIR \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\" CACHE FILEPATH \"${_PYTHON_PREFIX} Include Directory\")\n    endif()\n  endif()\n\n  _python_mark_as_internal (_${_PYTHON_PREFIX}_LIBRARY_RELEASE\n                            _${_PYTHON_PREFIX}_LIBRARY_DEBUG\n                            _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE\n                            _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG\n                            _${_PYTHON_PREFIX}_INCLUDE_DIR\n                            _${_PYTHON_PREFIX}_CONFIG\n                            _${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE\n                            _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE)\nendif()\n\nif (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy)\n  list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS)\nendif()\nif (\"NumPy\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND)\n  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)\n\n  if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR\n      AND IS_ABSOLUTE \"${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\")\n    set (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR \"${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\" CACHE INTERNAL \"\")\n  elseif (DEFINED _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)\n    # compute numpy signature. Depends on interpreter and development signatures\n    string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE \"${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\")\n    if (NOT __${_PYTHON_PREFIX}_NUMPY_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_NUMPY_SIGNATURE\n        OR NOT EXISTS \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\")\n      unset (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR CACHE)\n      unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)\n    endif()\n  endif()\n\n  if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)\n    execute_process(COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                            \"import sys\\ntry: import numpy; sys.stdout.write(numpy.get_include())\\nexcept:pass\\n\"\n                    RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                    OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH\n                    ERROR_QUIET\n                    OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n    if (NOT _${_PYTHON_PREFIX}_RESULT)\n      find_path (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR\n                 NAMES \"numpy/arrayobject.h\" \"numpy/numpyconfig.h\"\n                 HINTS \"${_${_PYTHON_PREFIX}_NumPy_PATH}\"\n                 NO_DEFAULT_PATH)\n    endif()\n  endif()\n\n  set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\")\n\n  if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\")\n    set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE \"Cannot find the directory \\\"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\\\"\")\n    set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE \"${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND\")\n  endif()\n\n  if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)\n    execute_process (COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} \"${_${_PYTHON_PREFIX}_EXECUTABLE}\" -c\n                             \"import sys\\ntry: import numpy; sys.stdout.write(numpy.__version__)\\nexcept:pass\\n\"\n                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT\n                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION)\n    if (NOT _${_PYTHON_PREFIX}_RESULT)\n      set (${_PYTHON_PREFIX}_NumPy_VERSION \"${_${_PYTHON_PREFIX}_NumPy_VERSION}\")\n    else()\n      unset (${_PYTHON_PREFIX}_NumPy_VERSION)\n    endif()\n\n    # final step: set NumPy founded only if Development.Module component is founded as well\n    set(${_PYTHON_PREFIX}_NumPy_FOUND ${${_PYTHON_PREFIX}_Development.Module_FOUND})\n  else()\n    set (${_PYTHON_PREFIX}_NumPy_FOUND FALSE)\n  endif()\n\n  if (${_PYTHON_PREFIX}_NumPy_FOUND)\n    unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)\n\n    # compute and save numpy signature\n    string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE \"${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}\")\n    set (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE \"${__${_PYTHON_PREFIX}_NUMPY_SIGNATURE}\" CACHE INTERNAL \"\")\n  else()\n    unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)\n  endif()\n\n  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)\n    set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\" CACHE FILEPATH \"${_PYTHON_PREFIX} NumPy Include Directory\")\n  endif()\n\n  _python_mark_as_internal (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR\n                            _${_PYTHON_PREFIX}_NUMPY_SIGNATURE)\nendif()\n\n# final validation\nif (${_PYTHON_PREFIX}_VERSION_MAJOR AND\n    NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)\n  _python_display_failure (\"Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \\\"${${_PYTHON_PREFIX}_VERSION_MAJOR}\\\", but required major version is exact version \\\"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\\\"\")\n\n  cmake_policy(POP)\n  return()\nendif()\n\nunset (_${_PYTHON_PREFIX}_REASON_FAILURE)\nforeach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)\n  if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)\n    string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE \"\\n        ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}\")\n    unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)\n  endif()\nendforeach()\n\nfind_package_handle_standard_args (${_PYTHON_PREFIX}\n                                   REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}\n                                   VERSION_VAR ${_PYTHON_PREFIX}_VERSION\n                                   HANDLE_VERSION_RANGE\n                                   HANDLE_COMPONENTS\n                                   REASON_FAILURE_MESSAGE \"${_${_PYTHON_PREFIX}_REASON_FAILURE}\")\n\n# Create imported targets and helper functions\nif(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL \"PROJECT\")\n  if (\"Interpreter\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n      AND ${_PYTHON_PREFIX}_Interpreter_FOUND\n      AND NOT TARGET ${_PYTHON_PREFIX}::Interpreter)\n    add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED)\n    set_property (TARGET ${_PYTHON_PREFIX}::Interpreter\n                  PROPERTY IMPORTED_LOCATION \"${${_PYTHON_PREFIX}_EXECUTABLE}\")\n  endif()\n\n  if (\"Compiler\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n      AND ${_PYTHON_PREFIX}_Compiler_FOUND\n      AND NOT TARGET ${_PYTHON_PREFIX}::Compiler)\n    add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED)\n    set_property (TARGET ${_PYTHON_PREFIX}::Compiler\n                  PROPERTY IMPORTED_LOCATION \"${${_PYTHON_PREFIX}_COMPILER}\")\n  endif()\n\n  if ((\"Development.Module\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n        AND ${_PYTHON_PREFIX}_Development.Module_FOUND)\n      OR (\"Development.Embed\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS\n        AND ${_PYTHON_PREFIX}_Development.Embed_FOUND))\n\n    macro (__PYTHON_IMPORT_LIBRARY __name)\n      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES \"${CMAKE_SHARED_LIBRARY_SUFFIX}$\"\n          OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)\n        set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)\n      else()\n        set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)\n      endif()\n\n      if (NOT TARGET ${__name})\n        add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)\n      endif()\n\n      set_property (TARGET ${__name}\n                    PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${${_PYTHON_PREFIX}_INCLUDE_DIRS}\")\n\n      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)\n        # System manage shared libraries in two parts: import and runtime\n        if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)\n          set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE \"C\"\n                                            IMPORTED_IMPLIB_RELEASE \"${${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"\n                                            IMPORTED_LOCATION_RELEASE \"${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}\")\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG \"C\"\n                                            IMPORTED_IMPLIB_DEBUG \"${${_PYTHON_PREFIX}_LIBRARY_DEBUG}\"\n                                            IMPORTED_LOCATION_DEBUG \"${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}\")\n        else()\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES \"C\"\n                                            IMPORTED_IMPLIB \"${${_PYTHON_PREFIX}_LIBRARIES}\"\n                                            IMPORTED_LOCATION \"${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}\")\n        endif()\n      else()\n        if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)\n          set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE \"C\"\n                                            IMPORTED_LOCATION_RELEASE \"${${_PYTHON_PREFIX}_LIBRARY_RELEASE}\")\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG \"C\"\n                                            IMPORTED_LOCATION_DEBUG \"${${_PYTHON_PREFIX}_LIBRARY_DEBUG}\")\n        else()\n          set_target_properties (${__name}\n                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES \"C\"\n                                            IMPORTED_LOCATION \"${${_PYTHON_PREFIX}_LIBRARY_RELEASE}\")\n        endif()\n      endif()\n\n      if (_${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL \"STATIC\")\n        # extend link information with dependent libraries\n        _python_get_config_var (_${_PYTHON_PREFIX}_LINK_LIBRARIES LIBS)\n        if (_${_PYTHON_PREFIX}_LINK_LIBRARIES)\n          set_property (TARGET ${__name}\n                        PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})\n        endif()\n      endif()\n\n      if (${_PYTHON_PREFIX}_LINK_OPTIONS\n          AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL \"SHARED\")\n        set_property (TARGET ${__name} PROPERTY INTERFACE_LINK_OPTIONS \"${${_PYTHON_PREFIX}_LINK_OPTIONS}\")\n      endif()\n    endmacro()\n\n    if (${_PYTHON_PREFIX}_Development.Embed_FOUND)\n      __python_import_library (${_PYTHON_PREFIX}::Python)\n    endif()\n\n    if (${_PYTHON_PREFIX}_Development.Module_FOUND)\n      if (\"LIBRARY\" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)\n        # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python\n        # but ALIAS cannot be used because the imported library is not GLOBAL.\n        __python_import_library (${_PYTHON_PREFIX}::Module)\n      else()\n        if (NOT TARGET ${_PYTHON_PREFIX}::Module)\n          add_library (${_PYTHON_PREFIX}::Module INTERFACE IMPORTED)\n        endif()\n        set_property (TARGET ${_PYTHON_PREFIX}::Module\n                      PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${${_PYTHON_PREFIX}_INCLUDE_DIRS}\")\n\n        # When available, enforce shared library generation with undefined symbols\n        if (APPLE)\n          set_property (TARGET ${_PYTHON_PREFIX}::Module\n                        PROPERTY INTERFACE_LINK_OPTIONS \"LINKER:-undefined,dynamic_lookup\")\n        endif()\n        if (CMAKE_SYSTEM_NAME STREQUAL \"SunOS\")\n          set_property (TARGET ${_PYTHON_PREFIX}::Module\n                        PROPERTY INTERFACE_LINK_OPTIONS \"LINKER:-z,nodefs\")\n        endif()\n        if (CMAKE_SYSTEM_NAME STREQUAL \"AIX\")\n          set_property (TARGET ${_PYTHON_PREFIX}::Module\n                        PROPERTY INTERFACE_LINK_OPTIONS \"LINKER:-b,erok\")\n        endif()\n      endif()\n    endif()\n\n    #\n    # PYTHON_ADD_LIBRARY (<name> [STATIC|SHARED|MODULE] src1 src2 ... srcN)\n    # It is used to build modules for python.\n    #\n    function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name)\n      cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY \"STATIC;SHARED;MODULE;WITH_SOABI\" \"\" \"\")\n\n      if (PYTHON_ADD_LIBRARY_STATIC)\n        set (type STATIC)\n      elseif (PYTHON_ADD_LIBRARY_SHARED)\n        set (type SHARED)\n      else()\n        set (type MODULE)\n      endif()\n\n      if (type STREQUAL \"MODULE\" AND NOT TARGET ${prefix}::Module)\n        message (SEND_ERROR \"${prefix}_ADD_LIBRARY: dependent target '${prefix}::Module' is not defined.\\n   Did you miss to request COMPONENT 'Development.Module'?\")\n        return()\n      endif()\n      if (NOT type STREQUAL \"MODULE\" AND NOT TARGET ${prefix}::Python)\n        message (SEND_ERROR \"${prefix}_ADD_LIBRARY: dependent target '${prefix}::Python' is not defined.\\n   Did you miss to request COMPONENT 'Development.Embed'?\")\n        return()\n      endif()\n\n      add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS})\n\n      get_property (type TARGET ${name} PROPERTY TYPE)\n\n      if (type STREQUAL \"MODULE_LIBRARY\")\n        target_link_libraries (${name} PRIVATE ${prefix}::Module)\n        # customize library name to follow module name rules\n        set_property (TARGET ${name} PROPERTY PREFIX \"\")\n        if(CMAKE_SYSTEM_NAME STREQUAL \"Windows\")\n          set_property (TARGET ${name} PROPERTY SUFFIX \".pyd\")\n        endif()\n\n        if (PYTHON_ADD_LIBRARY_WITH_SOABI AND ${prefix}_SOABI)\n          get_property (suffix TARGET ${name} PROPERTY SUFFIX)\n          if (NOT suffix)\n            set (suffix \"${CMAKE_SHARED_MODULE_SUFFIX}\")\n          endif()\n          set_property (TARGET ${name} PROPERTY SUFFIX \".${${prefix}_SOABI}${suffix}\")\n        endif()\n      else()\n        if (PYTHON_ADD_LIBRARY_WITH_SOABI)\n          message (AUTHOR_WARNING \"Find${prefix}: Option `WITH_SOABI` is only supported for `MODULE` library type.\")\n        endif()\n        target_link_libraries (${name} PRIVATE ${prefix}::Python)\n      endif()\n    endfunction()\n  endif()\n\n  if (\"NumPy\" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND\n      AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module)\n    add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED)\n    set_property (TARGET ${_PYTHON_PREFIX}::NumPy\n                  PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS}\")\n    target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module)\n  endif()\nendif()\n\n# final clean-up\n\n# Restore CMAKE_FIND_APPBUNDLE\nif (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)\n  set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE})\n  unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE)\nelse()\n  unset (CMAKE_FIND_APPBUNDLE)\nendif()\n# Restore CMAKE_FIND_FRAMEWORK\nif (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)\n  set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK})\n  unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)\nelse()\n  unset (CMAKE_FIND_FRAMEWORK)\nendif()\n\ncmake_policy(POP)\n"
  },
  {
    "path": "scenario/cmake/FindPython3.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindPython3\n-----------\n\n.. versionadded:: 3.12\n\nFind Python 3 interpreter, compiler and development environment (include\ndirectories and libraries).\n\n.. versionadded:: 3.19\n  When a version is requested, it can be specified as a simple value or as a\n  range. For a detailed description of version range usage and capabilities,\n  refer to the :command:`find_package` command.\n\nThe following components are supported:\n\n* ``Interpreter``: search for Python 3 interpreter\n* ``Compiler``: search for Python 3 compiler. Only offered by IronPython.\n* ``Development``: search for development artifacts (include directories and\n  libraries).\n\n  .. versionadded:: 3.18\n    This component includes two sub-components which can be specified\n    independently:\n\n    * ``Development.Module``: search for artifacts for Python 3 module\n      developments.\n    * ``Development.Embed``: search for artifacts for Python 3 embedding\n      developments.\n\n* ``NumPy``: search for NumPy include directories.\n\n.. versionadded:: 3.14\n  Added the ``NumPy`` component.\n\nIf no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.\n\nIf component ``Development`` is specified, it implies sub-components\n``Development.Module`` and ``Development.Embed``.\n\nTo ensure consistent versions between components ``Interpreter``, ``Compiler``,\n``Development`` (or one of its sub-components) and ``NumPy``, specify all\ncomponents at the same time::\n\n  find_package (Python3 COMPONENTS Interpreter Development)\n\nThis module looks only for version 3 of Python. This module can be used\nconcurrently with :module:`FindPython2` module to use both Python versions.\n\nThe :module:`FindPython` module can be used if Python version does not matter\nfor you.\n\n.. note::\n\n  If components ``Interpreter`` and ``Development`` (or one of its\n  sub-components) are both specified, this module search only for interpreter\n  with same platform architecture as the one defined by ``CMake``\n  configuration. This constraint does not apply if only ``Interpreter``\n  component is specified.\n\nImported Targets\n^^^^^^^^^^^^^^^^\n\nThis module defines the following :ref:`Imported Targets <Imported Targets>`:\n\n.. versionchanged:: 3.14\n  :ref:`Imported Targets <Imported Targets>` are only created when\n  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.\n\n``Python3::Interpreter``\n  Python 3 interpreter. Target defined if component ``Interpreter`` is found.\n``Python3::Compiler``\n  Python 3 compiler. Target defined if component ``Compiler`` is found.\n\n``Python3::Module``\n  .. versionadded:: 3.15\n\n  Python 3 library for Python module. Target defined if component\n  ``Development.Module`` is found.\n\n``Python3::Python``\n  Python 3 library for Python embedding. Target defined if component\n  ``Development.Embed`` is found.\n\n``Python3::NumPy``\n  .. versionadded:: 3.14\n\n  NumPy library for Python 3. Target defined if component ``NumPy`` is found.\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\nThis module will set the following variables in your project\n(see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):\n\n``Python3_FOUND``\n  System has the Python 3 requested components.\n``Python3_Interpreter_FOUND``\n  System has the Python 3 interpreter.\n``Python3_EXECUTABLE``\n  Path to the Python 3 interpreter.\n``Python3_INTERPRETER_ID``\n  A short string unique to the interpreter. Possible values include:\n    * Python\n    * ActivePython\n    * Anaconda\n    * Canopy\n    * IronPython\n    * PyPy\n``Python3_STDLIB``\n  Standard platform independent installation directory.\n\n  Information returned by\n  ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``\n  or else ``sysconfig.get_path('stdlib')``.\n``Python3_STDARCH``\n  Standard platform dependent installation directory.\n\n  Information returned by\n  ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``\n  or else ``sysconfig.get_path('platstdlib')``.\n``Python3_SITELIB``\n  Third-party platform independent installation directory.\n\n  Information returned by\n  ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``\n  or else ``sysconfig.get_path('purelib')``.\n``Python3_SITEARCH``\n  Third-party platform dependent installation directory.\n\n  Information returned by\n  ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``\n  or else ``sysconfig.get_path('platlib')``.\n\n``Python3_SOABI``\n  .. versionadded:: 3.17\n\n  Extension suffix for modules.\n\n  Information returned by\n  ``distutils.sysconfig.get_config_var('SOABI')`` or computed from\n  ``distutils.sysconfig.get_config_var('EXT_SUFFIX')`` or\n  ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is\n  not available, ``sysconfig.get_config_var('SOABI')`` or\n  ``sysconfig.get_config_var('EXT_SUFFIX')`` are used.\n\n``Python3_Compiler_FOUND``\n  System has the Python 3 compiler.\n``Python3_COMPILER``\n  Path to the Python 3 compiler. Only offered by IronPython.\n``Python3_COMPILER_ID``\n  A short string unique to the compiler. Possible values include:\n    * IronPython\n\n``Python3_DOTNET_LAUNCHER``\n  .. versionadded:: 3.18\n\n  The ``.Net`` interpreter. Only used by ``IronPython`` implementation.\n\n``Python3_Development_FOUND``\n\n  System has the Python 3 development artifacts.\n\n``Python3_Development.Module_FOUND``\n  .. versionadded:: 3.18\n\n  System has the Python 3 development artifacts for Python module.\n\n``Python3_Development.Embed_FOUND``\n  .. versionadded:: 3.18\n\n  System has the Python 3 development artifacts for Python embedding.\n\n``Python3_INCLUDE_DIRS``\n\n  The Python 3 include directories.\n\n``Python3_LINK_OPTIONS``\n  .. versionadded:: 3.19\n\n  The Python 3 link options. Some configurations require specific link options\n  for a correct build and execution.\n\n``Python3_LIBRARIES``\n  The Python 3 libraries.\n``Python3_LIBRARY_DIRS``\n  The Python 3 library directories.\n``Python3_RUNTIME_LIBRARY_DIRS``\n  The Python 3 runtime library directories.\n``Python3_VERSION``\n  Python 3 version.\n``Python3_VERSION_MAJOR``\n  Python 3 major version.\n``Python3_VERSION_MINOR``\n  Python 3 minor version.\n``Python3_VERSION_PATCH``\n  Python 3 patch version.\n\n``Python3_PyPy_VERSION``\n  .. versionadded:: 3.18\n\n  Python 3 PyPy version.\n\n``Python3_NumPy_FOUND``\n  .. versionadded:: 3.14\n\n  System has the NumPy.\n\n``Python3_NumPy_INCLUDE_DIRS``\n  .. versionadded:: 3.14\n\n  The NumPy include directories.\n\n``Python3_NumPy_VERSION``\n  .. versionadded:: 3.14\n\n  The NumPy version.\n\nHints\n^^^^^\n\n``Python3_ROOT_DIR``\n  Define the root directory of a Python 3 installation.\n\n``Python3_USE_STATIC_LIBS``\n  * If not defined, search for shared libraries and static libraries in that\n    order.\n  * If set to TRUE, search **only** for static libraries.\n  * If set to FALSE, search **only** for shared libraries.\n\n``Python3_FIND_ABI``\n  .. versionadded:: 3.16\n\n  This variable defines which ABIs, as defined in\n  `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.\n\n  .. note::\n\n    If ``Python3_FIND_ABI`` is not defined, any ABI will be searched.\n\n  The ``Python3_FIND_ABI`` variable is a 3-tuple specifying, in that order,\n  ``pydebug`` (``d``), ``pymalloc`` (``m``) and ``unicode`` (``u``) flags.\n  Each element can be set to one of the following:\n\n  * ``ON``: Corresponding flag is selected.\n  * ``OFF``: Corresponding flag is not selected.\n  * ``ANY``: The two possibilities (``ON`` and ``OFF``) will be searched.\n\n  From this 3-tuple, various ABIs will be searched starting from the most\n  specialized to the most general. Moreover, ``debug`` versions will be\n  searched **after** ``non-debug`` ones.\n\n  For example, if we have::\n\n    set (Python3_FIND_ABI \"ON\" \"ANY\" \"ANY\")\n\n  The following flags combinations will be appended, in that order, to the\n  artifact names: ``dmu``, ``dm``, ``du``, and ``d``.\n\n  And to search any possible ABIs::\n\n    set (Python3_FIND_ABI \"ANY\" \"ANY\" \"ANY\")\n\n  The following combinations, in that order, will be used: ``mu``, ``m``,\n  ``u``, ``<empty>``, ``dmu``, ``dm``, ``du`` and ``d``.\n\n  .. note::\n\n    This hint is useful only on ``POSIX`` systems. So, on ``Windows`` systems,\n    when ``Python3_FIND_ABI`` is defined, ``Python`` distributions from\n    `python.org <https://www.python.org/>`_ will be found only if value for\n    each flag is ``OFF`` or ``ANY``.\n\n``Python3_FIND_STRATEGY``\n  .. versionadded:: 3.15\n\n  This variable defines how lookup will be done.\n  The ``Python3_FIND_STRATEGY`` variable can be set to one of the following:\n\n  * ``VERSION``: Try to find the most recent version in all specified\n    locations.\n    This is the default if policy :policy:`CMP0094` is undefined or set to\n    ``OLD``.\n  * ``LOCATION``: Stops lookup as soon as a version satisfying version\n    constraints is founded.\n    This is the default if policy :policy:`CMP0094` is set to ``NEW``.\n\n``Python3_FIND_REGISTRY``\n  .. versionadded:: 3.13\n\n  On Windows the ``Python3_FIND_REGISTRY`` variable determine the order\n  of preference between registry and environment variables.\n  The ``Python3_FIND_REGISTRY`` variable can be set to one of the following:\n\n  * ``FIRST``: Try to use registry before environment variables.\n    This is the default.\n  * ``LAST``: Try to use registry after environment variables.\n  * ``NEVER``: Never try to use registry.\n\n``Python3_FIND_FRAMEWORK``\n  .. versionadded:: 3.15\n\n  On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of\n  preference between Apple-style and unix-style package components.\n  This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`\n  variable.\n\n  .. note::\n\n    Value ``ONLY`` is not supported so ``FIRST`` will be used instead.\n\n  If ``Python3_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`\n  variable will be used, if any.\n\n``Python3_FIND_VIRTUALENV``\n  .. versionadded:: 3.15\n\n  This variable defines the handling of virtual environments managed by\n  ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment\n  is active (i.e. the ``activate`` script has been evaluated). In this case, it\n  takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``\n  variables.  The ``Python3_FIND_VIRTUALENV`` variable can be set to one of the\n  following:\n\n  * ``FIRST``: The virtual environment is used before any other standard\n    paths to look-up for the interpreter. This is the default.\n  * ``ONLY``: Only the virtual environment is used to look-up for the\n    interpreter.\n  * ``STANDARD``: The virtual environment is not used to look-up for the\n    interpreter but environment variable ``PATH`` is always considered.\n    In this case, variable ``Python3_FIND_REGISTRY`` (Windows) or\n    ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or\n    ``NEVER`` to select preferably the interpreter from the virtual\n    environment.\n\n  .. versionadded:: 3.17\n    Added support for ``conda`` environments.\n\n  .. note::\n\n    If the component ``Development`` is requested, it is **strongly**\n    recommended to also include the component ``Interpreter`` to get expected\n    result.\n\n``Python3_FIND_IMPLEMENTATIONS``\n  .. versionadded:: 3.18\n\n  This variable defines, in an ordered list, the different implementations\n  which will be searched. The ``Python3_FIND_IMPLEMENTATIONS`` variable can\n  hold the following values:\n\n  * ``CPython``: this is the standard implementation. Various products, like\n    ``Anaconda`` or ``ActivePython``, rely on this implementation.\n  * ``IronPython``: This implementation use the ``CSharp`` language for\n    ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``).\n    See `IronPython <http://ironpython.net>`_.\n  * ``PyPy``: This implementation use ``RPython`` language and\n    ``RPython translation toolchain`` to produce the python interpreter.\n    See `PyPy <https://www.pypy.org>`_.\n\n  The default value is:\n\n  * Windows platform: ``CPython``, ``IronPython``\n  * Other platforms: ``CPython``\n\n  .. note::\n\n    This hint has the lowest priority of all hints, so even if, for example,\n    you specify ``IronPython`` first and ``CPython`` in second, a python\n    product based on ``CPython`` can be selected because, for example with\n    ``Python3_FIND_STRATEGY=LOCATION``, each location will be search first for\n    ``IronPython`` and second for ``CPython``.\n\n  .. note::\n\n    When ``IronPython`` is specified, on platforms other than ``Windows``, the\n    ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available\n    through the ``PATH`` variable.\n\n``Python3_FIND_UNVERSIONED_NAMES``\n  .. versionadded:: 3.20\n\n  This variable defines how the generic names will be searched. Currently, it\n  only applies to the generic names of the interpreter, namely, ``python3`` and\n  ``python``.\n  The ``Python3_FIND_UNVERSIONED_NAMES`` variable can be set to one of the\n  following values:\n\n  * ``FIRST``: The generic names are searched before the more specialized ones\n    (such as ``python3.5`` for example).\n  * ``LAST``: The generic names are searched after the more specialized ones.\n    This is the default.\n  * ``NEVER``: The generic name are not searched at all.\n\nArtifacts Specification\n^^^^^^^^^^^^^^^^^^^^^^^\n\n.. versionadded:: 3.16\n\nTo solve special cases, it is possible to specify directly the artifacts by\nsetting the following variables:\n\n``Python3_EXECUTABLE``\n  The path to the interpreter.\n\n``Python3_COMPILER``\n  The path to the compiler.\n\n``Python3_DOTNET_LAUNCHER``\n  .. versionadded:: 3.18\n\n  The ``.Net`` interpreter. Only used by ``IronPython`` implementation.\n\n``Python3_LIBRARY``\n  The path to the library. It will be used to compute the\n  variables ``Python3_LIBRARIES``, ``Python3_LIBRARY_DIRS`` and\n  ``Python3_RUNTIME_LIBRARY_DIRS``.\n\n``Python3_INCLUDE_DIR``\n  The path to the directory of the ``Python`` headers. It will be used to\n  compute the variable ``Python3_INCLUDE_DIRS``.\n\n``Python3_NumPy_INCLUDE_DIR``\n  The path to the directory of the ``NumPy`` headers. It will be used to\n  compute the variable ``Python3_NumPy_INCLUDE_DIRS``.\n\n.. note::\n\n  All paths must be absolute. Any artifact specified with a relative path\n  will be ignored.\n\n.. note::\n\n  When an artifact is specified, all ``HINTS`` will be ignored and no search\n  will be performed for this artifact.\n\n  If more than one artifact is specified, it is the user's responsibility to\n  ensure the consistency of the various artifacts.\n\nBy default, this module supports multiple calls in different directories of a\nproject with different version/component requirements while providing correct\nand consistent results for each call. To support this behavior, ``CMake`` cache\nis not used in the traditional way which can be problematic for interactive\nspecification. So, to enable also interactive specification, module behavior\ncan be controlled with the following variable:\n\n``Python3_ARTIFACTS_INTERACTIVE``\n  .. versionadded:: 3.18\n\n  Selects the behavior of the module. This is a boolean variable:\n\n  * If set to ``TRUE``: Create CMake cache entries for the above artifact\n    specification variables so that users can edit them interactively.\n    This disables support for multiple version/component requirements.\n  * If set to ``FALSE`` or undefined: Enable multiple version/component\n    requirements.\n\nCommands\n^^^^^^^^\n\nThis module defines the command ``Python3_add_library`` (when\n:prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as\n:command:`add_library` and adds a dependency to target ``Python3::Python`` or,\nwhen library type is ``MODULE``, to target ``Python3::Module`` and takes care\nof Python module naming rules::\n\n  Python3_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]\n                       <source1> [<source2> ...])\n\nIf the library type is not specified, ``MODULE`` is assumed.\n\n.. versionadded:: 3.17\n  For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the\n  module suffix will include the ``Python3_SOABI`` value, if any.\n#]=======================================================================]\n\n\nset (_PYTHON_PREFIX Python3)\n\nset (_Python3_REQUIRED_VERSION_MAJOR 3)\n\ninclude (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)\n\nif (COMMAND __Python3_add_library)\n  macro (Python3_add_library)\n    __Python3_add_library (Python3 ${ARGV})\n  endmacro()\nendif()\n\nunset (_PYTHON_PREFIX)\n"
  },
  {
    "path": "scenario/cmake/FindSphinx.cmake",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Look for an executable called sphinx-build\nfind_program(SPHINX_EXECUTABLE\n             NAMES sphinx-build\n             DOC \"Path to sphinx-build executable\")\n\ninclude(FindPackageHandleStandardArgs)\n\n# Handle standard arguments to find_package like REQUIRED and QUIET\nfind_package_handle_standard_args(Sphinx\n                                  \"Failed to find sphinx-build executable\"\n                                  SPHINX_EXECUTABLE)\n"
  },
  {
    "path": "scenario/cmake/FindSphinxApidoc.cmake",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Look for an executable called sphinx-apidoc\nfind_program(SPHINX_APIDOC_EXECUTABLE\n             NAMES sphinx-apidoc\n             DOC \"Path to sphinx-apidoc executable\")\n\ninclude(FindPackageHandleStandardArgs)\n\n# Handle standard arguments to find_package like REQUIRED and QUIET\nfind_package_handle_standard_args(SphinxApidoc\n                                  \"Failed to find sphinx-apidoc executable\"\n                                  SPHINX_APIDOC_EXECUTABLE)\n"
  },
  {
    "path": "scenario/cmake/FindSphinxMultiVersion.cmake",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# Look for an executable called sphinx-multiversion\nfind_program(SPHINX_MULTIVERSION_EXECUTABLE\n             NAMES sphinx-multiversion\n             DOC \"Path to sphinx-multiversion executable\")\n\ninclude(FindPackageHandleStandardArgs)\n\n# Handle standard arguments to find_package like REQUIRED and QUIET\nfind_package_handle_standard_args(SphinxMultiVersion\n                                  \"Failed to find sphinx-multiversion executable\"\n                                  SPHINX_MULTIVERSION_EXECUTABLE)\n"
  },
  {
    "path": "scenario/cmake/ImportTargetsCitadel.cmake",
    "content": "include(AliasImportedTarget)\n\n# https://ignitionrobotics.org/docs/citadel/install#citadel-libraries\n\nalias_imported_target(\n    PACKAGE_ORIG sdformat9\n    PACKAGE_DEST sdformat\n    TARGETS_ORIG sdformat9\n    TARGETS_DEST sdformat\n    NAMESPACE_ORIG sdformat9\n    NAMESPACE_DEST sdformat\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo3\n    PACKAGE_DEST ignition-gazebo\n    TARGETS_ORIG ignition-gazebo3 core\n    TARGETS_DEST ignition-gazebo  core\n    NAMESPACE_ORIG ignition-gazebo3\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-common3\n    PACKAGE_DEST ignition-common\n    TARGETS_ORIG ignition-common3\n    TARGETS_DEST ignition-common\n    NAMESPACE_ORIG ignition-common3\n    NAMESPACE_DEST ignition-common\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-sensors3-all\n    PACKAGE_DEST ignition-sensors-all\n    TARGETS_ORIG ignition-sensors3-all\n    TARGETS_DEST ignition-sensors-all\n    NAMESPACE_ORIG ignition-sensors3\n    NAMESPACE_DEST ignition-sensors\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-rendering3\n    PACKAGE_DEST ignition-rendering\n    TARGETS_ORIG ignition-rendering3\n    TARGETS_DEST ignition-rendering\n    NAMESPACE_ORIG ignition-rendering3\n    NAMESPACE_DEST ignition-rendering\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo3-rendering\n    PACKAGE_DEST ignition-gazebo-rendering\n    TARGETS_ORIG ignition-gazebo3-rendering\n    TARGETS_DEST ignition-gazebo-rendering\n    NAMESPACE_ORIG ignition-gazebo3\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-physics2\n    PACKAGE_DEST ignition-physics\n    TARGETS_ORIG ignition-physics2\n    TARGETS_DEST ignition-physics\n    NAMESPACE_ORIG ignition-physics2\n    NAMESPACE_DEST ignition-physics\n    REQUIRED TRUE\n    )\n"
  },
  {
    "path": "scenario/cmake/ImportTargetsDome.cmake",
    "content": "include(AliasImportedTarget)\n\n# https://ignitionrobotics.org/docs/dome/install#dome-libraries\n\nalias_imported_target(\n    PACKAGE_ORIG sdformat10\n    PACKAGE_DEST sdformat\n    TARGETS_ORIG sdformat10\n    TARGETS_DEST sdformat\n    NAMESPACE_ORIG sdformat10\n    NAMESPACE_DEST sdformat\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo4\n    PACKAGE_DEST ignition-gazebo\n    TARGETS_ORIG ignition-gazebo4 core\n    TARGETS_DEST ignition-gazebo  core\n    NAMESPACE_ORIG ignition-gazebo4\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-common3\n    PACKAGE_DEST ignition-common\n    TARGETS_ORIG ignition-common3\n    TARGETS_DEST ignition-common\n    NAMESPACE_ORIG ignition-common3\n    NAMESPACE_DEST ignition-common\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-sensors4-all\n    PACKAGE_DEST ignition-sensors-all\n    TARGETS_ORIG ignition-sensors4-all\n    TARGETS_DEST ignition-sensors-all\n    NAMESPACE_ORIG ignition-sensors4\n    NAMESPACE_DEST ignition-sensors\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-rendering4\n    PACKAGE_DEST ignition-rendering\n    TARGETS_ORIG ignition-rendering4\n    TARGETS_DEST ignition-rendering\n    NAMESPACE_ORIG ignition-rendering4\n    NAMESPACE_DEST ignition-rendering\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo4-rendering\n    PACKAGE_DEST ignition-gazebo-rendering\n    TARGETS_ORIG ignition-gazebo4-rendering\n    TARGETS_DEST ignition-gazebo-rendering\n    NAMESPACE_ORIG ignition-gazebo4\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-physics3\n    PACKAGE_DEST ignition-physics\n    TARGETS_ORIG ignition-physics3\n    TARGETS_DEST ignition-physics\n    NAMESPACE_ORIG ignition-physics3\n    NAMESPACE_DEST ignition-physics\n    REQUIRED TRUE\n    )\n\n    alias_imported_target(\n    PACKAGE_ORIG ignition-fuel_tools5\n    PACKAGE_DEST ignition-fuel_tools\n    TARGETS_ORIG ignition-fuel_tools5\n    TARGETS_DEST ignition-fuel_tools\n    NAMESPACE_ORIG ignition-fuel_tools5\n    NAMESPACE_DEST ignition-fuel_tools\n    REQUIRED TRUE\n    )\n"
  },
  {
    "path": "scenario/cmake/ImportTargetsEdifice.cmake",
    "content": "include(AliasImportedTarget)\n\n# https://ignitionrobotics.org/docs/edifice/install#edifice-libraries\n\nalias_imported_target(\n    PACKAGE_ORIG sdformat11\n    PACKAGE_DEST sdformat\n    TARGETS_ORIG sdformat11\n    TARGETS_DEST sdformat\n    NAMESPACE_ORIG sdformat11\n    NAMESPACE_DEST sdformat\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo5\n    PACKAGE_DEST ignition-gazebo\n    TARGETS_ORIG ignition-gazebo5 core\n    TARGETS_DEST ignition-gazebo  core\n    NAMESPACE_ORIG ignition-gazebo5\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-common4\n    PACKAGE_DEST ignition-common\n    TARGETS_ORIG ignition-common4\n    TARGETS_DEST ignition-common\n    NAMESPACE_ORIG ignition-common4\n    NAMESPACE_DEST ignition-common\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-sensors5-all\n    PACKAGE_DEST ignition-sensors-all\n    TARGETS_ORIG ignition-sensors5-all\n    TARGETS_DEST ignition-sensors-all\n    NAMESPACE_ORIG ignition-sensors5\n    NAMESPACE_DEST ignition-sensors\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-rendering5\n    PACKAGE_DEST ignition-rendering\n    TARGETS_ORIG ignition-rendering5\n    TARGETS_DEST ignition-rendering\n    NAMESPACE_ORIG ignition-rendering5\n    NAMESPACE_DEST ignition-rendering\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo5-rendering\n    PACKAGE_DEST ignition-gazebo-rendering\n    TARGETS_ORIG ignition-gazebo5-rendering\n    TARGETS_DEST ignition-gazebo-rendering\n    NAMESPACE_ORIG ignition-gazebo5\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-physics4\n    PACKAGE_DEST ignition-physics\n    TARGETS_ORIG ignition-physics4\n    TARGETS_DEST ignition-physics\n    NAMESPACE_ORIG ignition-physics4\n    NAMESPACE_DEST ignition-physics\n    REQUIRED TRUE\n    )\n"
  },
  {
    "path": "scenario/cmake/ImportTargetsFortress.cmake",
    "content": "include(AliasImportedTarget)\n\n# https://ignitionrobotics.org/docs/fortress/install#fortress-libraries\n\nalias_imported_target(\n    PACKAGE_ORIG sdformat12\n    PACKAGE_DEST sdformat\n    TARGETS_ORIG sdformat12\n    TARGETS_DEST sdformat\n    NAMESPACE_ORIG sdformat12\n    NAMESPACE_DEST sdformat\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo6\n    PACKAGE_DEST ignition-gazebo\n    TARGETS_ORIG ignition-gazebo6 core\n    TARGETS_DEST ignition-gazebo  core\n    NAMESPACE_ORIG ignition-gazebo6\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-common4\n    PACKAGE_DEST ignition-common\n    TARGETS_ORIG ignition-common4\n    TARGETS_DEST ignition-common\n    NAMESPACE_ORIG ignition-common4\n    NAMESPACE_DEST ignition-common\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-sensors6-all\n    PACKAGE_DEST ignition-sensors-all\n    TARGETS_ORIG ignition-sensors6-all\n    TARGETS_DEST ignition-sensors-all\n    NAMESPACE_ORIG ignition-sensors6\n    NAMESPACE_DEST ignition-sensors\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-rendering6\n    PACKAGE_DEST ignition-rendering\n    TARGETS_ORIG ignition-rendering6\n    TARGETS_DEST ignition-rendering\n    NAMESPACE_ORIG ignition-rendering6\n    NAMESPACE_DEST ignition-rendering\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-gazebo6-rendering\n    PACKAGE_DEST ignition-gazebo-rendering\n    TARGETS_ORIG ignition-gazebo6-rendering\n    TARGETS_DEST ignition-gazebo-rendering\n    NAMESPACE_ORIG ignition-gazebo6\n    NAMESPACE_DEST ignition-gazebo\n    REQUIRED TRUE\n    )\n\nalias_imported_target(\n    PACKAGE_ORIG ignition-physics5\n    PACKAGE_DEST ignition-physics\n    TARGETS_ORIG ignition-physics5\n    TARGETS_DEST ignition-physics\n    NAMESPACE_ORIG ignition-physics5\n    NAMESPACE_DEST ignition-physics\n    REQUIRED TRUE\n    )\n"
  },
  {
    "path": "scenario/deps/CMakeLists.txt",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\ninclude(FetchContent)\n\n# ===\n# YCM\n# ===\n\nfind_package(YCM QUIET)\n\noption(SCENARIO_USE_SYSTEM_YCM\n    \"Use system-installed YCM, rather than a private copy\"\n    ${YCM_FOUND})\n\nif(SCENARIO_USE_SYSTEM_YCM AND NOT ${YCM_FOUND})\n    message(FATAL_ERROR \"Failed to find system YCM\")\nendif()\n\nif(NOT ${SCENARIO_USE_SYSTEM_YCM})\n\n    FetchContent_Declare(\n        ycm\n        GIT_REPOSITORY https://github.com/robotology/ycm.git)\n\n    FetchContent_GetProperties(ycm)\n\n    if(NOT ycm_POPULATED)\n        FetchContent_Populate(ycm)\n\n        add_subdirectory(${ycm_SOURCE_DIR}\n                         ${ycm_BINARY_DIR}\n                         EXCLUDE_FROM_ALL)\n    endif()\n\n    set(CMAKE_MODULE_PATH\n        \"${CMAKE_MODULE_PATH};${ycm_SOURCE_DIR}/modules\" PARENT_SCOPE)\nelse()\n    set(CMAKE_MODULE_PATH\n        \"${CMAKE_MODULE_PATH};${YCM_MODULE_PATH}\" PARENT_SCOPE)\nendif()\n\n# ====================\n# TINY-PROCESS-LIBRARY\n# ====================\n\nfind_package(tiny-process-library QUIET)\n\noption(SCENARIO_USE_SYSTEM_TPL\n    \"Use system-installed tiny-process-library, rather than a private copy\"\n    ${tiny-process-library_FOUND})\n\nif(SCENARIO_USE_SYSTEM_TPL AND NOT ${tiny-process-library_FOUND})\n    message(FATAL_ERROR \"Failed to find system tiny-process-library\")\nendif()\n\nif(NOT ${SCENARIO_USE_SYSTEM_TPL})\n\n    FetchContent_Declare(\n        tinyprocesslibrary\n        GIT_REPOSITORY https://gitlab.com/eidheim/tiny-process-library.git)\n\n    FetchContent_GetProperties(tinyprocesslibrary)\n\n    if(NOT tinyprocesslibrary_POPULATED)\n        FetchContent_Populate(tinyprocesslibrary)\n\n        # We don't want to install this library in the system, we instead\n        # compile it as an OBJECT library and embed in either the shared or\n        # static libraries that need it.\n\n        if(WIN32)\n            add_library(tiny-process-library OBJECT\n                ${tinyprocesslibrary_SOURCE_DIR}/process.cpp\n                ${tinyprocesslibrary_SOURCE_DIR}/process_win.cpp)\n            #If compiled using MSYS2, use sh to run commands\n            if(MSYS)\n                target_compile_definitions(tiny-process-library\n                    PUBLIC MSYS_PROCESS_USE_SH)\n            endif()\n        else()\n            add_library(tiny-process-library OBJECT\n                ${tinyprocesslibrary_SOURCE_DIR}/process.cpp\n                ${tinyprocesslibrary_SOURCE_DIR}/process_unix.cpp)\n        endif()\n\n        if(MSVC)\n            target_compile_definitions(tiny-process-library\n                PRIVATE /D_CRT_SECURE_NO_WARNINGS)\n        endif()\n\n        find_package(Threads REQUIRED)\n\n        target_link_libraries(tiny-process-library PRIVATE\n            ${CMAKE_THREAD_LIBS_INIT})\n\n        target_include_directories(tiny-process-library PUBLIC\n            $<BUILD_INTERFACE:${tinyprocesslibrary_SOURCE_DIR}>)\n\n        add_library(tiny-process-library::tiny-process-library ALIAS tiny-process-library)\n\n    endif()\nendif()\n\n# =====\n# CLARA\n# =====\n\nadd_library(Clara INTERFACE)\ntarget_sources(Clara INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/clara/clara.hpp)\ntarget_include_directories(Clara INTERFACE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/clara>)\n"
  },
  {
    "path": "scenario/deps/clara/clara.hpp",
    "content": "// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n// See https://github.com/philsquared/Clara for more details\n\n// Clara v1.1.5\n\n#ifndef CLARA_HPP_INCLUDED\n#define CLARA_HPP_INCLUDED\n\n#ifndef CLARA_CONFIG_CONSOLE_WIDTH\n#define CLARA_CONFIG_CONSOLE_WIDTH 80\n#endif\n\n#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH\n#endif\n\n#ifndef CLARA_CONFIG_OPTIONAL_TYPE\n#ifdef __has_include\n#if __has_include(<optional>) && __cplusplus >= 201703L\n#include <optional>\n#define CLARA_CONFIG_OPTIONAL_TYPE std::optional\n#endif\n#endif\n#endif\n\n\n// ----------- #included from clara_textflow.hpp -----------\n\n// TextFlowCpp\n//\n// A single-header library for wrapping and laying out basic text, by Phil Nash\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n// This project is hosted at https://github.com/philsquared/textflowcpp\n\n#ifndef CLARA_TEXTFLOW_HPP_INCLUDED\n#define CLARA_TEXTFLOW_HPP_INCLUDED\n\n#include <cassert>\n#include <ostream>\n#include <sstream>\n#include <vector>\n\n#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80\n#endif\n\n\nnamespace clara { namespace TextFlow {\n\n    inline auto isWhitespace( char c ) -> bool {\n        static std::string chars = \" \\t\\n\\r\";\n        return chars.find( c ) != std::string::npos;\n    }\n    inline auto isBreakableBefore( char c ) -> bool {\n        static std::string chars = \"[({<|\";\n        return chars.find( c ) != std::string::npos;\n    }\n    inline auto isBreakableAfter( char c ) -> bool {\n        static std::string chars = \"])}>.,:;*+-=&/\\\\\";\n        return chars.find( c ) != std::string::npos;\n    }\n\n    class Columns;\n\n    class Column {\n        std::vector<std::string> m_strings;\n        size_t m_width = CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;\n        size_t m_indent = 0;\n        size_t m_initialIndent = std::string::npos;\n\n    public:\n        class iterator {\n            friend Column;\n\n            Column const& m_column;\n            size_t m_stringIndex = 0;\n            size_t m_pos = 0;\n\n            size_t m_len = 0;\n            size_t m_end = 0;\n            bool m_suffix = false;\n\n            iterator( Column const& column, size_t stringIndex )\n            :   m_column( column ),\n                m_stringIndex( stringIndex )\n            {}\n\n            auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }\n\n            auto isBoundary( size_t at ) const -> bool {\n                assert( at > 0 );\n                assert( at <= line().size() );\n\n                return at == line().size() ||\n                       ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||\n                       isBreakableBefore( line()[at] ) ||\n                       isBreakableAfter( line()[at-1] );\n            }\n\n            void calcLength() {\n                assert( m_stringIndex < m_column.m_strings.size() );\n\n                m_suffix = false;\n                auto width = m_column.m_width-indent();\n                m_end = m_pos;\n                while( m_end < line().size() && line()[m_end] != '\\n' )\n                    ++m_end;\n\n                if( m_end < m_pos + width ) {\n                    m_len = m_end - m_pos;\n                }\n                else {\n                    size_t len = width;\n                    while (len > 0 && !isBoundary(m_pos + len))\n                        --len;\n                    while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))\n                        --len;\n\n                    if (len > 0) {\n                        m_len = len;\n                    } else {\n                        m_suffix = true;\n                        m_len = width - 1;\n                    }\n                }\n            }\n\n            auto indent() const -> size_t {\n                auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;\n                return initial == std::string::npos ? m_column.m_indent : initial;\n            }\n\n            auto addIndentAndSuffix(std::string const &plain) const -> std::string {\n                return std::string( indent(), ' ' ) + (m_suffix ? plain + \"-\" : plain);\n            }\n\n        public:\n            using difference_type = std::ptrdiff_t;\n            using value_type = std::string;\n            using pointer = value_type*;\n            using reference = value_type&;\n            using iterator_category = std::forward_iterator_tag;\n\n            explicit iterator( Column const& column ) : m_column( column ) {\n                assert( m_column.m_width > m_column.m_indent );\n                assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );\n                calcLength();\n                if( m_len == 0 )\n                    m_stringIndex++; // Empty string\n            }\n\n            auto operator *() const -> std::string {\n                assert( m_stringIndex < m_column.m_strings.size() );\n                assert( m_pos <= m_end );\n                return addIndentAndSuffix(line().substr(m_pos, m_len));\n            }\n\n            auto operator ++() -> iterator& {\n                m_pos += m_len;\n                if( m_pos < line().size() && line()[m_pos] == '\\n' )\n                    m_pos += 1;\n                else\n                    while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )\n                        ++m_pos;\n\n                if( m_pos == line().size() ) {\n                    m_pos = 0;\n                    ++m_stringIndex;\n                }\n                if( m_stringIndex < m_column.m_strings.size() )\n                    calcLength();\n                return *this;\n            }\n            auto operator ++(int) -> iterator {\n                iterator prev( *this );\n                operator++();\n                return prev;\n            }\n\n            auto operator ==( iterator const& other ) const -> bool {\n                return\n                    m_pos == other.m_pos &&\n                    m_stringIndex == other.m_stringIndex &&\n                    &m_column == &other.m_column;\n            }\n            auto operator !=( iterator const& other ) const -> bool {\n                return !operator==( other );\n            }\n        };\n        using const_iterator = iterator;\n\n        explicit Column( std::string const& text ) { m_strings.push_back( text ); }\n\n        auto width( size_t newWidth ) -> Column& {\n            assert( newWidth > 0 );\n            m_width = newWidth;\n            return *this;\n        }\n        auto indent( size_t newIndent ) -> Column& {\n            m_indent = newIndent;\n            return *this;\n        }\n        auto initialIndent( size_t newIndent ) -> Column& {\n            m_initialIndent = newIndent;\n            return *this;\n        }\n\n        auto width() const -> size_t { return m_width; }\n        auto begin() const -> iterator { return iterator( *this ); }\n        auto end() const -> iterator { return { *this, m_strings.size() }; }\n\n        inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {\n            bool first = true;\n            for( auto line : col ) {\n                if( first )\n                    first = false;\n                else\n                    os << \"\\n\";\n                os <<  line;\n            }\n            return os;\n        }\n\n        auto operator + ( Column const& other ) -> Columns;\n\n        auto toString() const -> std::string {\n            std::ostringstream oss;\n            oss << *this;\n            return oss.str();\n        }\n    };\n\n    class Spacer : public Column {\n\n    public:\n        explicit Spacer( size_t spaceWidth ) : Column( \"\" ) {\n            width( spaceWidth );\n        }\n    };\n\n    class Columns {\n        std::vector<Column> m_columns;\n\n    public:\n\n        class iterator {\n            friend Columns;\n            struct EndTag {};\n\n            std::vector<Column> const& m_columns;\n            std::vector<Column::iterator> m_iterators;\n            size_t m_activeIterators;\n\n            iterator( Columns const& columns, EndTag )\n            :   m_columns( columns.m_columns ),\n                m_activeIterators( 0 )\n            {\n                m_iterators.reserve( m_columns.size() );\n\n                for( auto const& col : m_columns )\n                    m_iterators.push_back( col.end() );\n            }\n\n        public:\n            using difference_type = std::ptrdiff_t;\n            using value_type = std::string;\n            using pointer = value_type*;\n            using reference = value_type&;\n            using iterator_category = std::forward_iterator_tag;\n\n            explicit iterator( Columns const& columns )\n            :   m_columns( columns.m_columns ),\n                m_activeIterators( m_columns.size() )\n            {\n                m_iterators.reserve( m_columns.size() );\n\n                for( auto const& col : m_columns )\n                    m_iterators.push_back( col.begin() );\n            }\n\n            auto operator ==( iterator const& other ) const -> bool {\n                return m_iterators == other.m_iterators;\n            }\n            auto operator !=( iterator const& other ) const -> bool {\n                return m_iterators != other.m_iterators;\n            }\n            auto operator *() const -> std::string {\n                std::string row, padding;\n\n                for( size_t i = 0; i < m_columns.size(); ++i ) {\n                    auto width = m_columns[i].width();\n                    if( m_iterators[i] != m_columns[i].end() ) {\n                        std::string col = *m_iterators[i];\n                        row += padding + col;\n                        if( col.size() < width )\n                            padding = std::string( width - col.size(), ' ' );\n                        else\n                            padding = \"\";\n                    }\n                    else {\n                        padding += std::string( width, ' ' );\n                    }\n                }\n                return row;\n            }\n            auto operator ++() -> iterator& {\n                for( size_t i = 0; i < m_columns.size(); ++i ) {\n                    if (m_iterators[i] != m_columns[i].end())\n                        ++m_iterators[i];\n                }\n                return *this;\n            }\n            auto operator ++(int) -> iterator {\n                iterator prev( *this );\n                operator++();\n                return prev;\n            }\n        };\n        using const_iterator = iterator;\n\n        auto begin() const -> iterator { return iterator( *this ); }\n        auto end() const -> iterator { return { *this, iterator::EndTag() }; }\n\n        auto operator += ( Column const& col ) -> Columns& {\n            m_columns.push_back( col );\n            return *this;\n        }\n        auto operator + ( Column const& col ) -> Columns {\n            Columns combined = *this;\n            combined += col;\n            return combined;\n        }\n\n        inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {\n\n            bool first = true;\n            for( auto line : cols ) {\n                if( first )\n                    first = false;\n                else\n                    os << \"\\n\";\n                os << line;\n            }\n            return os;\n        }\n\n        auto toString() const -> std::string {\n            std::ostringstream oss;\n            oss << *this;\n            return oss.str();\n        }\n    };\n\n    inline auto Column::operator + ( Column const& other ) -> Columns {\n        Columns cols;\n        cols += *this;\n        cols += other;\n        return cols;\n    }\n}}\n\n#endif // CLARA_TEXTFLOW_HPP_INCLUDED\n\n// ----------- end of #include from clara_textflow.hpp -----------\n// ........... back in clara.hpp\n\n\n#include <memory>\n#include <set>\n#include <algorithm>\n\n#if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )\n#define CLARA_PLATFORM_WINDOWS\n#endif\n\nnamespace clara {\nnamespace detail {\n\n    // Traits for extracting arg and return type of lambdas (for single argument lambdas)\n    template<typename L>\n    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};\n\n    template<typename ClassT, typename ReturnT, typename... Args>\n    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {\n        static const bool isValid = false;\n    };\n\n    template<typename ClassT, typename ReturnT, typename ArgT>\n    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {\n        static const bool isValid = true;\n        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;\n        using ReturnType = ReturnT;\n    };\n\n    class TokenStream;\n\n    // Transport for raw args (copied from main args, or supplied via init list for testing)\n    class Args {\n        friend TokenStream;\n        std::string m_exeName;\n        std::vector<std::string> m_args;\n\n    public:\n        Args( int argc, char const* const* argv )\n            : m_exeName(argv[0]),\n              m_args(argv + 1, argv + argc) {}\n\n        Args( std::initializer_list<std::string> args )\n        :   m_exeName( *args.begin() ),\n            m_args( args.begin()+1, args.end() )\n        {}\n\n        auto exeName() const -> std::string {\n            return m_exeName;\n        }\n    };\n\n    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string\n    // may encode an option + its argument if the : or = form is used\n    enum class TokenType {\n        Option, Argument\n    };\n    struct Token {\n        TokenType type;\n        std::string token;\n    };\n\n    inline auto isOptPrefix( char c ) -> bool {\n        return c == '-'\n#ifdef CLARA_PLATFORM_WINDOWS\n            || c == '/'\n#endif\n        ;\n    }\n\n    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled\n    class TokenStream {\n        using Iterator = std::vector<std::string>::const_iterator;\n        Iterator it;\n        Iterator itEnd;\n        std::vector<Token> m_tokenBuffer;\n\n        void loadBuffer() {\n            m_tokenBuffer.resize( 0 );\n\n            // Skip any empty strings\n            while( it != itEnd && it->empty() )\n                ++it;\n\n            if( it != itEnd ) {\n                auto const &next = *it;\n                if( isOptPrefix( next[0] ) ) {\n                    auto delimiterPos = next.find_first_of( \" :=\" );\n                    if( delimiterPos != std::string::npos ) {\n                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );\n                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );\n                    } else {\n                        if( next[1] != '-' && next.size() > 2 ) {\n                            std::string opt = \"- \";\n                            for( size_t i = 1; i < next.size(); ++i ) {\n                                opt[1] = next[i];\n                                m_tokenBuffer.push_back( { TokenType::Option, opt } );\n                            }\n                        } else {\n                            m_tokenBuffer.push_back( { TokenType::Option, next } );\n                        }\n                    }\n                } else {\n                    m_tokenBuffer.push_back( { TokenType::Argument, next } );\n                }\n            }\n        }\n\n    public:\n        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}\n\n        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {\n            loadBuffer();\n        }\n\n        explicit operator bool() const {\n            return !m_tokenBuffer.empty() || it != itEnd;\n        }\n\n        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }\n\n        auto operator*() const -> Token {\n            assert( !m_tokenBuffer.empty() );\n            return m_tokenBuffer.front();\n        }\n\n        auto operator->() const -> Token const * {\n            assert( !m_tokenBuffer.empty() );\n            return &m_tokenBuffer.front();\n        }\n\n        auto operator++() -> TokenStream & {\n            if( m_tokenBuffer.size() >= 2 ) {\n                m_tokenBuffer.erase( m_tokenBuffer.begin() );\n            } else {\n                if( it != itEnd )\n                    ++it;\n                loadBuffer();\n            }\n            return *this;\n        }\n    };\n\n\n    class ResultBase {\n    public:\n        enum Type {\n            Ok, LogicError, RuntimeError\n        };\n\n    protected:\n        ResultBase( Type type ) : m_type( type ) {}\n        virtual ~ResultBase() = default;\n\n        virtual void enforceOk() const = 0;\n\n        Type m_type;\n    };\n\n    template<typename T>\n    class ResultValueBase : public ResultBase {\n    public:\n        auto value() const -> T const & {\n            enforceOk();\n            return m_value;\n        }\n\n    protected:\n        ResultValueBase( Type type ) : ResultBase( type ) {}\n\n        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {\n            if( m_type == ResultBase::Ok )\n                new( &m_value ) T( other.m_value );\n        }\n\n        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {\n            new( &m_value ) T( value );\n        }\n\n        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {\n            if( m_type == ResultBase::Ok )\n                m_value.~T();\n            ResultBase::operator=(other);\n            if( m_type == ResultBase::Ok )\n                new( &m_value ) T( other.m_value );\n            return *this;\n        }\n\n        ~ResultValueBase() override {\n            if( m_type == Ok )\n                m_value.~T();\n        }\n\n        union {\n            T m_value;\n        };\n    };\n\n    template<>\n    class ResultValueBase<void> : public ResultBase {\n    protected:\n        using ResultBase::ResultBase;\n    };\n\n    template<typename T = void>\n    class BasicResult : public ResultValueBase<T> {\n    public:\n        template<typename U>\n        explicit BasicResult( BasicResult<U> const &other )\n        :   ResultValueBase<T>( other.type() ),\n            m_errorMessage( other.errorMessage() )\n        {\n            assert( type() != ResultBase::Ok );\n        }\n\n        template<typename U>\n        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }\n        static auto ok() -> BasicResult { return { ResultBase::Ok }; }\n        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }\n        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }\n\n        explicit operator bool() const { return m_type == ResultBase::Ok; }\n        auto type() const -> ResultBase::Type { return m_type; }\n        auto errorMessage() const -> std::string { return m_errorMessage; }\n\n    protected:\n        void enforceOk() const override {\n\n            // Errors shouldn't reach this point, but if they do\n            // the actual error message will be in m_errorMessage\n            assert( m_type != ResultBase::LogicError );\n            assert( m_type != ResultBase::RuntimeError );\n            if( m_type != ResultBase::Ok )\n                std::abort();\n        }\n\n        std::string m_errorMessage; // Only populated if resultType is an error\n\n        BasicResult( ResultBase::Type type, std::string const &message )\n        :   ResultValueBase<T>(type),\n            m_errorMessage(message)\n        {\n            assert( m_type != ResultBase::Ok );\n        }\n\n        using ResultValueBase<T>::ResultValueBase;\n        using ResultBase::m_type;\n    };\n\n    enum class ParseResultType {\n        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame\n    };\n\n    class ParseState {\n    public:\n\n        ParseState( ParseResultType type, TokenStream const &remainingTokens )\n        : m_type(type),\n          m_remainingTokens( remainingTokens )\n        {}\n\n        auto type() const -> ParseResultType { return m_type; }\n        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }\n\n    private:\n        ParseResultType m_type;\n        TokenStream m_remainingTokens;\n    };\n\n    using Result = BasicResult<void>;\n    using ParserResult = BasicResult<ParseResultType>;\n    using InternalParseResult = BasicResult<ParseState>;\n\n    struct HelpColumns {\n        std::string left;\n        std::string right;\n    };\n\n    template<typename T>\n    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {\n        std::stringstream ss;\n        ss << source;\n        ss >> target;\n        if( ss.fail() )\n            return ParserResult::runtimeError( \"Unable to convert '\" + source + \"' to destination type\" );\n        else\n            return ParserResult::ok( ParseResultType::Matched );\n    }\n    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {\n        target = source;\n        return ParserResult::ok( ParseResultType::Matched );\n    }\n    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {\n        std::string srcLC = source;\n        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );\n        if (srcLC == \"y\" || srcLC == \"1\" || srcLC == \"true\" || srcLC == \"yes\" || srcLC == \"on\")\n            target = true;\n        else if (srcLC == \"n\" || srcLC == \"0\" || srcLC == \"false\" || srcLC == \"no\" || srcLC == \"off\")\n            target = false;\n        else\n            return ParserResult::runtimeError( \"Expected a boolean value but did not recognise: '\" + source + \"'\" );\n        return ParserResult::ok( ParseResultType::Matched );\n    }\n#ifdef CLARA_CONFIG_OPTIONAL_TYPE\n    template<typename T>\n    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {\n        T temp;\n        auto result = convertInto( source, temp );\n        if( result )\n            target = std::move(temp);\n        return result;\n    }\n#endif // CLARA_CONFIG_OPTIONAL_TYPE\n\n    struct NonCopyable {\n        NonCopyable() = default;\n        NonCopyable( NonCopyable const & ) = delete;\n        NonCopyable( NonCopyable && ) = delete;\n        NonCopyable &operator=( NonCopyable const & ) = delete;\n        NonCopyable &operator=( NonCopyable && ) = delete;\n    };\n\n    struct BoundRef : NonCopyable {\n        virtual ~BoundRef() = default;\n        virtual auto isContainer() const -> bool { return false; }\n        virtual auto isFlag() const -> bool { return false; }\n    };\n    struct BoundValueRefBase : BoundRef {\n        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;\n    };\n    struct BoundFlagRefBase : BoundRef {\n        virtual auto setFlag( bool flag ) -> ParserResult = 0;\n        virtual auto isFlag() const -> bool { return true; }\n    };\n\n    template<typename T>\n    struct BoundValueRef : BoundValueRefBase {\n        T &m_ref;\n\n        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            return convertInto( arg, m_ref );\n        }\n    };\n\n    template<typename T>\n    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {\n        std::vector<T> &m_ref;\n\n        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}\n\n        auto isContainer() const -> bool override { return true; }\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            T temp;\n            auto result = convertInto( arg, temp );\n            if( result )\n                m_ref.push_back( temp );\n            return result;\n        }\n    };\n\n    struct BoundFlagRef : BoundFlagRefBase {\n        bool &m_ref;\n\n        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}\n\n        auto setFlag( bool flag ) -> ParserResult override {\n            m_ref = flag;\n            return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    template<typename ReturnType>\n    struct LambdaInvoker {\n        static_assert( std::is_same<ReturnType, ParserResult>::value, \"Lambda must return void or clara::ParserResult\" );\n\n        template<typename L, typename ArgType>\n        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {\n            return lambda( arg );\n        }\n    };\n\n    template<>\n    struct LambdaInvoker<void> {\n        template<typename L, typename ArgType>\n        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {\n            lambda( arg );\n            return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    template<typename ArgType, typename L>\n    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {\n        ArgType temp{};\n        auto result = convertInto( arg, temp );\n        return !result\n           ? result\n           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );\n    }\n\n\n    template<typename L>\n    struct BoundLambda : BoundValueRefBase {\n        L m_lambda;\n\n        static_assert( UnaryLambdaTraits<L>::isValid, \"Supplied lambda must take exactly one argument\" );\n        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );\n        }\n    };\n\n    template<typename L>\n    struct BoundFlagLambda : BoundFlagRefBase {\n        L m_lambda;\n\n        static_assert( UnaryLambdaTraits<L>::isValid, \"Supplied lambda must take exactly one argument\" );\n        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, \"flags must be boolean\" );\n\n        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}\n\n        auto setFlag( bool flag ) -> ParserResult override {\n            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );\n        }\n    };\n\n    enum class Optionality { Optional, Required };\n\n    struct Parser;\n\n    class ParserBase {\n    public:\n        virtual ~ParserBase() = default;\n        virtual auto validate() const -> Result { return Result::ok(); }\n        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;\n        virtual auto cardinality() const -> size_t { return 1; }\n\n        auto parse( Args const &args ) const -> InternalParseResult {\n            return parse( args.exeName(), TokenStream( args ) );\n        }\n    };\n\n    template<typename DerivedT>\n    class ComposableParserImpl : public ParserBase {\n    public:\n        template<typename T>\n        auto operator|( T const &other ) const -> Parser;\n\n\t\ttemplate<typename T>\n        auto operator+( T const &other ) const -> Parser;\n    };\n\n    // Common code and state for Args and Opts\n    template<typename DerivedT>\n    class ParserRefImpl : public ComposableParserImpl<DerivedT> {\n    protected:\n        Optionality m_optionality = Optionality::Optional;\n        std::shared_ptr<BoundRef> m_ref;\n        std::string m_hint;\n        std::string m_description;\n\n        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}\n\n    public:\n        template<typename T>\n        ParserRefImpl( T &ref, std::string const &hint )\n        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),\n            m_hint( hint )\n        {}\n\n        template<typename LambdaT>\n        ParserRefImpl( LambdaT const &ref, std::string const &hint )\n        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),\n            m_hint(hint)\n        {}\n\n        auto operator()( std::string const &description ) -> DerivedT & {\n            m_description = description;\n            return static_cast<DerivedT &>( *this );\n        }\n\n        auto optional() -> DerivedT & {\n            m_optionality = Optionality::Optional;\n            return static_cast<DerivedT &>( *this );\n        };\n\n        auto required() -> DerivedT & {\n            m_optionality = Optionality::Required;\n            return static_cast<DerivedT &>( *this );\n        };\n\n        auto isOptional() const -> bool {\n            return m_optionality == Optionality::Optional;\n        }\n\n        auto cardinality() const -> size_t override {\n            if( m_ref->isContainer() )\n                return 0;\n            else\n                return 1;\n        }\n\n        auto hint() const -> std::string { return m_hint; }\n    };\n\n    class ExeName : public ComposableParserImpl<ExeName> {\n        std::shared_ptr<std::string> m_name;\n        std::shared_ptr<BoundValueRefBase> m_ref;\n\n        template<typename LambdaT>\n        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {\n            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;\n        }\n\n    public:\n        ExeName() : m_name( std::make_shared<std::string>( \"<executable>\" ) ) {}\n\n        explicit ExeName( std::string &ref ) : ExeName() {\n            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );\n        }\n\n        template<typename LambdaT>\n        explicit ExeName( LambdaT const& lambda ) : ExeName() {\n            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );\n        }\n\n        // The exe name is not parsed out of the normal tokens, but is handled specially\n        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {\n            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );\n        }\n\n        auto name() const -> std::string { return *m_name; }\n        auto set( std::string const& newName ) -> ParserResult {\n\n            auto lastSlash = newName.find_last_of( \"\\\\/\" );\n            auto filename = ( lastSlash == std::string::npos )\n                    ? newName\n                    : newName.substr( lastSlash+1 );\n\n            *m_name = filename;\n            if( m_ref )\n                return m_ref->setValue( filename );\n            else\n                return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    class Arg : public ParserRefImpl<Arg> {\n    public:\n        using ParserRefImpl::ParserRefImpl;\n\n        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {\n            auto validationResult = validate();\n            if( !validationResult )\n                return InternalParseResult( validationResult );\n\n            auto remainingTokens = tokens;\n            auto const &token = *remainingTokens;\n            if( token.type != TokenType::Argument )\n                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );\n\n            assert( !m_ref->isFlag() );\n            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );\n\n            auto result = valueRef->setValue( remainingTokens->token );\n            if( !result )\n                return InternalParseResult( result );\n            else\n                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );\n        }\n    };\n\n    inline auto normaliseOpt( std::string const &optName ) -> std::string {\n#ifdef CLARA_PLATFORM_WINDOWS\n        if( optName[0] == '/' )\n            return \"-\" + optName.substr( 1 );\n        else\n#endif\n            return optName;\n    }\n\n    class Opt : public ParserRefImpl<Opt> {\n    protected:\n        std::vector<std::string> m_optNames;\n\n    public:\n        template<typename LambdaT>\n        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}\n\n        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}\n\n        template<typename LambdaT>\n        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}\n\n        template<typename T>\n        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}\n\n        auto operator[]( std::string const &optName ) -> Opt & {\n            m_optNames.push_back( optName );\n            return *this;\n        }\n\n        auto getHelpColumns() const -> std::vector<HelpColumns> {\n            std::ostringstream oss;\n            bool first = true;\n            for( auto const &opt : m_optNames ) {\n                if (first)\n                    first = false;\n                else\n                    oss << \", \";\n                oss << opt;\n            }\n            if( !m_hint.empty() )\n                oss << \" <\" << m_hint << \">\";\n            return { { oss.str(), m_description } };\n        }\n\n        auto isMatch( std::string const &optToken ) const -> bool {\n            auto normalisedToken = normaliseOpt( optToken );\n            for( auto const &name : m_optNames ) {\n                if( normaliseOpt( name ) == normalisedToken )\n                    return true;\n            }\n            return false;\n        }\n\n        using ParserBase::parse;\n\n        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {\n            auto validationResult = validate();\n            if( !validationResult )\n                return InternalParseResult( validationResult );\n\n            auto remainingTokens = tokens;\n            if( remainingTokens && remainingTokens->type == TokenType::Option ) {\n                auto const &token = *remainingTokens;\n                if( isMatch(token.token ) ) {\n                    if( m_ref->isFlag() ) {\n                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );\n                        auto result = flagRef->setFlag( true );\n                        if( !result )\n                            return InternalParseResult( result );\n                        if( result.value() == ParseResultType::ShortCircuitAll )\n                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );\n                    } else {\n                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );\n                        ++remainingTokens;\n                        if( !remainingTokens )\n                            return InternalParseResult::runtimeError( \"Expected argument following \" + token.token );\n                        auto const &argToken = *remainingTokens;\n                        if( argToken.type != TokenType::Argument )\n                            return InternalParseResult::runtimeError( \"Expected argument following \" + token.token );\n                        auto result = valueRef->setValue( argToken.token );\n                        if( !result )\n                            return InternalParseResult( result );\n                        if( result.value() == ParseResultType::ShortCircuitAll )\n                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );\n                    }\n                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );\n                }\n            }\n            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );\n        }\n\n        auto validate() const -> Result override {\n            if( m_optNames.empty() )\n                return Result::logicError( \"No options supplied to Opt\" );\n            for( auto const &name : m_optNames ) {\n                if( name.empty() )\n                    return Result::logicError( \"Option name cannot be empty\" );\n#ifdef CLARA_PLATFORM_WINDOWS\n                if( name[0] != '-' && name[0] != '/' )\n                    return Result::logicError( \"Option name must begin with '-' or '/'\" );\n#else\n                if( name[0] != '-' )\n                    return Result::logicError( \"Option name must begin with '-'\" );\n#endif\n            }\n            return ParserRefImpl::validate();\n        }\n    };\n\n    struct Help : Opt {\n        Help( bool &showHelpFlag )\n        :   Opt([&]( bool flag ) {\n                showHelpFlag = flag;\n                return ParserResult::ok( ParseResultType::ShortCircuitAll );\n            })\n        {\n            static_cast<Opt &>( *this )\n                    (\"display usage information\")\n                    [\"-?\"][\"-h\"][\"--help\"]\n                    .optional();\n        }\n    };\n\n\n    struct Parser : ParserBase {\n\n        mutable ExeName m_exeName;\n        std::vector<Opt> m_options;\n        std::vector<Arg> m_args;\n\n        auto operator|=( ExeName const &exeName ) -> Parser & {\n            m_exeName = exeName;\n            return *this;\n        }\n\n        auto operator|=( Arg const &arg ) -> Parser & {\n            m_args.push_back(arg);\n            return *this;\n        }\n\n        auto operator|=( Opt const &opt ) -> Parser & {\n            m_options.push_back(opt);\n            return *this;\n        }\n\n        auto operator|=( Parser const &other ) -> Parser & {\n            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());\n            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());\n            return *this;\n        }\n\n        template<typename T>\n        auto operator|( T const &other ) const -> Parser {\n            return Parser( *this ) |= other;\n        }\n\n        // Forward deprecated interface with '+' instead of '|'\n        template<typename T>\n        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }\n        template<typename T>\n        auto operator+( T const &other ) const -> Parser { return operator|( other ); }\n\n        auto getHelpColumns() const -> std::vector<HelpColumns> {\n            std::vector<HelpColumns> cols;\n            for (auto const &o : m_options) {\n                auto childCols = o.getHelpColumns();\n                cols.insert( cols.end(), childCols.begin(), childCols.end() );\n            }\n            return cols;\n        }\n\n        void writeToStream( std::ostream &os ) const {\n            if (!m_exeName.name().empty()) {\n                os << \"usage:\\n\" << \"  \" << m_exeName.name() << \" \";\n                bool required = true, first = true;\n                for( auto const &arg : m_args ) {\n                    if (first)\n                        first = false;\n                    else\n                        os << \" \";\n                    if( arg.isOptional() && required ) {\n                        os << \"[\";\n                        required = false;\n                    }\n                    os << \"<\" << arg.hint() << \">\";\n                    if( arg.cardinality() == 0 )\n                        os << \" ... \";\n                }\n                if( !required )\n                    os << \"]\";\n                if( !m_options.empty() )\n                    os << \" options\";\n                os << \"\\n\\nwhere options are:\" << std::endl;\n            }\n\n            auto rows = getHelpColumns();\n            size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;\n            size_t optWidth = 0;\n            for( auto const &cols : rows )\n                optWidth = (std::max)(optWidth, cols.left.size() + 2);\n\n            optWidth = (std::min)(optWidth, consoleWidth/2);\n\n            for( auto const &cols : rows ) {\n                auto row =\n                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +\n                        TextFlow::Spacer(4) +\n                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );\n                os << row << std::endl;\n            }\n        }\n\n        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {\n            parser.writeToStream( os );\n            return os;\n        }\n\n        auto validate() const -> Result override {\n            for( auto const &opt : m_options ) {\n                auto result = opt.validate();\n                if( !result )\n                    return result;\n            }\n            for( auto const &arg : m_args ) {\n                auto result = arg.validate();\n                if( !result )\n                    return result;\n            }\n            return Result::ok();\n        }\n\n        using ParserBase::parse;\n\n        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {\n\n            struct ParserInfo {\n                ParserBase const* parser = nullptr;\n                size_t count = 0;\n            };\n            const size_t totalParsers = m_options.size() + m_args.size();\n            assert( totalParsers < 512 );\n            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do\n            ParserInfo parseInfos[512];\n\n            {\n                size_t i = 0;\n                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;\n                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;\n            }\n\n            m_exeName.set( exeName );\n\n            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );\n            while( result.value().remainingTokens() ) {\n                bool tokenParsed = false;\n\n                for( size_t i = 0; i < totalParsers; ++i ) {\n                    auto&  parseInfo = parseInfos[i];\n                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {\n                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());\n                        if (!result)\n                            return result;\n                        if (result.value().type() != ParseResultType::NoMatch) {\n                            tokenParsed = true;\n                            ++parseInfo.count;\n                            break;\n                        }\n                    }\n                }\n\n                if( result.value().type() == ParseResultType::ShortCircuitAll )\n                    return result;\n                if( !tokenParsed )\n                    return InternalParseResult::runtimeError( \"Unrecognised token: \" + result.value().remainingTokens()->token );\n            }\n            // !TBD Check missing required options\n            return result;\n        }\n    };\n\n    template<typename DerivedT>\n    template<typename T>\n    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {\n        return Parser() | static_cast<DerivedT const &>( *this ) | other;\n    }\n} // namespace detail\n\n\n// A Combined parser\nusing detail::Parser;\n\n// A parser for options\nusing detail::Opt;\n\n// A parser for arguments\nusing detail::Arg;\n\n// Wrapper for argc, argv from main()\nusing detail::Args;\n\n// Specifies the name of the executable\nusing detail::ExeName;\n\n// Convenience wrapper for option parser that specifies the help option\nusing detail::Help;\n\n// enum of result types from a parse\nusing detail::ParseResultType;\n\n// Result type for parser operation\nusing detail::ParserResult;\n\n\n} // namespace clara\n\n#endif // CLARA_HPP_INCLUDED\n"
  },
  {
    "path": "scenario/pyproject.toml",
    "content": "# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n[build-system]\nbuild-backend = \"setuptools.build_meta\"\nrequires = [\n    \"wheel\",\n    \"setuptools>=45\",\n    \"setuptools_scm[toml]>=6.0\",\n    \"cmake-build-extension\",\n    \"idyntree>=3.1\",\n]\n\n[tool.setuptools_scm]\nroot = \"../\"\nlocal_scheme = \"dirty-tag\"\n"
  },
  {
    "path": "scenario/setup.cfg",
    "content": "# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n[metadata]\nname = scenario\ndescription = SCENe interfAces for Robot Input/Output.\nlong_description = file: README.md\nlong_description_content_type = text/markdown\nauthor = Diego Ferigo\nauthor_email = dgferigo@gmail.com\nlicense = LGPL\nplatforms = any\nurl = https://github.com/robotology/gym-ignition/tree/master/scenario\n\nproject_urls =\n    Changelog = https://github.com/robotology/gym-ignition/releases\n    Tracker = https://github.com/robotology/gym-ignition/issues\n    Documentation = https://robotology.github.io/gym-ignition\n    Source = https://github.com/robotology/gym-ignition/tree/master/scenario\n\nkeywords =\n    robotics\n    gazebo\n    ignition\n    simulation\n    physics\n    multibody\n    dynamics\n    physics simulation\n    middleware\n    real-time\n\nclassifiers =\n    Development Status :: 5 - Production/Stable\n    Operating System :: POSIX :: Linux\n    Topic :: Games/Entertainment :: Simulation\n    Topic :: Scientific/Engineering :: Artificial Intelligence\n    Topic :: Scientific/Engineering :: Physics\n    Topic :: Software Development\n    Framework :: Robot Framework\n    Intended Audience :: Developers\n    Intended Audience :: Science/Research\n    Programming Language :: C++\n    Programming Language :: Python :: 3.8\n    Programming Language :: Python :: 3.9\n    Programming Language :: Python :: 3 :: Only\n    Programming Language :: Python :: Implementation :: CPython\n    License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)\n\n[options]\nzip_safe = False\npython_requires = >=3.8\ninstall_requires =\n    packaging\n"
  },
  {
    "path": "scenario/setup.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport sys\n\nimport setuptools\nfrom cmake_build_extension import BuildExtension, CMakeExtension\n\nsetuptools.setup(\n    ext_modules=[\n        CMakeExtension(\n            name=\"ScenarioCMakeProject\",\n            install_prefix=\"scenario\",\n            cmake_build_type=\"Release\",\n            cmake_configure_options=[\n                \"-DSCENARIO_CALL_FROM_SETUP_PY:BOOL=ON\",\n                \"-DSCENARIO_BUILD_SHARED_LIBRARY:BOOL=OFF\",\n                f\"-DPython3_EXECUTABLE:PATH={sys.executable}\",\n            ],\n            cmake_depends_on=[\"idyntree\"],\n            disable_editable=True,\n        )\n    ],\n    cmdclass=dict(build_ext=BuildExtension),\n)\n"
  },
  {
    "path": "scenario/src/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nadd_subdirectory(core)\n\nset(SCENARIO_COMPONENTS ScenarioCore)\nset(SCENARIO_PRIVATE_DEPENDENCIES \"\")\n\nif(SCENARIO_USE_IGNITION)\n\n    option(ENABLE_PROFILER \"Enable Ignition Profiler\" OFF)\n    mark_as_advanced(ENABLE_PROFILER)\n\n    add_subdirectory(gazebo)\n    add_subdirectory(plugins)\n    add_subdirectory(controllers)\n\n    list(APPEND SCENARIO_COMPONENTS ScenarioGazebo ScenarioControllers)\n\nendif()\n\n# Dummy meta target for the top-level EXPORT\nadd_library(Scenario INTERFACE)\n\ninstall(\n    TARGETS Scenario\n    EXPORT ScenarioExport)\n\ninstall_basic_package_files(Scenario\n    VERSION ${PROJECT_VERSION}\n    COMPATIBILITY AnyNewerVersion\n    EXPORT ScenarioExport\n    DEPENDENCIES ${SCENARIO_COMPONENTS}\n    PRIVATE_DEPENDENCIES ${SCENARIO_PRIVATE_DEPENDENCIES}\n    NAMESPACE Scenario::\n    NO_CHECK_REQUIRED_COMPONENTS_MACRO\n    INSTALL_DESTINATION\n    ${SCENARIO_INSTALL_LIBDIR}/cmake/Scenario)\n"
  },
  {
    "path": "scenario/src/controllers/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfind_package(iDynTree REQUIRED)\nfind_package (Eigen3 3.3 REQUIRED NO_MODULE)\n\n# ==============\n# ControllersABC\n# ==============\n\nset(CONTROLLERS_ABC_PUBLIC_HDRS\n    include/scenario/controllers/Controller.h\n    include/scenario/controllers/References.h)\n\nadd_library(ControllersABC INTERFACE)\nadd_library(ScenarioControllers::ControllersABC ALIAS ControllersABC)\n\ntarget_include_directories(ControllersABC INTERFACE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\nset_target_properties(ControllersABC PROPERTIES\n    PUBLIC_HEADER \"${CONTROLLERS_ABC_PUBLIC_HDRS}\")\n\n# https://stackoverflow.com/a/29214327\n# As a workaround target_sources can be used, however it requires more\n# boilerplate code and it has probles when exporting the INTERFACE target:\n# https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/\nadd_custom_target(ScenarioControllersABC SOURCES ${CONTROLLERS_ABC_PUBLIC_HDRS})\n\n# =======================\n# ComputedTorqueFixedBase\n# =======================\n\nadd_library(ComputedTorqueFixedBase SHARED\n    include/scenario/controllers/ComputedTorqueFixedBase.h\n    src/ComputedTorqueFixedBase.cpp)\nadd_library(ScenarioControllers::ComputedTorqueFixedBase ALIAS ComputedTorqueFixedBase)\n\ntarget_link_libraries(ComputedTorqueFixedBase\n    PUBLIC\n    ScenarioControllers::ControllersABC\n    PRIVATE\n    Eigen3::Eigen\n    ScenarioCore::ScenarioABC\n    iDynTree::idyntree-core\n    iDynTree::idyntree-model\n    iDynTree::idyntree-modelio-urdf\n    iDynTree::idyntree-high-level)\n\ntarget_include_directories(ComputedTorqueFixedBase PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\nset_target_properties(ComputedTorqueFixedBase PROPERTIES\n    PUBLIC_HEADER include/scenario/controllers/ComputedTorqueFixedBase.h)\n\n# ===================\n# Install the targets\n# ===================\n\ninstall(\n    TARGETS\n    ControllersABC\n    ComputedTorqueFixedBase\n    EXPORT ScenarioControllersExport\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION\n    ${SCENARIO_INSTALL_INCLUDEDIR}/scenario/controllers)\n\ninstall_basic_package_files(ScenarioControllers\n    COMPONENT Controllers\n    VERSION ${PROJECT_VERSION}\n    COMPATIBILITY AnyNewerVersion\n    EXPORT ScenarioControllersExport\n    NAMESPACE ScenarioControllers::\n    NO_CHECK_REQUIRED_COMPONENTS_MACRO\n    INSTALL_DESTINATION\n    ${SCENARIO_INSTALL_LIBDIR}/cmake/ScenarioControllers)\n"
  },
  {
    "path": "scenario/src/controllers/include/scenario/controllers/ComputedTorqueFixedBase.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CONTROLLERS_COMPUTEDTORQUEFIXEDBASE_H\n#define SCENARIO_CONTROLLERS_COMPUTEDTORQUEFIXEDBASE_H\n\n#include \"scenario/controllers/Controller.h\"\n#include \"scenario/controllers/References.h\"\n\n#include <array>\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::core {\n    class Model;\n} // namespace scenario::core\n\nnamespace scenario::controllers {\n    class ControllersFactory;\n    class ComputedTorqueFixedBase;\n} // namespace scenario::controllers\n\nclass scenario::controllers::ComputedTorqueFixedBase final\n    : public scenario::controllers::Controller\n    , public scenario::controllers::UseScenarioModel\n    , public scenario::controllers::SetJointReferences\n{\npublic:\n    ComputedTorqueFixedBase() = delete;\n    ComputedTorqueFixedBase(const std::string& urdfFile,\n                            std::shared_ptr<core::Model> model,\n                            const std::vector<double>& kp,\n                            const std::vector<double>& kd,\n                            const std::vector<std::string>& controlledJoints,\n                            const std::array<double, 3> gravity = g);\n    ~ComputedTorqueFixedBase() override;\n\n    bool initialize() override;\n    bool step(const StepSize& dt) override;\n    bool terminate() override;\n\n    bool updateStateFromModel() override;\n\n    const std::vector<std::string>& controlledJoints() override;\n    bool setJointReferences(const JointReferences& jointReferences) override;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_CONTROLLERS_COMPUTEDTORQUEFIXEDBASE_H\n"
  },
  {
    "path": "scenario/src/controllers/include/scenario/controllers/Controller.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CONTROLLERS_CONTROLLER_H\n#define SCENARIO_CONTROLLERS_CONTROLLER_H\n\n#include \"scenario/controllers/References.h\"\n\n#include <chrono>\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::controllers {\n    class Controller;\n    class UseScenarioModel;\n    class SetBaseReferences;\n    class SetJointReferences;\n    using ControllerPtr = std::shared_ptr<Controller>;\n    constexpr std::array<double, 3> g = {0, 0, -9.80665};\n} // namespace scenario::controllers\n\nnamespace scenario::core {\n    class Model;\n    using ModelPtr = std::shared_ptr<Model>;\n} // namespace scenario::core\n\nclass scenario::controllers::Controller\n    : public std::enable_shared_from_this<scenario::controllers::Controller>\n{\npublic:\n    using StepSize = std::chrono::duration<double>;\n\n    Controller() = default;\n    virtual ~Controller() = default;\n\n    virtual bool initialize() = 0;\n    virtual bool step(const StepSize& dt) = 0;\n    virtual bool terminate() = 0;\n};\n\nclass scenario::controllers::UseScenarioModel\n{\npublic:\n    UseScenarioModel() = default;\n    virtual ~UseScenarioModel() = default;\n\n    virtual bool updateStateFromModel() = 0;\n\nprotected:\n    core::ModelPtr m_model;\n};\n\nclass scenario::controllers::SetBaseReferences\n{\npublic:\n    SetBaseReferences() = default;\n    virtual ~SetBaseReferences() = default;\n\n    virtual bool setBaseReferences(const BaseReferences& jointReferences) = 0;\n};\n\nclass scenario::controllers::SetJointReferences\n{\npublic:\n    SetJointReferences() = default;\n    virtual ~SetJointReferences() = default;\n\n    virtual const std::vector<std::string>& controlledJoints() = 0;\n    virtual bool setJointReferences(const JointReferences& jointReferences) = 0;\n\nprotected:\n    std::vector<std::string> m_controlledJoints;\n};\n\n#endif // SCENARIO_CONTROLLERS_CONTROLLER_H\n"
  },
  {
    "path": "scenario/src/controllers/include/scenario/controllers/References.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CONTROLLERS_REFERENCES_H\n#define SCENARIO_CONTROLLERS_REFERENCES_H\n\n#include <array>\n#include <cstddef>\n#include <vector>\n\nnamespace scenario::controllers {\n    struct BaseReferences;\n    struct JointReferences;\n} // namespace scenario::controllers\n\nstruct scenario::controllers::BaseReferences\n{\n    std::array<double, 3> position = {0, 0, 0};\n    std::array<double, 4> orientation = {1, 0, 0, 0};\n    std::array<double, 3> linearVelocity = {0, 0, 0};\n    std::array<double, 3> angularVelocity = {0, 0, 0};\n    std::array<double, 3> linearAcceleration = {0, 0, 0};\n    std::array<double, 3> angularAcceleration = {0, 0, 0};\n};\n\nstruct scenario::controllers::JointReferences\n{\n    JointReferences(const size_t controlledDofs = 0)\n    {\n        position = std::vector<double>(controlledDofs, 0.0);\n        velocity = std::vector<double>(controlledDofs, 0.0);\n        acceleration = std::vector<double>(controlledDofs, 0.0);\n    }\n\n    inline bool valid() const\n    {\n        size_t dofs = position.size();\n        return dofs > 0 && velocity.size() == dofs\n               && acceleration.size() == dofs;\n    }\n\n    std::vector<double> position;\n    std::vector<double> velocity;\n    std::vector<double> acceleration;\n};\n\n#endif // SCENARIO_CONTROLLERS_REFERENCES_H\n"
  },
  {
    "path": "scenario/src/controllers/src/ComputedTorqueFixedBase.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#include \"scenario/controllers/ComputedTorqueFixedBase.h\"\n#include \"scenario/controllers/References.h\"\n#include \"scenario/core/Joint.h\"\n#include \"scenario/core/Model.h\"\n#include \"scenario/core/utils/Log.h\"\n\n#include <Eigen/Dense>\n#include <iDynTree/Core/EigenHelpers.h>\n#include <iDynTree/Core/MatrixDynSize.h>\n#include <iDynTree/Core/VectorDynSize.h>\n#include <iDynTree/Core/VectorFixSize.h>\n#include <iDynTree/KinDynComputations.h>\n#include <iDynTree/Model/FreeFloatingState.h>\n#include <iDynTree/ModelIO/ModelLoader.h>\n\n#include <cassert>\n#include <unordered_map>\n\nusing namespace scenario::controllers;\n\nclass ComputedTorqueFixedBase::Impl\n{\npublic:\n    class Buffers;\n\n    std::string urdfFile;\n\n    struct\n    {\n        std::vector<double> kp;\n        std::vector<double> kd;\n        std::array<double, 3> gravity;\n        std::unordered_map<std::string, core::JointControlMode> controlMode;\n    } initialValues;\n\n    JointReferences jointReferences;\n    std::unique_ptr<Buffers> buffers;\n    std::unique_ptr<iDynTree::KinDynComputations> kinDyn;\n\n    static Eigen::Map<Eigen::VectorXd> toEigen(std::vector<double>& vector)\n    {\n        return {vector.data(), Eigen::Index(vector.size())};\n    }\n};\n\nclass ComputedTorqueFixedBase::Impl::Buffers\n{\npublic:\n    Buffers(const unsigned controlledDofs = 0)\n    {\n        jointPositions.resize(controlledDofs);\n        jointVelocities.resize(controlledDofs);\n        massMatrix.resize(controlledDofs + 6, controlledDofs + 6);\n\n        kp = Eigen::ArrayXd(controlledDofs);\n        kd = Eigen::ArrayXd(controlledDofs);\n\n        torques = Eigen::VectorXd(controlledDofs);\n        dds_star = Eigen::VectorXd(controlledDofs);\n        positionError = Eigen::VectorXd(controlledDofs);\n        velocityError = Eigen::VectorXd(controlledDofs);\n\n        torquesVector.reserve(controlledDofs);\n    }\n\n    iDynTree::Vector3 gravity = {g.data(), 3};\n    iDynTree::MatrixDynSize massMatrix;\n    iDynTree::VectorDynSize jointPositions;\n    iDynTree::VectorDynSize jointVelocities;\n    iDynTree::FreeFloatingGeneralizedTorques biasForces;\n\n    Eigen::ArrayXd kp;\n    Eigen::ArrayXd kd;\n\n    Eigen::VectorXd torques;\n    Eigen::VectorXd dds_star;\n    Eigen::VectorXd positionError;\n    Eigen::VectorXd velocityError;\n\n    std::vector<double> torquesVector;\n};\n\nComputedTorqueFixedBase::ComputedTorqueFixedBase(\n    const std::string& urdfFile,\n    std::shared_ptr<core::Model> model,\n    const std::vector<double>& kp,\n    const std::vector<double>& kd,\n    const std::vector<std::string>& controlledJoints,\n    const std::array<double, 3> gravity)\n    : Controller()\n    , UseScenarioModel()\n    , SetJointReferences()\n    , pImpl{std::make_unique<Impl>()}\n{\n    m_model = model;\n    pImpl->urdfFile = urdfFile;\n    m_controlledJoints = controlledJoints;\n\n    if (m_controlledJoints.size() == 0) {\n        sDebug << \"No list of controlled joints found. \"\n               << \"Controlling all the robots joints.\" << std::endl;\n        // Note: the joint serialization is now given by the default\n        //       list of joint names provided by the model\n        m_controlledJoints = m_model->jointNames();\n    }\n\n    pImpl->initialValues.gravity = gravity;\n\n    pImpl->initialValues.kp = kp;\n    pImpl->initialValues.kd = kd;\n    assert(m_controlledJoints.size() == kp.size());\n    assert(kp.size() == kd.size());\n}\n\nComputedTorqueFixedBase::~ComputedTorqueFixedBase() = default;\n\nbool ComputedTorqueFixedBase::initialize()\n{\n    sDebug << \"Initializing ComputedTorqueFixedBaseCpp\" << std::endl;\n\n    if (pImpl->kinDyn) {\n        sWarning << \"The KinDynComputations object has been already initialized\"\n                 << std::endl;\n        return true;\n    }\n\n    if (!(m_model && m_model->valid())) {\n        sError << \"Couldn't initialize controller. Model not valid.\"\n               << std::endl;\n        return false;\n    }\n\n    if (m_controlledJoints.empty()) {\n        sError << \"The list of controlled joints is not valid\" << std::endl;\n        return false;\n    }\n\n    if (m_controlledJoints.size() != m_model->dofs()) {\n        sError << \"Controlling only a subset of joints is not yet supported\"\n               << std::endl;\n        return false;\n    }\n\n    for (auto& joint : m_model->joints(m_controlledJoints)) {\n        if (joint->dofs() != 1) {\n            sError << \"Joint '\" << joint->name()\n                   << \"' does not have 1 DoF and is not supported\" << std::endl;\n            return false;\n        }\n    }\n\n    iDynTree::ModelLoader loader;\n    if (!loader.loadReducedModelFromFile(pImpl->urdfFile, m_controlledJoints)) {\n        sError << \"Failed to load reduced model from the urdf file\"\n               << std::endl;\n        return false;\n    }\n\n    pImpl->kinDyn = std::make_unique<iDynTree::KinDynComputations>();\n    pImpl->kinDyn->setFrameVelocityRepresentation(\n        iDynTree::MIXED_REPRESENTATION);\n\n    if (!pImpl->kinDyn->loadRobotModel(loader.model())) {\n        sError << \"Failed to insert model in the KinDynComputations object\"\n               << std::endl;\n        return false;\n    }\n\n    // Set controlled joints in torque control mode\n    for (auto& joint : m_model->joints(m_controlledJoints)) {\n        pImpl->initialValues.controlMode[joint->name()] = joint->controlMode();\n\n        if (!joint->setControlMode(core::JointControlMode::Force)) {\n            sError << \"Failed to control joint '\" << joint->name()\n                   << \"' in Force\" << std::endl;\n            return false;\n        }\n    }\n\n    // Initialize buffers\n    sDebug << \"Controlling \" << m_controlledJoints.size() << \" DoFs\"\n           << std::endl;\n    pImpl->buffers = std::make_unique<Impl::Buffers>(m_controlledJoints.size());\n\n    pImpl->buffers->kp = Impl::toEigen(pImpl->initialValues.kp);\n    pImpl->buffers->kd = Impl::toEigen(pImpl->initialValues.kd);\n    pImpl->buffers->biasForces.resize(loader.model());\n\n    // Set the gravity\n    pImpl->buffers->gravity[0] = pImpl->initialValues.gravity[0];\n    pImpl->buffers->gravity[1] = pImpl->initialValues.gravity[1];\n    pImpl->buffers->gravity[2] = pImpl->initialValues.gravity[2];\n\n    return true;\n}\n\nbool ComputedTorqueFixedBase::step(const Controller::StepSize& /*dt*/)\n{\n    // ===================\n    // Intermediate Values\n    // ===================\n\n    const auto nrControlledDofs = pImpl->buffers->jointPositions.size();\n\n    auto Mfloating = iDynTree::toEigen(pImpl->buffers->massMatrix);\n\n    auto h = iDynTree::toEigen(pImpl->buffers->biasForces.jointTorques());\n    auto M = Mfloating.bottomRightCorner(nrControlledDofs, nrControlledDofs);\n    assert(h.size() == nrControlledDofs);\n    assert(M.size() == nrControlledDofs * nrControlledDofs);\n\n    auto s = iDynTree::toEigen(pImpl->buffers->jointPositions);\n    auto ds = iDynTree::toEigen(pImpl->buffers->jointVelocities);\n    assert(s.size() == nrControlledDofs);\n    assert(ds.size() == nrControlledDofs);\n\n    auto s_ref = Impl::toEigen(pImpl->jointReferences.position);\n    auto ds_ref = Impl::toEigen(pImpl->jointReferences.velocity);\n    auto dds_ref = Impl::toEigen(pImpl->jointReferences.acceleration);\n    assert(s_ref.size() == nrControlledDofs);\n    assert(ds_ref.size() == nrControlledDofs);\n    assert(dds_ref.size() == nrControlledDofs);\n\n    auto& kp = pImpl->buffers->kp;\n    auto& kd = pImpl->buffers->kd;\n    auto& s_tilde = pImpl->buffers->positionError;\n    auto& ds_tilde = pImpl->buffers->velocityError;\n    assert(kp.size() == nrControlledDofs);\n    assert(kd.size() == nrControlledDofs);\n    assert(s_tilde.size() == nrControlledDofs);\n    assert(ds_tilde.size() == nrControlledDofs);\n\n    auto& tau = pImpl->buffers->torques;\n    auto& dds_star = pImpl->buffers->dds_star;\n    assert(tau.size() == nrControlledDofs);\n    assert(dds_star.size() == nrControlledDofs);\n\n    // ===========\n    // Control Law\n    // ===========\n\n    // Compute errors\n    s_tilde = s - s_ref;\n    ds_tilde = ds - ds_ref;\n\n    // Compute the acceleration\n    dds_star = dds_ref.array() - kp * s_tilde.array() - kd * ds_tilde.array();\n\n    // Compute the torque\n    tau = M * dds_star + h;\n\n    pImpl->buffers->torquesVector = std::vector<double>(\n        pImpl->buffers->torques.data(),\n        pImpl->buffers->torques.data() + pImpl->buffers->torques.size());\n\n    if (!m_model->setJointGeneralizedForceTargets(pImpl->buffers->torquesVector,\n                                                  m_controlledJoints)) {\n        sError << \"Failed to set joint forces\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool ComputedTorqueFixedBase::terminate()\n{\n    bool ok = true;\n\n    for (const auto& [jointName, controlMode] :\n         pImpl->initialValues.controlMode) {\n\n        auto joint = m_model->getJoint(jointName);\n\n        if (!joint->setControlMode(controlMode)) {\n            sError << \"Failed to restore original control mode of joint '\"\n                   << jointName << \"'\" << std::endl;\n            ok = ok && false;\n        }\n    }\n\n    pImpl->kinDyn.reset();\n    pImpl->buffers.reset();\n    return ok;\n}\n\nbool ComputedTorqueFixedBase::updateStateFromModel()\n{\n    assert(m_model->jointPositions(m_controlledJoints).size()\n           == pImpl->buffers->jointPositions.size());\n    assert(m_model->jointVelocities(m_controlledJoints).size()\n           == pImpl->buffers->jointVelocities.size());\n\n    for (unsigned i = 0; i < m_controlledJoints.size(); ++i) {\n        // Get the joint\n        const auto& jointName = m_controlledJoints[i];\n        auto joint = m_model->getJoint(jointName);\n        assert(joint->dofs() == 1);\n\n        // Update the buffers\n        pImpl->buffers->jointPositions.setVal(i, joint->position());\n        pImpl->buffers->jointVelocities.setVal(i, joint->velocity());\n    }\n\n    if (!pImpl->kinDyn->setRobotState(pImpl->buffers->jointPositions,\n                                      pImpl->buffers->jointVelocities,\n                                      pImpl->buffers->gravity)) {\n        sError << \"Failed to set the robot state\" << std::endl;\n        return false;\n    }\n\n    if (!pImpl->kinDyn->getFreeFloatingMassMatrix(pImpl->buffers->massMatrix)) {\n        sError << \"Failed to get the mass matrix\" << std::endl;\n        return false;\n    }\n\n    if (!pImpl->kinDyn->generalizedBiasForces(pImpl->buffers->biasForces)) {\n        sError << \"Failed to get the bias forces \" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nconst std::vector<std::string>& ComputedTorqueFixedBase::controlledJoints()\n{\n    return m_controlledJoints;\n}\n\nbool ComputedTorqueFixedBase::setJointReferences(\n    const JointReferences& jointReferences)\n{\n    pImpl->jointReferences = jointReferences;\n    return pImpl->jointReferences.valid();\n};\n"
  },
  {
    "path": "scenario/src/core/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n# ===========\n# ScenarioABC\n# ===========\n\nset(SCENARIO_ABC_PUBLIC_HEADERS\n    include/scenario/core/World.h\n    include/scenario/core/Model.h\n    include/scenario/core/Joint.h\n    include/scenario/core/Link.h)\n\nadd_library(ScenarioABC INTERFACE)\nadd_library(ScenarioCore::ScenarioABC ALIAS ScenarioABC)\n\ntarget_include_directories(ScenarioABC INTERFACE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\nset_target_properties(ScenarioABC PROPERTIES\n    PUBLIC_HEADER \"${SCENARIO_ABC_PUBLIC_HEADERS}\")\n\n# https://stackoverflow.com/a/29214327\n# As a workaround target_sources can be used, however it requires more\n# boilerplate code and it has probles when exporting the INTERFACE target:\n# https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/\nadd_custom_target(ScenarioCoreABC SOURCES ${SCENARIO_ABC_PUBLIC_HEADERS})\n\n# =================\n# ScenarioCoreUtils\n# =================\n\nset(CORE_UTILS_HEADERS\n    include/scenario/core/utils/Log.h\n    include/scenario/core/utils/signals.h\n    include/scenario/core/utils/utils.h)\n\nadd_library(CoreUtils\n    ${CORE_UTILS_HEADERS}\n    src/signals.cpp\n    src/utils.cpp)\nadd_library(ScenarioCore::CoreUtils ALIAS CoreUtils)\n\ntarget_include_directories(CoreUtils PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\nset_target_properties(CoreUtils PROPERTIES\n    PUBLIC_HEADER \"${CORE_UTILS_HEADERS}\")\n\n# This definition is used by the \"scenario\" Python package\n# to detect User / Developer installation mode\nif(NOT SCENARIO_CALL_FROM_SETUP_PY)\n    target_compile_options(CoreUtils PRIVATE\n        -DSCENARIO_CMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\")\nendif()\n\n# ===================\n# Install the targets\n# ===================\n\ninstall(\n    TARGETS ScenarioABC\n    EXPORT ScenarioCoreExport\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION\n    ${SCENARIO_INSTALL_INCLUDEDIR}/scenario/core)\n\ninstall(\n    TARGETS CoreUtils\n    EXPORT ScenarioCoreExport\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION\n    ${SCENARIO_INSTALL_INCLUDEDIR}/scenario/core/utils)\n\ninstall_basic_package_files(ScenarioCore\n    COMPONENT Core\n    VERSION ${PROJECT_VERSION}\n    COMPATIBILITY AnyNewerVersion\n    EXPORT ScenarioCoreExport\n    NAMESPACE ScenarioCore::\n    NO_CHECK_REQUIRED_COMPONENTS_MACRO\n    INSTALL_DESTINATION\n    ${SCENARIO_INSTALL_LIBDIR}/cmake/ScenarioCore)\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/Joint.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_JOINT_H\n#define SCENARIO_CORE_JOINT_H\n\n#include <algorithm>\n#include <limits>\n#include <string>\n#include <vector>\n\nnamespace scenario::core {\n    struct PID;\n    struct Limit;\n    struct JointLimit;\n\n    /**\n     * Supported joint types.\n     */\n    enum class JointType\n    {\n        Invalid,\n        Fixed,\n        Revolute,\n        Prismatic,\n        Ball,\n    };\n\n    /**\n     * Supported joint control modes.\n     */\n    enum class JointControlMode\n    {\n        /// Marks the joint to have an invalid control mode.\n        Invalid,\n\n        /// Marks the joint to be IDLE. An IDLE joint is equivalent to a joint\n        /// controlled in Force with zero references. The joint shows only\n        /// passive behaviour.\n        Idle,\n\n        /// Marks the joint to be controlled in force. A Force joint receives\n        /// generalized force references that are actuated by a force actuator.\n        /// Depending on the active backend, the presence of friction and other\n        /// loss components could be compensated.\n        Force,\n\n        /// Marks the joint to be controlled in velocity. A Velocity joint\n        /// receives velocity references that are actuated using a PID\n        /// controller.\n        Velocity,\n\n        /// Marks the joint to follow precisely a velocity trajectory. A\n        /// VelocityFollowerDart joint receives velocity references that\n        /// are processed by the physics engine, which computes instantaneously\n        /// the right force to apply to follow the desired trajectory.\n        /// It works only with the DART physics engine.\n        VelocityFollowerDart,\n\n        /// Marks the joint to be controlled in position. A Position joint\n        /// receives position references that are actuated using a PID\n        /// controller.\n        Position,\n\n        /// Marks the joint to be controlled in position with trajectory\n        /// smoothing. A PositionInterpolated joint receives position references\n        /// that are filtered to get a smooth trajectory. The resulting\n        /// trajectory is then actuated using a position PID controller.\n        PositionInterpolated,\n    };\n    class Joint;\n} // namespace scenario::core\n\nclass scenario::core::Joint\n{\npublic:\n    Joint() = default;\n    virtual ~Joint() = default;\n\n    /**\n     * Check if the joint is valid.\n     *\n     * @return True if the joint is valid, false otherwise.\n     */\n    virtual bool valid() const = 0;\n\n    /**\n     * Get the number of degrees of freedom of the joint.\n     *\n     * @return The number of DOFs of the joint.\n     */\n    virtual size_t dofs() const = 0;\n\n    /**\n     * Get the name of the joint.\n     *\n     * @param scoped If true, the scoped name of the joint is returned.\n     * @return The name of the joint.\n     */\n    virtual std::string name(const bool scoped = false) const = 0;\n\n    /**\n     * Get the type of the joint.\n     *\n     * @return The type of the joint.\n     */\n    virtual JointType type() const = 0;\n\n    /**\n     * Get the active joint control mode.\n     *\n     * @return The active joint control mode.\n     */\n    virtual JointControlMode controlMode() const = 0;\n\n    /**\n     * Set the joint control mode.\n     *\n     * @param mode The desired control mode.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setControlMode(const JointControlMode mode) = 0;\n\n    /**\n     * Get the period of the controller, if any.\n     *\n     * The controller period is a model quantity. If no controller\n     * is active, infinity is returned.\n     *\n     * @return The the controller period.\n     */\n    virtual double controllerPeriod() const = 0;\n\n    /**\n     * Get the PID parameters of the joint.\n     *\n     * If no PID parameters have been set, the default parameters are\n     * returned.\n     *\n     * @return The joint PID parameters.\n     */\n    virtual PID pid() const = 0;\n\n    /**\n     * Set the PID parameters of the joint.\n     *\n     * @param pid The desired PID parameters.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setPID(const PID& pid) = 0;\n\n    /**\n     * Check if the history of applied joint forces is enabled.\n     *\n     * @return True if the history is enabled, false otherwise.\n     */\n    virtual bool historyOfAppliedJointForcesEnabled() const = 0;\n\n    /**\n     * Enable the history of joint forces.\n     *\n     * @param enable True to enable, false to disable.\n     * @param maxHistorySize The size of the history window.\n     * @return True for success, false otherwise.\n     */\n    virtual bool enableHistoryOfAppliedJointForces( //\n        const bool enable = true,\n        const size_t maxHistorySize = 100) = 0;\n\n    /**\n     * Get the history of applied joint forces.\n     *\n     * The vector is populated with #DoFs values at each physics step.\n     *\n     * @return The vector containing the history of joint forces.\n     */\n    virtual std::vector<double> historyOfAppliedJointForces() const = 0;\n\n    /**\n     * Get the Coulomb friction of the joint.\n     *\n     * If \\f$ K_c \\f$ is the Coulomb friction parameter, and \\f$ \\dot{q} \\f$\n     * the joint velocity, the corresponding torque is often modelled as:\n     *\n     * \\f$ \\tau_{static} = sign(\\dot{q}) K_c \\f$\n     *\n     * @return The Coulomb friction parameter of the joint.\n     */\n    virtual double coulombFriction() const = 0;\n\n    /**\n     * Get the viscous friction of the joint.\n     *\n     * If \\f$ K_v \\f$ is the viscous friction parameter, and \\f$ \\dot{q} \\f$\n     * the joint velocity, the corresponding torque is often modelled as:\n     *\n     * \\f$ \\tau_{static} = K_v \\dot{q} \\f$\n     *\n     * @return The viscous friction parameter of the joint.\n     */\n    virtual double viscousFriction() const = 0;\n\n    // ==================\n    // Single DOF methods\n    // ==================\n\n    /**\n     * Get the position limits of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The position limits of the joint DOF.\n     */\n    virtual Limit positionLimit(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the velocity limit of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The velocity limit of the joint DOF.\n     */\n    virtual Limit velocityLimit(const size_t dof = 0) const = 0;\n\n    /**\n     * Set the maximum velocity of a joint DOF.\n     *\n     * This limit can be used to clip the velocity applied by joint\n     * controllers.\n     *\n     * @param maxVelocity The maximum velocity.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setVelocityLimit(const double maxVelocity,\n                                  const size_t dof = 0) = 0;\n\n    /**\n     * Get the maximum generalized force that could be applied to a joint\n     * DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The maximum generalized force of the joint DOF.\n     */\n    virtual double maxGeneralizedForce(const size_t dof = 0) const = 0;\n\n    /**\n     * Set the maximum generalized force that can be applied to a joint DOF.\n     *\n     * This limit can be used to clip the force applied by joint\n     * controllers.\n     *\n     * @param maxForce The maximum generalized force.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setMaxGeneralizedForce(const double maxForce,\n                                        const size_t dof = 0) = 0;\n\n    /**\n     * Get the position of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The position of the joint DOF.\n     */\n    virtual double position(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the velocity of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The velocity of the joint DOF.\n     */\n    virtual double velocity(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the acceleration of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The acceleration of the joint DOF.\n     */\n    virtual double acceleration(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the generalized force of a joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return The generalized force of the joint DOF.\n     */\n    virtual double generalizedForce(const size_t dof = 0) const = 0;\n\n    /**\n     * Set the position target of a joint DOF.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param position The position target of the joint DOF.\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setPositionTarget(const double position,\n                                   const size_t dof = 0) = 0;\n\n    /**\n     * Set the velocity target of a joint DOF.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param velocity The velocity target of the joint DOF.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setVelocityTarget(const double velocity,\n                                   const size_t dof = 0) = 0;\n\n    /**\n     * Set the acceleration target of a joint DOF.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param acceleration The acceleration target of the joint DOF.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setAccelerationTarget(const double acceleration,\n                                       const size_t dof = 0) = 0;\n\n    /**\n     * Set the generalized force target of a joint DOF.\n     *\n     * The force is applied to the desired DOF. Note that if there's\n     * friction or other loss components, the real joint force will differ.\n     *\n     * @param force The generalized force target of the joint DOF.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setGeneralizedForceTarget(const double force,\n                                           const size_t dof = 0) = 0;\n\n    /**\n     * Get the active position target of the joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid or if no position\n     * target was set.\n     * @return The position target of the joint DOF.\n     */\n    virtual double positionTarget(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the active velocity target of the joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid or if no velocity\n     * target was set.\n     * @return The velocity target of the joint DOF.\n     */\n    virtual double velocityTarget(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the active acceleration target of the joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid or if no\n     * acceleration target was set.\n     * @return The acceleration target of the joint DOF.\n     */\n    virtual double accelerationTarget(const size_t dof = 0) const = 0;\n\n    /**\n     * Get the active generalized force target of the joint DOF.\n     *\n     * @param dof The index of the DOF.\n     * @throw std::runtime_error if the DOF is not valid or if no\n     * generalized force target was set.\n     * @return The generalized force target of the joint DOF.\n     */\n    virtual double generalizedForceTarget(const size_t dof = 0) const = 0;\n\n    // =================\n    // Multi DOF methods\n    // =================\n\n    /**\n     * Get the position limits of the joint.\n     *\n     * @return The position limits of the joint.\n     */\n    virtual JointLimit jointPositionLimit() const = 0;\n\n    /**\n     * Get the velocity limits of the joint.\n     *\n     * @return The velocity limits of the joint.\n     */\n    virtual JointLimit jointVelocityLimit() const = 0;\n\n    /**\n     * Set the maximum velocity of the joint.\n     *\n     * This limit can be used to clip the velocity applied by joint\n     * controllers.\n     *\n     * @param maxVelocity A vector with the maximum velocity of the joint DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointVelocityLimit(const std::vector<double>& maxVelocity) = 0;\n\n    /**\n     * Get the maximum generalized force that could be applied to the joint.\n     *\n     * @return The maximum generalized force of the joint.\n     */\n    virtual std::vector<double> jointMaxGeneralizedForce() const = 0;\n\n    /**\n     * Set the maximum generalized force that can be applied to the joint.\n     *\n     * This limit can be used to clip the force applied by joint\n     * controllers.\n     *\n     * @param maxForce A vector with the maximum generalized forces of the\n     * joint DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointMaxGeneralizedForce(const std::vector<double>& maxForce) = 0;\n\n    /**\n     * Get the position of the joint.\n     *\n     * @return The position of the joint.\n     */\n    virtual std::vector<double> jointPosition() const = 0;\n\n    /**\n     * Get the velocity of the joint.\n     *\n     * @return The velocity of the joint.\n     */\n    virtual std::vector<double> jointVelocity() const = 0;\n\n    /**\n     * Get the acceleration of the joint.\n     *\n     * @return The acceleration of the joint.\n     */\n    virtual std::vector<double> jointAcceleration() const = 0;\n\n    /**\n     * Get the generalized force of the joint.\n     *\n     * @return The generalized force of the joint.\n     */\n    virtual std::vector<double> jointGeneralizedForce() const = 0;\n\n    /**\n     * Set the position target of the joint.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param position A vector with the position targets of the joint DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointPositionTarget(const std::vector<double>& position) = 0;\n\n    /**\n     * Set the velocity target of the joint.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param velocity A vector with the velocity targets of the joint DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointVelocityTarget(const std::vector<double>& velocity) = 0;\n\n    /**\n     * Set the acceleration target of the joint.\n     *\n     * The target is processed by a joint controller, if enabled.\n     *\n     * @param acceleration A vector with the acceleration targets of the\n     * joint DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointAccelerationTarget(const std::vector<double>& acceleration) = 0;\n\n    /**\n     * Set the generalized force target of the joint.\n     *\n     * Note that if there's friction or other loss components, the real\n     * joint force will differ.\n     *\n     * @param force A vector with the generalized force targets of the joint\n     * DOFs.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointGeneralizedForceTarget(const std::vector<double>& force) = 0;\n\n    /**\n     * Get the active position target.\n     *\n     * @return The position target of the joint.\n     */\n    virtual std::vector<double> jointPositionTarget() const = 0;\n\n    /**\n     * Get the active velocity target.\n     *\n     * @return The velocity target of the joint.\n     */\n    virtual std::vector<double> jointVelocityTarget() const = 0;\n\n    /**\n     * Get the active acceleration target.\n     *\n     * @return The acceleration target of the joint.\n     */\n    virtual std::vector<double> jointAccelerationTarget() const = 0;\n\n    /**\n     * Get the active generalized force target.\n     *\n     * @return The generalized force target of the joint.\n     */\n    virtual std::vector<double> jointGeneralizedForceTarget() const = 0;\n};\n\nstruct scenario::core::PID\n{\n    PID() = default;\n\n    PID(const double _p, const double _i, const double _d)\n        : p(_p)\n        , i(_i)\n        , d(_d)\n    {}\n\n    double p = 0;\n    double i = 0;\n    double d = 0;\n    double cmdMin = std::numeric_limits<double>::lowest();\n    double cmdMax = std::numeric_limits<double>::max();\n    double cmdOffset = 0;\n    double iMin = std::numeric_limits<double>::lowest();\n    double iMax = std::numeric_limits<double>::max();\n};\n\nstruct scenario::core::Limit\n{\n    Limit() = default;\n    Limit(const double _min, const double _max)\n        : min(_min)\n        , max(_max)\n    {}\n\n    double min = std::numeric_limits<double>::lowest();\n    double max = std::numeric_limits<double>::max();\n};\n\nstruct scenario::core::JointLimit\n{\n    JointLimit(const size_t dofs = 0)\n    {\n        constexpr double m = std::numeric_limits<double>::lowest();\n        constexpr double M = std::numeric_limits<double>::max();\n\n        min = std::vector<double>(dofs, m);\n        max = std::vector<double>(dofs, M);\n    }\n\n    JointLimit(const std::vector<double>& _min, const std::vector<double>& _max)\n        : JointLimit(std::min(_min.size(), _max.size()))\n    {\n        if (_min.size() != _max.size()) {\n            return;\n        }\n\n        min = _min;\n        max = _max;\n    }\n\n    std::vector<double> min;\n    std::vector<double> max;\n};\n\n#endif // SCENARIO_CORE_JOINT_H\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/Link.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_LINK_H\n#define SCENARIO_CORE_LINK_H\n\n#include <array>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace scenario::core {\n    class Link;\n    class Model;\n    struct Pose;\n    struct Contact;\n    struct ContactPoint;\n} // namespace scenario::core\n\nclass scenario::core::Link\n{\npublic:\n    Link() = default;\n    virtual ~Link() = default;\n\n    /**\n     * Check if the link is valid.\n     *\n     * @return True if the link is valid, false otherwise.\n     */\n    virtual bool valid() const = 0;\n\n    /**\n     * Get the name of the link.\n     *\n     * @param scoped If true, the scoped name of the link is returned.\n     * @return The name of the link.\n     */\n    virtual std::string name(const bool scoped = false) const = 0;\n\n    /**\n     * Get the mass of the link.\n     *\n     * @return The mass of the link.\n     */\n    virtual double mass() const = 0;\n\n    /**\n     * Get the position of the link.\n     *\n     * The returned position is the position of the link frame, as it was\n     * defined in the model file, in world coordinates.\n     *\n     * @return The cartesian position of the link frame in world coordinates.\n     */\n    virtual std::array<double, 3> position() const = 0;\n\n    /**\n     * Get the orientation of the link.\n     *\n     * The orientation is returned as a quaternion, which defines the\n     * rotation between the world frame and the link frame.\n     *\n     * @return The wxyz quaternion defining the orientation if the link wrt the\n     * world frame.\n     */\n    virtual std::array<double, 4> orientation() const = 0;\n\n    /**\n     * Get the linear mixed velocity of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear mixed velocity of the link.\n     */\n    virtual std::array<double, 3> worldLinearVelocity() const = 0;\n\n    /**\n     * Get the angular mixed velocity of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular mixed velocity of the link.\n     */\n    virtual std::array<double, 3> worldAngularVelocity() const = 0;\n\n    /**\n     * Get the linear body velocity of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear body velocity of the link.\n     */\n    virtual std::array<double, 3> bodyLinearVelocity() const = 0;\n\n    /**\n     * Get the angular body velocity of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular body velocity of the link.\n     */\n    virtual std::array<double, 3> bodyAngularVelocity() const = 0;\n\n    /**\n     * Get the linear mixed acceleration of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear mixed acceleration of the link.\n     */\n    virtual std::array<double, 3> worldLinearAcceleration() const = 0;\n\n    /**\n     * Get the angular mixed acceleration of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular mixed acceleration of the link.\n     */\n    virtual std::array<double, 3> worldAngularAcceleration() const = 0;\n\n    /**\n     * Get the linear body acceleration of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear body acceleration of the link.\n     */\n    virtual std::array<double, 3> bodyLinearAcceleration() const = 0;\n\n    /**\n     * Get the angular body acceleration of the link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular body acceleration of the link.\n     */\n    virtual std::array<double, 3> bodyAngularAcceleration() const = 0;\n\n    /**\n     * Check if the contact detection is enabled.\n     *\n     * @return True if the contact detection is enabled, false otherwise.\n     */\n    virtual bool contactsEnabled() const = 0;\n\n    /**\n     * Enable the contact detection.\n     *\n     * @param enable True to enable the contact detection, false to disable.\n     * @return True for success, false otherwise.\n     */\n    virtual bool enableContactDetection(const bool enable) = 0;\n\n    /**\n     * Check if the link has active contacts.\n     *\n     * @return True if the link has at least one contact and contacts are\n     * enabled, false otherwise.\n     */\n    virtual bool inContact() const = 0;\n\n    /**\n     * Get the active contacts of the link.\n     *\n     * @return The vector of active contacts.\n     */\n    virtual std::vector<Contact> contacts() const = 0;\n\n    /**\n     * Get the total wrench generated by the active contacts.\n     *\n     * All the contact wrenches are composed to an equivalent wrench\n     * applied to the origin of the link frame and expressed in world\n     * coordinates.\n     *\n     * @return The total wrench of the active contacts.\n     */\n    virtual std::array<double, 6> contactWrench() const = 0;\n};\n\nstruct scenario::core::Pose\n{\n    Pose() = default;\n    Pose(std::array<double, 3> p, std::array<double, 4> o)\n        : position(p)\n        , orientation(o)\n    {}\n    Pose(std::pair<std::array<double, 3>, std::array<double, 4>> pose)\n        : position(pose.first)\n        , orientation(pose.second)\n    {}\n\n    static Pose Identity() { return {}; }\n\n    bool operator==(const Pose& other) const\n    {\n        return this->position == other.position\n               && this->orientation == other.orientation;\n    }\n\n    bool operator!=(const Pose& other) const { return !(*this == other); }\n\n    std::array<double, 3> position = {0, 0, 0};\n    std::array<double, 4> orientation = {1, 0, 0, 0};\n};\n\nstruct scenario::core::ContactPoint\n{\n    double depth;\n    std::array<double, 3> force;\n    std::array<double, 3> torque;\n    std::array<double, 3> normal;\n    std::array<double, 3> position;\n};\n\nstruct scenario::core::Contact\n{\n    std::string bodyA;\n    std::string bodyB;\n    std::vector<ContactPoint> points;\n};\n\n#endif // SCENARIO_CORE_LINK_H\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/Model.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_MODEL_H\n#define SCENARIO_CORE_MODEL_H\n\n#include \"scenario/core/Joint.h\"\n\n#include <array>\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::core {\n    struct Contact;\n    class Link;\n    class Model;\n    using LinkPtr = std::shared_ptr<Link>;\n    using JointPtr = std::shared_ptr<Joint>;\n    using ModelPtr = std::shared_ptr<Model>;\n} // namespace scenario::core\n\nclass scenario::core::Model\n{\npublic:\n    Model() = default;\n    virtual ~Model() = default;\n\n    /**\n     * Check if the model is valid.\n     *\n     * @return True if the model is valid, false otherwise.\n     */\n    virtual bool valid() const = 0;\n\n    /**\n     * Get the degrees of freedom of the model.\n     *\n     * @param jointNames Optionally restrict the count to a subset of\n     * joints.\n     * @return The number of degrees of freedom of the model.\n     */\n    virtual size_t\n    dofs(const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the name of the model.\n     *\n     * @return The name of the model.\n     */\n    virtual std::string name() const = 0;\n\n    /**\n     * Get the number of links of the model.\n     *\n     * @return The number of links.\n     */\n    virtual size_t nrOfLinks() const = 0;\n\n    /**\n     * Get the number of joints of the model.\n     *\n     * @return The number of joints.\n     */\n    virtual size_t nrOfJoints() const = 0;\n\n    /**\n     * Get the total mass of the model.\n     *\n     * @param linkNames Optionally restrict the count to a subset of links.\n     * @return The total mass of the model.\n     */\n    virtual double\n    totalMass(const std::vector<std::string>& linkNames = {}) const = 0;\n\n    /**\n     * Get a link belonging to the model.\n     *\n     * @param linkName The name of the link.\n     * @throw std::runtime_error if the link does not exist.\n     * @return The desired link.\n     */\n    virtual LinkPtr getLink(const std::string& linkName) const = 0;\n\n    /**\n     * Get a joint belonging to the model.\n     *\n     * @param jointName The name of the joint.\n     * @throw std::runtime_error if the joint does not exist.\n     * @return The desired joint.\n     */\n    virtual JointPtr getJoint(const std::string& jointName) const = 0;\n\n    /**\n     * Get the name of all the model's links.\n     *\n     * @param scoped Scope the link names with the model name\n     * (e.g. ``mymodel::link1``).\n     * @return The list of link names.\n     */\n    virtual std::vector<std::string>\n    linkNames(const bool scoped = false) const = 0;\n\n    /**\n     * Get the name of all the model's joints.\n     *\n     * @param scoped Scope the joint names with the model name,\n     * (e.g. ``mymodel::joint1``).\n     * @return The list of joint names.\n     */\n    virtual std::vector<std::string>\n    jointNames(const bool scoped = false) const = 0;\n\n    /**\n     * Get the controller period of the model.\n     *\n     * If no controller has been enabled, infinite is returned.\n     *\n     * @return The controller period of the model.\n     */\n    virtual double controllerPeriod() const = 0;\n\n    /**\n     * Set the controller period of the model.\n     *\n     * This controller period is used by PIDs and custom controller.\n     * If it is smaller than the physics step, it is treated as 0.\n     *\n     * @param period The desired controller period.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setControllerPeriod(const double period) = 0;\n\n    /**\n     * Enable logging the applied joint forces.\n     *\n     * The output of joint controllers is often a torque. This method allows to\n     * log the force references that the controller sent to the joints. It is\n     * useful when the controller runs in its own thread at its own rate and the\n     * caller wants to extract the forces at a lower frequency.\n     *\n     * @param enable True to enable logging, false to disable.\n     * @param maxHistorySizePerJoint Size of the logging window of each joint.\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool enableHistoryOfAppliedJointForces( //\n        const bool enable = true,\n        const size_t maxHistorySizePerJoint = 100,\n        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Check if logging the applied joint force is enabled.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return True if the log is enabled, false otherwise.\n     */\n    virtual bool historyOfAppliedJointForcesEnabled(\n        const std::vector<std::string>& jointNames) const = 0;\n\n    /**\n     * Get the log of applied joint forces.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The entire window of applied joint forces.\n     *\n     * @note Given a serialization, the window has ``DoFs * JointWindowSize``\n     * elements. The elements are ordered per time steps, i.e. the first\n     * ``#DoFs`` elements refer to the oldest forces of the windows ordered with\n     * the active joint serialization.\n     *\n     * @note If a joint has multiple DoFs, they are serialized contiguously.\n     */\n    virtual std::vector<double> historyOfAppliedJointForces(\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    // ========\n    // Contacts\n    // ========\n\n    /**\n     * Check if the contact detection is enabled model-wise.\n     *\n     * @return True if the contact detection is enabled model-wise, false\n     * otherwise.\n     */\n    virtual bool contactsEnabled() const = 0;\n\n    /**\n     * Enable the contact detection model-wise.\n     *\n     * @param enable True to enable the contact detection model-wise, false\n     * to disable.\n     * @return True for success, false otherwise.\n     */\n    virtual bool enableContacts(const bool enable = true) = 0;\n\n    /**\n     * Get the vector of links with active contacts with other bodies.\n     *\n     * @return The vector of links in contact.\n     */\n    virtual std::vector<std::string> linksInContact() const = 0;\n\n    /**\n     * Get the active contacts of the model.\n     *\n     * @param linkNames Optionally restrict the considered links.\n     * @return A vector of contacts.\n     */\n    virtual std::vector<Contact>\n    contacts(const std::vector<std::string>& linkNames = {}) const = 0;\n\n    // ==================\n    // Vectorized Methods\n    // ==================\n\n    /**\n     * Get the joint positions.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The serialization of joint positions. The vector has as many\n     * elements as DoFs of the considered joints.\n     */\n    virtual std::vector<double> jointPositions( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the joint velocities.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The serialization of joint velocities. The vector has as many\n     * elements as DoFs of the considered joints.\n     */\n    virtual std::vector<double> jointVelocities( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the joint accelerations.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The serialization of joint accelerations. The vector has as many\n     * elements as DoFs of the considered joints.\n     */\n    virtual std::vector<double> jointAccelerations( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the joint generalized forces.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The serialization of joint forces. The vector has as many\n     * elements as DoFs of the considered joints.\n     */\n    virtual std::vector<double> jointGeneralizedForces( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the joint limits of the model.\n     *\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return The joint limits of the model. The vectors of the limit\n     * object have as many elements as DoFs of the considered joints.\n     */\n    virtual JointLimit jointLimits( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Set the control mode of model joints.\n     *\n     * @param mode The desired joint control mode.\n     * @param jointNames Optional vector of considered joints that also\n     * defines the joint serialization. By default, ``Model::jointNames`` is\n     * used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setJointControlMode(const JointControlMode mode,\n                        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Get the links of the model.\n     *\n     * @param linkNames Optional vector of considered links. By default,\n     * ``Model::linkNames`` is used.\n     * @return A vector of pointers to the link objects.\n     */\n    virtual std::vector<LinkPtr> links( //\n        const std::vector<std::string>& linkNames = {}) const = 0;\n\n    /**\n     * Get the joints of the model.\n     *\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return A vector of pointers to the joint objects.\n     */\n    virtual std::vector<JointPtr> joints( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    // =========================\n    // Vectorized Target Methods\n    // =========================\n\n    /**\n     * Set the position targets of the joints.\n     *\n     * @param positions The vector with the joint position targets. It must\n     * have as many elements as the considered joint DoFs.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setJointPositionTargets( //\n        const std::vector<double>& positions,\n        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Set the velocity targets of the joints.\n     *\n     * @param velocities The vector with the joint velocity targets. It must\n     * have as many elements as the considered joint DoFs.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setJointVelocityTargets( //\n        const std::vector<double>& velocities,\n        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Set the acceleration targets of the joints.\n     *\n     * @param accelerations The vector with the joint acceleration targets.\n     * It must have as many elements as the considered joint DoFs.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setJointAccelerationTargets( //\n        const std::vector<double>& accelerations,\n        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Set the generalized force targets of the joints.\n     *\n     * @param forces The vector with the joint generalized force targets. It\n     * must have as many elements as the considered joint DoFs.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setJointGeneralizedForceTargets( //\n        const std::vector<double>& forces,\n        const std::vector<std::string>& jointNames = {}) = 0;\n\n    /**\n     * Get the position targets of the joints.\n     *\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return The position targets of the joints.\n     */\n    virtual std::vector<double> jointPositionTargets( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the velocity targets of the joints.\n     *\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return The velocity targets of the joints.\n     */\n    virtual std::vector<double> jointVelocityTargets( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the acceleration targets of the joints.\n     *\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return The acceleration targets of the joints.\n     */\n    virtual std::vector<double> jointAccelerationTargets( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    /**\n     * Get the generalized force targets of the joints.\n     *\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return The generalized force targets of the joints.\n     */\n    virtual std::vector<double> jointGeneralizedForceTargets( //\n        const std::vector<std::string>& jointNames = {}) const = 0;\n\n    // =========\n    // Base Link\n    // =========\n\n    /**\n     * Get the name of the model's base frame.\n     *\n     * By default, the base frame is typically the root of the kinematic tree of\n     * the model.\n     *\n     * @return The name of the model's base frame.\n     */\n    virtual std::string baseFrame() const = 0;\n\n    /**\n     * Get the position of the base link.\n     *\n     * @return The position of the base link in world coordinates.\n     */\n    virtual std::array<double, 3> basePosition() const = 0;\n\n    /**\n     * Get the orientation of the base link.\n     *\n     * @return The wxyz quaternion defining the orientation of the base link wrt\n     * the world frame.\n     */\n    virtual std::array<double, 4> baseOrientation() const = 0;\n\n    /**\n     * Get the linear body velocity of the base link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear body velocity of the base link.\n     */\n    virtual std::array<double, 3> baseBodyLinearVelocity() const = 0;\n\n    /**\n     * Get the angular body velocity of the base link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular body velocity of the base link.\n     */\n    virtual std::array<double, 3> baseBodyAngularVelocity() const = 0;\n\n    /**\n     * Get the linear mixed velocity of the base link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The linear mixed velocity of the base link.\n     */\n    virtual std::array<double, 3> baseWorldLinearVelocity() const = 0;\n\n    /**\n     * Get the angular mixed velocity of the base link.\n     *\n     * @todo Add link to the velocity representation documentation page.\n     *\n     * @return The angular mixed velocity of the base link.\n     */\n    virtual std::array<double, 3> baseWorldAngularVelocity() const = 0;\n\n    // =================\n    // Base Link Targets\n    // =================\n\n    /**\n     * Set the pose target of the base link.\n     *\n     * @param position The position target of the base link in world\n     * coordinates.\n     * @param orientation The wxyz quaternion defining the orientation target of\n     * the base link wrt the world frame.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setBasePoseTarget(const std::array<double, 3>& position,\n                      const std::array<double, 4>& orientation) = 0;\n\n    /**\n     * Set the position target of the base link.\n     *\n     * @param position The position target of the base link in world\n     * coordinates.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setBasePositionTarget(const std::array<double, 3>& position) = 0;\n\n    /**\n     * Set the orientation target of the base link.\n     *\n     * @param orientation The wxyz quaternion defining the orientation target of\n     * the base link wrt the world frame.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setBaseOrientationTarget(const std::array<double, 4>& orientation) = 0;\n\n    /**\n     * Set the mixed velocity target of the base link.\n     *\n     * @param linear The mixed linear velocity target of the base link.\n     * @param angular The mixed angular velocity target of the base link.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setBaseWorldVelocityTarget(const std::array<double, 3>& linear,\n                               const std::array<double, 3>& angular) = 0;\n\n    /**\n     * Set the mixed linear velocity target of the base link.\n     *\n     * @param linear The mixed linear velocity target of the base link.\n     * @return True for success, false otherwise.\n     */\n    virtual bool\n    setBaseWorldLinearVelocityTarget(const std::array<double, 3>& linear) = 0;\n\n    /**\n     * Set the mixed angular velocity target of the base link.\n     *\n     * @param angular The mixed angular velocity target of the base link.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setBaseWorldAngularVelocityTarget( //\n        const std::array<double, 3>& angular) = 0;\n\n    /**\n     * Set the mixed linear acceleration target of the base link.\n     *\n     * @param linear The mixed linear acceleration target of the base link.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setBaseWorldLinearAccelerationTarget( //\n        const std::array<double, 3>& linear) = 0;\n\n    /**\n     * Set the mixed angular acceleration target of the base link.\n     *\n     * @param angular The mixed angular acceleration target of the base link.\n     * @return True for success, false otherwise.\n     */\n    virtual bool setBaseWorldAngularAccelerationTarget( //\n        const std::array<double, 3>& angular) = 0;\n\n    /**\n     * Get the position target of the base link.\n     *\n     * @return The position target of the base link.\n     */\n    virtual std::array<double, 3> basePositionTarget() const = 0;\n\n    /**\n     * Get the orientation target of the base link.\n     *\n     * @return The quaternion defining the orientation target of the base link.\n     */\n    virtual std::array<double, 4> baseOrientationTarget() const = 0;\n\n    /**\n     * Get the mixed linear velocity target of the base link.\n     *\n     * @return The mixed linear velocity target of the base link.\n     */\n    virtual std::array<double, 3> baseWorldLinearVelocityTarget() const = 0;\n\n    /**\n     * Get the mixed angular velocity target of the base link.\n     *\n     * @return The mixed angular velocity target of the base link.\n     */\n    virtual std::array<double, 3> baseWorldAngularVelocityTarget() const = 0;\n\n    /**\n     * Get the mixed linear acceleration target of the base link.\n     *\n     * @return The mixed linear acceleration target of the base link.\n     */\n    virtual std::array<double, 3> baseWorldLinearAccelerationTarget() const = 0;\n\n    /**\n     * Get the mixed angular acceleration target of the base link.\n     *\n     * @return The mixed angular acceleration target of the base link.\n     */\n    virtual std::array<double, 3>\n    baseWorldAngularAccelerationTarget() const = 0;\n};\n\n#endif // SCENARIO_CORE_MODEL_H\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/World.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_WORLD_H\n#define SCENARIO_CORE_WORLD_H\n\n#include \"scenario/core/Link.h\"\n\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::core {\n    class World;\n    class Model;\n    using ModelPtr = std::shared_ptr<Model>;\n    using WorldPtr = std::shared_ptr<World>;\n} // namespace scenario::core\n\nclass scenario::core::World\n{\npublic:\n    World() = default;\n    virtual ~World() = default;\n\n    /**\n     * Check if the world is valid.\n     *\n     * @return True if the world is valid, false otherwise.\n     */\n    virtual bool valid() const = 0;\n\n    /**\n     * Get the simulated time.\n     *\n     * @note A physics plugin need to be part of the simulation\n     * in order to make the time flow.\n     *\n     * @return The simulated time.\n     */\n    virtual double time() const = 0;\n\n    /**\n     * Get the name of the world.\n     *\n     * @return The name of the world.\n     */\n    virtual std::string name() const = 0;\n\n    /**\n     * Get the gravity vector.\n     * @return The gravity vector.\n     */\n    virtual std::array<double, 3> gravity() const = 0;\n\n    /**\n     * Get the name of the models that are part of the world.\n     *\n     * @return The list of model names.\n     */\n    virtual std::vector<std::string> modelNames() const = 0;\n\n    /**\n     * Get a model part of the world.\n     *\n     * @param modelName The name of the model to get.\n     * @return The model if it is part of the world, ``nullptr`` otherwise.\n     */\n    virtual ModelPtr getModel(const std::string& modelName) const = 0;\n\n    /**\n     * Get the models of the world.\n     *\n     * @param modelNames Optional vector of considered models. By default,\n     * ``World::modelNames`` is used.\n     * @return A vector of pointers to the model objects.\n     */\n    virtual std::vector<ModelPtr> models( //\n        const std::vector<std::string>& modelNames = {}) const = 0;\n};\n\n#endif // SCENARIO_CORE_WORLD_H\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/utils/Log.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_UTILS_LOG\n#define SCENARIO_CORE_UTILS_LOG\n\n// Downstream implementations can override logs and then\n// use the include order to select the right log backend\n#ifndef SCENARIO_LOG_MACROS_DEFINED\n#define SCENARIO_LOG_MACROS_DEFINED\n\n#include <iostream>\n#define sError std::cerr\n#define sWarning std::cerr\n#define sMessage std::cout\n#define sDebug std::cout\n#define sLog std::cout\n\n#endif // SCENARIO_LOG_MACROS_DEFINED\n\n#endif // SCENARIO_CORE_UTILS_LOG\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/utils/signals.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_UTILS_SIGNALS_H\n#define SCENARIO_CORE_UTILS_SIGNALS_H\n\n#include <functional>\n#include <memory>\n\nnamespace scenario::core::utils {\n    class SignalManager;\n} // namespace scenario::core::utils\n\nclass scenario::core::utils::SignalManager\n{\npublic:\n    using SignalType = int;\n    using SignalCallback = std::function<void(int)>;\n\n    SignalManager();\n    ~SignalManager();\n\n    static void ExecuteCallback(SignalType type);\n\n    static SignalManager& Instance();\n    SignalCallback getCallback(const SignalType type) const;\n    SignalCallback setCallback(const SignalType type,\n                               const SignalCallback& callback);\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_CORE_UTILS_SIGNALS_H\n"
  },
  {
    "path": "scenario/src/core/include/scenario/core/utils/utils.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#ifndef SCENARIO_CORE_UTILS_H\n#define SCENARIO_CORE_UTILS_H\n\n#include <string>\n\nnamespace scenario::core::utils {\n    /**\n     * Get the install prefix used by the CMake project.\n     *\n     * @note It is defined only if the project is installed in\n     * Developer mode.\n     *\n     * @return A string with the install prefix if the project is\n     * installed in Developer mode, an empty string otherwise.\n     */\n    std::string getInstallPrefix();\n} // namespace scenario::core::utils\n\n#endif // SCENARIO_CORE_UTILS_H\n"
  },
  {
    "path": "scenario/src/core/src/signals.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#include \"scenario/core/utils/signals.h\"\n#include \"scenario/core/utils/Log.h\"\n\n#include <csignal>\n#include <mutex>\n#include <unordered_map>\n\nnamespace scenario::core::detail {\n    static std::mutex SignalManagerMutex;\n}\n\nusing namespace scenario::core::utils;\n\nclass SignalManager::Impl\n{\npublic:\n    static std::string ToString(const int type);\n    static std::unordered_map<SignalManager::SignalType, std::string>\n        DefaultTypeToName;\n\n    std::unordered_map<SignalType, SignalCallback> callbacks;\n};\n\nSignalManager::SignalManager()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nSignalManager::~SignalManager() = default;\n\nvoid SignalManager::ExecuteCallback(SignalType type)\n{\n    std::lock_guard lock(detail::SignalManagerMutex);\n\n    sDebug << \"Received interrupt signal \" << Impl::ToString(type) << std::endl;\n    auto callback = SignalManager::Instance().getCallback(type);\n\n    if (callback) {\n        sDebug << \"Found signal callback\" << std::endl;\n        callback(type);\n        return;\n    }\n\n    sDebug << \"No callback found\" << std::endl;\n}\n\nSignalManager& SignalManager::Instance()\n{\n    static SignalManager instance;\n    return instance;\n}\n\nSignalManager::SignalCallback\nSignalManager::getCallback(const SignalType type) const\n{\n    if (pImpl->callbacks.find(type) != pImpl->callbacks.end()) {\n        return pImpl->callbacks.at(type);\n    }\n\n    return nullptr;\n}\n\nSignalManager::SignalCallback\nSignalManager::setCallback(const SignalType type,\n                           const SignalManager::SignalCallback& callback)\n{\n    SignalCallback oldCallback = this->getCallback(type);\n\n    std::signal(type, SignalManager::ExecuteCallback);\n    pImpl->callbacks[type] = callback;\n\n    return oldCallback;\n}\n\n// ==============\n// Implementation\n// ==============\n\nstd::string SignalManager::Impl::ToString(const int type)\n{\n    if (DefaultTypeToName.find(type) != DefaultTypeToName.end()) {\n        return DefaultTypeToName.at(type);\n    }\n    else {\n        return std::to_string(type);\n    }\n}\n\nstd::unordered_map<SignalManager::SignalType, std::string>\n    SignalManager::Impl::DefaultTypeToName = {\n        {SIGABRT, \"SIGABRT\"},\n        {SIGFPE, \"SIGFPE\"},\n        {SIGILL, \"SIGILL\"},\n        {SIGINT, \"SIGINT\"},\n        {SIGSEGV, \"SIGSEGV\"},\n        {SIGTERM, \"SIGTERM\"},\n};\n"
  },
  {
    "path": "scenario/src/core/src/utils.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n */\n\n#include \"scenario/core/utils/utils.h\"\n#include \"scenario/core/utils/Log.h\"\n\nusing namespace scenario::core;\n\nstd::string utils::getInstallPrefix()\n{\n#ifdef SCENARIO_CMAKE_INSTALL_PREFIX\n    return SCENARIO_CMAKE_INSTALL_PREFIX;\n#else\n    // The install prefix of the User installation can be computed\n    // from the Python module path\n    return \"\";\n#endif\n}\n"
  },
  {
    "path": "scenario/src/gazebo/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n# All rights reserved.\n#\n#  This project is dual licensed under LGPL v2.1+ or Apache License.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  This software may be modified and distributed under the terms of the\n#  GNU Lesser General Public License v2.1 or any later version.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\n# ================\n# Extra Components\n# ================\n\nset(EXTRA_COMPONENTS_PUBLIC_HEADERS\n    include/scenario/gazebo/components/JointPID.h\n    include/scenario/gazebo/components/SimulatedTime.h\n    include/scenario/gazebo/components/BasePoseTarget.h\n    include/scenario/gazebo/components/BaseWorldVelocityTarget.h\n    include/scenario/gazebo/components/BaseWorldAccelerationTarget.h\n    include/scenario/gazebo/components/JointControlMode.h\n    include/scenario/gazebo/components/JointController.h\n    include/scenario/gazebo/components/JointPositionTarget.h\n    include/scenario/gazebo/components/JointVelocityTarget.h\n    include/scenario/gazebo/components/JointAccelerationTarget.h\n    include/scenario/gazebo/components/HistoryOfAppliedJointForces.h\n    include/scenario/gazebo/components/ExternalWorldWrenchCmdWithDuration.h\n    include/scenario/gazebo/components/Timestamp.h\n    include/scenario/gazebo/components/JointControllerPeriod.h\n    include/scenario/gazebo/components/JointAcceleration.h\n    )\n\nadd_library(ExtraComponents INTERFACE)\nadd_library(ScenarioGazebo::ExtraComponents ALIAS ExtraComponents)\n\ntarget_include_directories(ExtraComponents INTERFACE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\ntarget_link_libraries(ExtraComponents INTERFACE ${ignition-gazebo.core})\n\nset_target_properties(ExtraComponents PROPERTIES\n    PUBLIC_HEADER \"${EXTRA_COMPONENTS_PUBLIC_HEADERS}\")\n\n# https://stackoverflow.com/a/29214327\n# As a workaround target_sources can be used, however it requires more\n# boilerplate code and it has probles when exporting the INTERFACE target:\n# https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/\nadd_custom_target(GazeboExtraComponents SOURCES ${EXTRA_COMPONENTS_PUBLIC_HEADERS})\n\n# ==============\n# ScenarioGazebo\n# ==============\n\nset(SCENARIO_GAZEBO_PUBLIC_HDRS\n    include/scenario/gazebo/GazeboEntity.h\n    include/scenario/gazebo/World.h\n    include/scenario/gazebo/Model.h\n    include/scenario/gazebo/Joint.h\n    include/scenario/gazebo/Link.h\n    include/scenario/gazebo/Log.h\n    include/scenario/gazebo/utils.h\n    include/scenario/gazebo/helpers.h\n    include/scenario/gazebo/exceptions.h)\n\nadd_library(ScenarioGazebo\n    ${SCENARIO_GAZEBO_PUBLIC_HDRS}\n    src/World.cpp\n    src/Model.cpp\n    src/Joint.cpp\n    src/Link.cpp\n    src/utils.cpp\n    src/helpers.cpp)\nadd_library(ScenarioGazebo::ScenarioGazebo ALIAS ScenarioGazebo)\n\ntarget_include_directories(ScenarioGazebo PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\ntarget_link_libraries(ScenarioGazebo\n    PUBLIC\n    ScenarioCore::ScenarioABC\n    ${ignition-gazebo.core}\n    ${ignition-common.ignition-common}\n    PRIVATE\n    ScenarioCore::CoreUtils\n    ScenarioGazebo::ExtraComponents\n    ${ignition-physics.ignition-physics}\n    ${ignition-fuel_tools.ignition-fuel_tools})\n\nset_target_properties(ScenarioGazebo PROPERTIES\n    PUBLIC_HEADER \"${SCENARIO_GAZEBO_PUBLIC_HDRS}\")\n\n# ===============\n# GazeboSimulator\n# ===============\n\nadd_library(GazeboSimulator\n    include/scenario/gazebo/GazeboSimulator.h\n    src/GazeboSimulator.cpp)\nadd_library(ScenarioGazebo::GazeboSimulator ALIAS GazeboSimulator)\n\ntarget_include_directories(GazeboSimulator PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${SCENARIO_INSTALL_INCLUDEDIR}>)\n\ntarget_link_libraries(GazeboSimulator\n    PUBLIC\n    ScenarioCore::ScenarioABC\n    PRIVATE\n    tiny-process-library::tiny-process-library\n    ${ignition-gazebo.core}\n    ScenarioCore::CoreUtils\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioGazebo::ExtraComponents\n    ${ignition-fuel_tools.ignition-fuel_tools})\n\nset_target_properties(GazeboSimulator PROPERTIES\n    PUBLIC_HEADER include/scenario/gazebo/GazeboSimulator.h)\n\n# ===================\n# Install the targets\n# ===================\n\nget_property(TPL_IS_IMPORTED\n    TARGET tiny-process-library::tiny-process-library\n    PROPERTY IMPORTED)\n\nif(TPL_IS_IMPORTED)\n    set(EXPORT_TPL_TARGET)\nelse()\n    set(EXPORT_TPL_TARGET tiny-process-library)\nendif()\n\ninstall(\n    TARGETS\n    ExtraComponents ${EXPORT_TPL_TARGET}\n    EXPORT ScenarioGazeboExport\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION\n    ${SCENARIO_INSTALL_INCLUDEDIR}/scenario/gazebo/components)\n\ninstall(\n    TARGETS\n    ScenarioGazebo GazeboSimulator\n    EXPORT ScenarioGazeboExport\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}\n    PUBLIC_HEADER DESTINATION\n    ${SCENARIO_INSTALL_INCLUDEDIR}/scenario/gazebo)\n\ninstall_basic_package_files(ScenarioGazebo\n    COMPONENT Gazebo\n    VERSION ${PROJECT_VERSION}\n    COMPATIBILITY AnyNewerVersion\n    EXPORT ScenarioGazeboExport\n    DEPENDENCIES ScenarioCore ${ignition-gazebo} ${ignition-common}\n    NAMESPACE ScenarioGazebo::\n    NO_CHECK_REQUIRED_COMPONENTS_MACRO\n    INSTALL_DESTINATION\n    ${SCENARIO_INSTALL_LIBDIR}/cmake/ScenarioGazebo)\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/GazeboEntity.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_GAZEBOENTITY_H\n#define SCENARIO_GAZEBO_GAZEBOENTITY_H\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n\n#include <cstdint>\n\nnamespace scenario::gazebo {\n    class GazeboEntity;\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::GazeboEntity\n{\npublic:\n    GazeboEntity() = default;\n    virtual ~GazeboEntity() = default;\n\n    /**\n     * Get the unique id of the object.\n     *\n     * @note It might differ from the entity number since a multi-world setting\n     * with the same models inserted in the same order would result to same\n     * numbering.\n     *\n     * @return The unique object id. Invalid objects return 0.\n     */\n    virtual uint64_t id() const = 0;\n\n    /**\n     * Initialize the object with entity data.\n     *\n     * @param linkEntity The entity of the ECM.\n     * @param ecm The pointer to the ECM.\n     * @param eventManager The pointer to the EventManager.\n     * @return True for success, false otherwise.\n     */\n    virtual bool initialize(const ignition::gazebo::Entity linkEntity,\n                            ignition::gazebo::EntityComponentManager* ecm,\n                            ignition::gazebo::EventManager* eventManager) = 0;\n\n    /**\n     * Initialize the object.\n     *\n     * @note This method has to be called after ``GazeboEntity::initialize``.\n     *\n     * @return True for success, false otherwise.\n     */\n    virtual bool createECMResources() = 0;\n\n    /**\n     * Return the entity of this object.\n     *\n     * @return The entity that corresponds to this object.\n     */\n    inline ignition::gazebo::Entity entity() const { return this->m_entity; }\n\n    /**\n     * Return the pointer to the event manager.\n     *\n     * @return The pointer to the event manager.\n     */\n    inline ignition::gazebo::EventManager* eventManager() const\n    {\n        return this->m_eventManager;\n    }\n\n    /**\n     * Return the pointer to the Entity Component Manager.\n     *\n     * @return The pointer to the Entity Component Manager.\n     */\n    inline ignition::gazebo::EntityComponentManager* ecm() const\n    {\n        return this->m_ecm;\n    }\n\n    /**\n     * Checks if the GazeboEntity is valid.\n     *\n     * @return True if the GazeboEntity is valid, false otherwise.\n     */\n    inline bool validEntity() const\n    {\n        return m_eventManager && m_ecm\n               && m_entity != ignition::gazebo::kNullEntity;\n    }\n\nprotected:\n    ignition::gazebo::EventManager* m_eventManager = nullptr;\n    ignition::gazebo::EntityComponentManager* m_ecm = nullptr;\n    ignition::gazebo::Entity m_entity = ignition::gazebo::kNullEntity;\n};\n\n#endif // SCENARIO_GAZEBO_GAZEBOENTITY_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/GazeboSimulator.h",
    "content": "/*\n * Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_GAZEBOSIMULATOR_H\n#define SCENARIO_GAZEBO_GAZEBOSIMULATOR_H\n\n#include \"scenario/core/World.h\"\n\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::gazebo {\n    class World;\n    class GazeboSimulator;\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::GazeboSimulator\n{\npublic:\n    /**\n     * Class wrapping the Ignition Gazebo simulator.\n     *\n     * The simulator can execute either unpaused or paused runs. Paused runs\n     * update the internal state of the simulator without stepping the physics.\n     * This is useful to process e.g. model insertions or removals.\n     * Every simulator run can execute one or more physics steps, depending on\n     * how it is configured when constructed.\n     *\n     * @param stepSize The size of the physics step.\n     * @param rtf The desired real-time factor.\n     * @param stepsPerRun Number of steps to execute at each simulator run.\n     */\n    GazeboSimulator(const double stepSize = 0.001,\n                    const double rtf = 1.0,\n                    const size_t stepsPerRun = 1);\n    virtual ~GazeboSimulator();\n\n    /**\n     * Get the size of a simulator step.\n     *\n     * @return The simulator step size in seconds.\n     */\n    double stepSize() const;\n\n    /**\n     * Get the desired real-time factor of the simulator.\n     *\n     * @return The desired real-time factor.\n     */\n    double realTimeFactor() const;\n\n    /**\n     * Get the number or steps to execute every simulator run.\n     *\n     * @return The configured number of steps per run.\n     */\n    size_t stepsPerRun() const;\n\n    /**\n     * Initialize the simulator.\n     *\n     * @return True for success, false otherwise.\n     */\n    bool initialize();\n\n    /**\n     * Check if the simulator has been initialized.\n     *\n     * @return True if the simulator was initialized, false otherwise.\n     */\n    bool initialized() const;\n\n    /**\n     * Run the simulator.\n     *\n     * @param paused True to perform paused steps that do not affect the\n     * physics, false for normal steps. The number of steps configured during\n     * construction are executed.\n     * @return True for success, false otherwise.\n     */\n    bool run(const bool paused = false);\n\n    /**\n     * Open the Ignition Gazebo GUI.\n     *\n     * @param verbosity Configure the verbosity of the GUI (0-4)\n     * @return True for success, false otherwise.\n     */\n    bool gui(const int verbosity = -1);\n\n    /**\n     * Close the simulator and the GUI.\n     *\n     * @return True for success, false otherwise.\n     */\n    bool close();\n\n    /**\n     * Pause the simulator.\n     *\n     * @note This method is useful in non-deterministic mode, which is not\n     * currently supported.\n     *\n     * @return True for success, false otherwise.\n     */\n    bool pause();\n\n    /**\n     * Check if the simulator is running.\n     *\n     * @note This method is useful in non-deterministic mode, which is not\n     * currently supported.\n     *\n     * @return True for success, false otherwise.\n     */\n    bool running() const;\n\n    /**\n     * Load a SDF world file.\n     *\n     * @note If the world file is not passed, the default empty world is\n     * inserted. The default empty world does not have the ground plane nor\n     * any physics. Both can be added by operating on the ``World`` object.\n     *\n     * @note This function can only be used while the simulator object is\n     * uninitialized.\n     *\n     * @param worldFile The path to the SDF world file.\n     * @param worldName Optionally override the name of the world defined in the\n     * SDF world file.\n     * @return True for success, false otherwise.\n     */\n    bool insertWorldFromSDF(const std::string& worldFile = \"\",\n                            const std::string& worldName = \"\");\n\n    /**\n     * Load a SDF world file containing multiple worlds.\n     *\n     * @param worldFile The path to the SDF world file.\n     * @param worldNames Optionally override the names of the worlds defined in\n     * the SDF world file.\n     * @return True for success, false otherwise.\n     *\n     * @warning This is an experimental feature. Multiworld simulations are only\n     * partially supported by Ignition Gazebo.\n     */\n    bool insertWorldsFromSDF(const std::string& worldFile,\n                             const std::vector<std::string>& worldNames = {});\n\n    /**\n     * Get the list if the world names part of the simulation.\n     *\n     * @return The world names.\n     */\n    std::vector<std::string> worldNames() const;\n\n    /**\n     * Get a simulated world.\n     *\n     * @param worldName The name of the desired world.\n     * @return The world object.\n     */\n    std::shared_ptr<scenario::gazebo::World>\n    getWorld(const std::string& worldName = \"\") const;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_GAZEBO_GAZEBOSIMULATOR_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/Joint.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_JOINT_H\n#define SCENARIO_GAZEBO_JOINT_H\n\n#include \"scenario/core/Joint.h\"\n#include \"scenario/gazebo/GazeboEntity.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::gazebo {\n    class Joint;\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::Joint final\n    : public scenario::core::Joint\n    , public scenario::gazebo::GazeboEntity\n    , public std::enable_shared_from_this<scenario::gazebo::Joint>\n{\npublic:\n    Joint();\n    virtual ~Joint();\n\n    // =============\n    // Gazebo Entity\n    // =============\n\n    uint64_t id() const override;\n\n    bool initialize(const ignition::gazebo::Entity jointEntity,\n                    ignition::gazebo::EntityComponentManager* ecm,\n                    ignition::gazebo::EventManager* eventManager) override;\n\n    bool createECMResources() override;\n\n    // ============\n    // Gazebo Joint\n    // ============\n\n    /**\n     * Insert a Ignition Gazebo plugin to the joint.\n     *\n     * @param libName The library name of the plugin.\n     * @param className The class name (or alias) of the plugin.\n     * @param context Optional XML plugin context.\n     * @return True for success, false otherwise.\n     */\n    bool insertJointPlugin(const std::string& libName,\n                           const std::string& className,\n                           const std::string& context = {});\n\n    /**\n     * Reset the position of a joint DOF.\n     *\n     * @param position The desired position.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    bool resetPosition(const double position = 0, const size_t dof = 0);\n\n    /**\n     * Reset the velocity of a joint DOF.\n     *\n     * @param velocity The desired velocity.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    bool resetVelocity(const double velocity = 0, const size_t dof = 0);\n\n    /**\n     * Reset the state of a joint DOF.\n     *\n     * This method also resets the PID state of the joint.\n     *\n     * @param position The desired position.\n     * @param velocity The desired velocity.\n     * @param dof The index of the DOF.\n     * @return True for success, false otherwise.\n     */\n    bool reset(const double position = 0,\n               const double velocity = 0,\n               const size_t dof = 0);\n\n    /**\n     * Reset the position of the joint.\n     *\n     * This method also resets the PID state of the joint.\n     *\n     * @param position The desired position.\n     * @return True for success, false otherwise.\n     */\n    bool resetJointPosition(const std::vector<double>& position);\n\n    /**\n     * Reset the velocity of the joint.\n     *\n     * This method also resets the PID state of the joint.\n     *\n     * @param velocity The desired velocity.\n     * @return True for success, false otherwise.\n     */\n    bool resetJointVelocity(const std::vector<double>& velocity);\n\n    /**\n     * Reset the state of the joint.\n     *\n     * This method also resets the PID state of the joint.\n     *\n     * @param position The desired position.\n     * @param velocity The desired velocity.\n     * @return True for success, false otherwise.\n     */\n    bool resetJoint(const std::vector<double>& position,\n                    const std::vector<double>& velocity);\n\n    /**\n     * Set the Coulomb friction parameter of the joint.\n     *\n     * @note Friction can be changed only before the first simulated step\n     * after model insertion.\n     *\n     * @param value The new Coulomb friction value.\n     * @return True for success, false otherwise.\n     */\n    bool setCoulombFriction(const double value);\n\n    /**\n     * Set the viscous friction parameter of the joint.\n     *\n     * @note Friction can be changed only before the first simulated step\n     * after model insertion.\n     *\n     * @param value The new viscous friction value.\n     * @return True for success, false otherwise.\n     */\n    bool setViscousFriction(const double value);\n\n    // ==========\n    // Joint Core\n    // ==========\n\n    bool valid() const override;\n\n    size_t dofs() const override;\n\n    std::string name(const bool scoped = false) const override;\n\n    core::JointType type() const override;\n\n    core::JointControlMode controlMode() const override;\n\n    bool setControlMode(const core::JointControlMode mode) override;\n\n    double controllerPeriod() const override;\n\n    core::PID pid() const override;\n\n    bool setPID(const core::PID& pid) override;\n\n    bool historyOfAppliedJointForcesEnabled() const override;\n\n    bool enableHistoryOfAppliedJointForces(\n        const bool enable = true,\n        const size_t maxHistorySize = 100) override;\n\n    std::vector<double> historyOfAppliedJointForces() const override;\n\n    double coulombFriction() const override;\n\n    double viscousFriction() const override;\n\n    // ==================\n    // Single DOF methods\n    // ==================\n\n    core::Limit positionLimit(const size_t dof = 0) const override;\n\n    core::Limit velocityLimit(const size_t dof = 0) const override;\n\n    bool setVelocityLimit(const double maxVelocity,\n                          const size_t dof = 0) override;\n\n    double maxGeneralizedForce(const size_t dof = 0) const override;\n\n    bool setMaxGeneralizedForce(const double maxForce,\n                                const size_t dof = 0) override;\n\n    double position(const size_t dof = 0) const override;\n\n    double velocity(const size_t dof = 0) const override;\n\n    double acceleration(const size_t dof = 0) const override;\n\n    double generalizedForce(const size_t dof = 0) const override;\n\n    bool setPositionTarget(const double position,\n                           const size_t dof = 0) override;\n\n    bool setVelocityTarget(const double velocity,\n                           const size_t dof = 0) override;\n\n    bool setAccelerationTarget(const double acceleration,\n                               const size_t dof = 0) override;\n\n    bool setGeneralizedForceTarget(const double force,\n                                   const size_t dof = 0) override;\n\n    double positionTarget(const size_t dof = 0) const override;\n\n    double velocityTarget(const size_t dof = 0) const override;\n\n    double accelerationTarget(const size_t dof = 0) const override;\n\n    double generalizedForceTarget(const size_t dof = 0) const override;\n\n    // =================\n    // Multi DOF methods\n    // =================\n\n    core::JointLimit jointPositionLimit() const override;\n\n    core::JointLimit jointVelocityLimit() const override;\n\n    bool setJointVelocityLimit(const std::vector<double>& maxVelocity) override;\n\n    std::vector<double> jointMaxGeneralizedForce() const override;\n\n    bool setJointMaxGeneralizedForce( //\n        const std::vector<double>& maxForce) override;\n\n    std::vector<double> jointPosition() const override;\n\n    std::vector<double> jointVelocity() const override;\n\n    std::vector<double> jointAcceleration() const override;\n\n    std::vector<double> jointGeneralizedForce() const override;\n\n    bool setJointPositionTarget(const std::vector<double>& position) override;\n\n    bool setJointVelocityTarget(const std::vector<double>& velocity) override;\n\n    bool setJointAccelerationTarget(\n        const std::vector<double>& acceleration) override;\n\n    bool setJointGeneralizedForceTarget( //\n        const std::vector<double>& force) override;\n\n    std::vector<double> jointPositionTarget() const override;\n\n    std::vector<double> jointVelocityTarget() const override;\n\n    std::vector<double> jointAccelerationTarget() const override;\n\n    std::vector<double> jointGeneralizedForceTarget() const override;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_GAZEBO_JOINT_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/Link.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_LINK_H\n#define SCENARIO_GAZEBO_LINK_H\n\n#include \"scenario/core/Link.h\"\n#include \"scenario/gazebo/GazeboEntity.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n\n#include <array>\n#include <memory>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace scenario::gazebo {\n    class Link;\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::Link final\n    : public scenario::core::Link\n    , public scenario::gazebo::GazeboEntity\n    , public std::enable_shared_from_this<scenario::gazebo::Link>\n{\npublic:\n    Link();\n    virtual ~Link();\n\n    // =============\n    // Gazebo Entity\n    // =============\n\n    uint64_t id() const override;\n\n    bool initialize(const ignition::gazebo::Entity linkEntity,\n                    ignition::gazebo::EntityComponentManager* ecm,\n                    ignition::gazebo::EventManager* eventManager) override;\n\n    bool createECMResources() override;\n\n    // ===========\n    // Gazebo Link\n    // ===========\n\n    /**\n     * Insert a Ignition Gazebo plugin to the link.\n     *\n     * @param libName The library name of the plugin.\n     * @param className The class name (or alias) of the plugin.\n     * @param context Optional XML plugin context.\n     * @return True for success, false otherwise.\n     */\n    bool insertLinkPlugin(const std::string& libName,\n                          const std::string& className,\n                          const std::string& context = {});\n\n    // =========\n    // Link Core\n    // =========\n\n    bool valid() const override;\n\n    std::string name(const bool scoped = false) const override;\n\n    double mass() const override;\n\n    std::array<double, 3> position() const override;\n\n    std::array<double, 4> orientation() const override;\n\n    std::array<double, 3> worldLinearVelocity() const override;\n\n    std::array<double, 3> worldAngularVelocity() const override;\n\n    std::array<double, 3> bodyLinearVelocity() const override;\n\n    std::array<double, 3> bodyAngularVelocity() const override;\n\n    std::array<double, 3> worldLinearAcceleration() const override;\n\n    std::array<double, 3> worldAngularAcceleration() const override;\n\n    std::array<double, 3> bodyLinearAcceleration() const override;\n\n    std::array<double, 3> bodyAngularAcceleration() const override;\n\n    bool contactsEnabled() const override;\n\n    bool enableContactDetection(const bool enable) override;\n\n    bool inContact() const override;\n\n    std::vector<core::Contact> contacts() const override;\n\n    std::array<double, 6> contactWrench() const override;\n\n    // ===========\n    // Gazebo Link\n    // ===========\n\n    /**\n     * Apply a force to the link.\n     *\n     * The force is applied to the origin of the link frame.\n     *\n     * @param force The force to apply expressed in world coordinates.\n     * @param duration The duration of the application of the force.\n     * By default the force is applied for a single physics step.\n     * @return True for success, false otherwise.\n     */\n    bool applyWorldForce(const std::array<double, 3>& force,\n                         const double duration = 0.0);\n\n    /**\n     * Apply a torque to the link.\n     *\n     * The force is applied to the origin of the link frame.\n     *\n     * @param torque The torque to apply expressed in world coordinates.\n     * @param duration The duration of the application of the torque.\n     * By default the torque is applied for a single physics step.\n     * @return True for success, false otherwise.\n     */\n    bool applyWorldTorque(const std::array<double, 3>& torque,\n                          const double duration = 0.0);\n\n    /**\n     * Apply a wrench to the link.\n     *\n     * The force is applied to the origin of the link frame.\n     *\n     * @param force The force to apply expressed in world coordinates.\n     * @param torque The torque to apply expressed in world coordinates.\n     * @param duration The duration of the application of the wrench.\n     * By default the wrench is applied for a single physics step.\n     * @return True for success, false otherwise.\n     */\n    bool applyWorldWrench(const std::array<double, 3>& force,\n                          const std::array<double, 3>& torque,\n                          const double duration = 0.0);\n\n    /**\n     * Apply a wrench to the CoM of the link.\n     *\n     * @note This method considers the CoM being positioned in the origin of\n     * the inertial frame as it is defined in the SDF description of the model.\n     * Note that if not explicitly specified, inertial and link frames match.\n     * In this case, `applyWorldWrench` and `applyWorldWrenchToCoM` effects\n     * will be the same.\n     *\n     * @param force The force to apply expressed in world coordinates.\n     * @param torque The torque to apply expressed in world coordinates.\n     * @param duration The duration of the application of the wrench.\n     * By default the wrench is applied for a single physics step.\n     * @return True for success, false otherwise.\n     */\n    bool applyWorldWrenchToCoM(const std::array<double, 3>& force,\n                               const std::array<double, 3>& torque,\n                               const double duration = 0.0);\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_GAZEBO_LINK_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/Log.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_LOG\n#define SCENARIO_GAZEBO_LOG\n\n#ifndef SCENARIO_LOG_MACROS_DEFINED\n#define SCENARIO_LOG_MACROS_DEFINED\n\n#include <ignition/common/Console.hh>\n#define sError ::ignition::common::Console::err(__FILE__, __LINE__)\n#define sWarning ::ignition::common::Console::warn(__FILE__, __LINE__)\n#define sMessage ::ignition::common::Console::msg(__FILE__, __LINE__)\n#define sDebug ::ignition::common::Console::dbg(__FILE__, __LINE__)\n#define sLog ::ignition::common::Console::log(__FILE__, __LINE__)\n\n#endif // SCENARIO_LOG_MACROS_DEFINED\n\n#endif // SCENARIO_GAZEBO_LOG\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/Model.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_MODEL_H\n#define SCENARIO_GAZEBO_MODEL_H\n\n#include \"scenario/core/Model.h\"\n#include \"scenario/gazebo/GazeboEntity.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n\n#include <array>\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::gazebo {\n    class Model;\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::Model final\n    : public scenario::core::Model\n    , public scenario::gazebo::GazeboEntity\n    , public std::enable_shared_from_this<scenario::gazebo::Model>\n{\npublic:\n    Model();\n    virtual ~Model();\n\n    // =============\n    // Gazebo Entity\n    // =============\n\n    uint64_t id() const override;\n\n    bool initialize(const ignition::gazebo::Entity modelEntity,\n                    ignition::gazebo::EntityComponentManager* ecm,\n                    ignition::gazebo::EventManager* eventManager) override;\n    bool createECMResources() override;\n\n    // ============\n    // Gazebo Model\n    // ============\n\n    /**\n     * Insert a Ignition Gazebo plugin to the model.\n     *\n     * @param libName The library name of the plugin.\n     * @param className The class name (or alias) of the plugin.\n     * @param context Optional XML plugin context.\n     * @return True for success, false otherwise.\n     */\n    bool insertModelPlugin(const std::string& libName,\n                           const std::string& className,\n                           const std::string& context = {});\n\n    /**\n     * Reset the positions of the joints.\n     *\n     * @param positions The desired new joint positions.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    bool resetJointPositions( //\n        const std::vector<double>& positions,\n        const std::vector<std::string>& jointNames = {});\n\n    /**\n     * Reset the velocities of the joints.\n     *\n     * @param velocities The desired new velocities positions.\n     * @param jointNames Optional vector of considered joints. By default,\n     * ``Model::jointNames`` is used.\n     * @return True for success, false otherwise.\n     */\n    bool resetJointVelocities( //\n        const std::vector<double>& velocities,\n        const std::vector<std::string>& jointNames = {});\n\n    /**\n     * Reset the pose of the base link.\n     *\n     * @param position The desired position of the base link in world\n     * coordinates.\n     * @param orientation The wxyz quaternion defining the desired orientation\n     * of the base link wrt the world frame.\n     * @return True for success, false otherwise.\n     */\n    bool resetBasePose(const std::array<double, 3>& position = {0, 0, 0},\n                       const std::array<double, 4>& orientation = {0, 0, 0, 0});\n\n    /**\n     * Reset the position of the base link.\n     *\n     * @param position The desired position of the base link in world\n     * coordinates.\n     * @return True for success, false otherwise.\n     */\n    bool resetBasePosition(const std::array<double, 3>& position = {0, 0, 0});\n\n    /**\n     * Reset the orientation of the base link.\n     *\n     * @param orientation The wxyz quaternion defining the desired orientation\n     * of the base link wrt the world frame.\n     * @return True for success, false otherwise.\n     */\n    bool resetBaseOrientation(\n        const std::array<double, 4>& orientation = {0, 0, 0, 0});\n\n    /**\n     * Reset the linear mixed velocity of the base link.\n     *\n     * @param linear The desired linear mixed velocity of the base link.\n     * @return True for success, false otherwise.\n     */\n    bool resetBaseWorldLinearVelocity(\n        const std::array<double, 3>& linear = {0, 0, 0});\n\n    /**\n     * Reset the angular mixed velocity of the base link.\n     *\n     * @param angular The desired angular mixed velocity of the base link.\n     * @return True for success, false otherwise.\n     */\n    bool resetBaseWorldAngularVelocity(\n        const std::array<double, 3>& angular = {0, 0, 0});\n\n    /**\n     * Reset the mixed velocity of the base link.\n     *\n     * @param linear The desired linear mixed velocity of the base link.\n     * @param angular The desired angular mixed velocity of the base link.\n     * @return True for success, false otherwise.\n     */\n    bool resetBaseWorldVelocity( //\n        const std::array<double, 3>& linear = {0, 0, 0},\n        const std::array<double, 3>& angular = {0, 0, 0});\n\n    /**\n     * Check if the detection of self-collisions is enabled.\n     *\n     * @return True if self-collisions detection is enabled, false\n     * otherwise.\n     */\n    bool selfCollisionsEnabled() const;\n\n    /**\n     * Enable the detection of self-collisions.\n     *\n     * It will enable contact detection if it was disabled.\n     *\n     * @param enable True to enable the self-collision detection, false to\n     * disable.\n     * @return True for success, false otherwise.\n     */\n    bool enableSelfCollisions(const bool enable = true);\n\n    // ==========\n    // Model Core\n    // ==========\n\n    bool valid() const override;\n\n    size_t dofs(const std::vector<std::string>& jointNames = {}) const override;\n\n    std::string name() const override;\n\n    size_t nrOfLinks() const override;\n\n    size_t nrOfJoints() const override;\n\n    double\n    totalMass(const std::vector<std::string>& linkNames = {}) const override;\n\n    core::LinkPtr getLink(const std::string& linkName) const override;\n\n    core::JointPtr getJoint(const std::string& jointName) const override;\n\n    std::vector<std::string>\n    linkNames(const bool scoped = false) const override;\n\n    std::vector<std::string>\n    jointNames(const bool scoped = false) const override;\n\n    double controllerPeriod() const override;\n\n    bool setControllerPeriod(const double period) override;\n\n    bool enableHistoryOfAppliedJointForces(\n        const bool enable = true,\n        const size_t maxHistorySizePerJoint = 100,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    bool historyOfAppliedJointForcesEnabled(\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> historyOfAppliedJointForces(\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    // ========\n    // Contacts\n    // ========\n\n    bool contactsEnabled() const override;\n\n    bool enableContacts(const bool enable = true) override;\n\n    std::vector<std::string> linksInContact() const override;\n\n    std::vector<core::Contact>\n    contacts(const std::vector<std::string>& linkNames = {}) const override;\n\n    // ==================\n    // Vectorized Methods\n    // ==================\n\n    std::vector<double> jointPositions( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointVelocities( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointAccelerations( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointGeneralizedForces( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    core::JointLimit jointLimits( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    bool setJointControlMode( //\n        const core::JointControlMode mode,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    std::vector<core::LinkPtr> links( //\n        const std::vector<std::string>& linkNames = {}) const override;\n\n    std::vector<core::JointPtr> joints( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    // =========================\n    // Vectorized Target Methods\n    // =========================\n\n    bool setJointPositionTargets( //\n        const std::vector<double>& positions,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    bool setJointVelocityTargets( //\n        const std::vector<double>& velocities,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    bool setJointAccelerationTargets( //\n        const std::vector<double>& accelerations,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    bool setJointGeneralizedForceTargets( //\n        const std::vector<double>& forces,\n        const std::vector<std::string>& jointNames = {}) override;\n\n    std::vector<double> jointPositionTargets( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointVelocityTargets( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointAccelerationTargets( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    std::vector<double> jointGeneralizedForceTargets( //\n        const std::vector<std::string>& jointNames = {}) const override;\n\n    // =========\n    // Base Link\n    // =========\n\n    std::string baseFrame() const override;\n\n    std::array<double, 3> basePosition() const override;\n\n    std::array<double, 4> baseOrientation() const override;\n\n    std::array<double, 3> baseBodyLinearVelocity() const override;\n\n    std::array<double, 3> baseBodyAngularVelocity() const override;\n\n    std::array<double, 3> baseWorldLinearVelocity() const override;\n\n    std::array<double, 3> baseWorldAngularVelocity() const override;\n\n    // =================\n    // Base Link Targets\n    // =================\n\n    bool setBasePoseTarget( //\n        const std::array<double, 3>& position,\n        const std::array<double, 4>& orientation) override;\n\n    bool setBasePositionTarget( //\n        const std::array<double, 3>& position) override;\n\n    bool setBaseOrientationTarget( //\n        const std::array<double, 4>& orientation) override;\n\n    bool setBaseWorldVelocityTarget( //\n        const std::array<double, 3>& linear,\n        const std::array<double, 3>& angular) override;\n\n    bool setBaseWorldLinearVelocityTarget( //\n        const std::array<double, 3>& linear) override;\n\n    bool setBaseWorldAngularVelocityTarget( //\n        const std::array<double, 3>& angular) override;\n\n    bool setBaseWorldLinearAccelerationTarget( //\n        const std::array<double, 3>& linear) override;\n\n    bool setBaseWorldAngularAccelerationTarget( //\n        const std::array<double, 3>& angular) override;\n\n    std::array<double, 3> basePositionTarget() const override;\n\n    std::array<double, 4> baseOrientationTarget() const override;\n\n    std::array<double, 3> baseWorldLinearVelocityTarget() const override;\n\n    std::array<double, 3> baseWorldAngularVelocityTarget() const override;\n\n    std::array<double, 3> baseWorldLinearAccelerationTarget() const override;\n\n    std::array<double, 3> baseWorldAngularAccelerationTarget() const override;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_GAZEBO_MODEL_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/World.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_WORLD_H\n#define SCENARIO_GAZEBO_WORLD_H\n\n#include \"scenario/core/World.h\"\n#include \"scenario/gazebo/GazeboEntity.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n\n#include <array>\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace scenario::gazebo {\n    class World;\n\n    /**\n     * Supported physics engines.\n     */\n    enum class PhysicsEngine\n    {\n        /// The physics engine included in the Dynamic Animation and Robotics\n        /// Toolkit.\n        Dart,\n    };\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::World final\n    : public scenario::core::World\n    , public scenario::gazebo::GazeboEntity\n    , public std::enable_shared_from_this<scenario::gazebo::World>\n{\npublic:\n    World();\n    virtual ~World();\n\n    // =============\n    // Gazebo Entity\n    // =============\n\n    uint64_t id() const override;\n\n    bool initialize(const ignition::gazebo::Entity worldEntity,\n                    ignition::gazebo::EntityComponentManager* ecm,\n                    ignition::gazebo::EventManager* eventManager) override;\n\n    bool createECMResources() override;\n\n    // ============\n    // Gazebo World\n    // ============\n\n    /**\n     * Insert a Ignition Gazebo plugin to the world.\n     *\n     * @param libName The library name of the plugin.\n     * @param className The class name (or alias) of the plugin.\n     * @param context Optional XML plugin context.\n     * @return True for success, false otherwise.\n     */\n    bool insertWorldPlugin(const std::string& libName,\n                           const std::string& className,\n                           const std::string& context = {});\n\n    /**\n     * Set the physics engine of the world.\n     *\n     * By default, if the world file does not already contain a physics\n     * plugin, no physics is loaded by default. This method allows to\n     * insert in the simulator a plugin with one of the supported physics\n     * engines.\n     *\n     * @param engine The desired physics engine.\n     * @return True for success, false otherwise.\n     */\n    bool setPhysicsEngine(const PhysicsEngine engine);\n\n    /**\n     * Set the gravity of the world.\n     *\n     * @note This method must be called after setting the physics engine and\n     * before performing any physics step.\n     *\n     * @param gravity The desired gravity vector.\n     * @return True for success, false otherwise.\n     */\n    bool setGravity(const std::array<double, 3>& gravity);\n\n    /**\n     * Load a model from the given path and insert it into the world.\n     *\n     * This function is a shim over InsertModelFromFile for backwards\n     * compatibility.\n     *\n     * @param modelFile A path to the URDF or SDF file to load and insert.\n     * @param pose The optional initial pose of the model.\n     * @param overrideModelName The optional name of the model. This is the name\n     * used to get the model with ``World::getModel``.\n     * @return True for success, false otherwise.\n     *\n     * @note The default pose and model name are those specified in the robot\n     * description. If the pose is not specified, the identity is used.\n     *\n     * @warning In order to process the model insertion, a simulator step must\n     * be executed. It could either be a paused or unpaused step.\n     */\n    bool insertModel(const std::string& modelFile,\n                     const core::Pose& pose = core::Pose::Identity(),\n                     const std::string& overrideModelName = {});\n\n    /**\n     * Load a model from the given path and insert it into the world.\n     *\n     * @param path A path to the URDF or SDF file to load and insert.\n     * @param pose The optional initial pose of the model.\n     * @param overrideModelName The optional name of the model. This is the name\n     * used to get the model with ``World::getModel``.\n     * @return True for success, false otherwise.\n     *\n     * @note The default pose and model name are those specified in the robot\n     * description. If the pose is not specified, the identity is used.\n     *\n     * @warning In order to process the model insertion, a simulator step must\n     * be executed. It could either be a paused or unpaused step.\n     */\n    bool insertModelFromFile(const std::string& path,\n                             const core::Pose& pose = core::Pose::Identity(),\n                             const std::string& overrideModelName = {});\n\n    /**\n     * Load a model from the given string and insert it into the world.\n     *\n     * @param sdfString A string containing the model's SDF/URDF XML.\n     * @param pose The optional initial pose of the model.\n     * @param overrideModelName The optional name of the model. This is the name\n     * used to get the model with ``World::getModel``.\n     * @return True for success, false otherwise.\n     *\n     * @note The default pose and model name are those specified in the robot\n     * description. If the pose is not specified, the identity is used.\n     *\n     * @warning In order to process the model insertion, a simulator step must\n     * be executed. It could either be a paused or unpaused step.\n     */\n    bool insertModelFromString(const std::string& sdfString,\n                               const core::Pose& pose = core::Pose::Identity(),\n                               const std::string& overrideModelName = {});\n\n    /**\n     * Remove a model from the world.\n     *\n     * @param modelName The name of the model to remove.\n     * @return True for success, false otherwise.\n     *\n     * @warning In order to process the model removal, a simulator step must\n     * be executed. It could either be a paused or unpaused step.\n     */\n    bool removeModel(const std::string& modelName);\n\n    // ==========\n    // World Core\n    // ==========\n\n    bool valid() const override;\n\n    double time() const override;\n\n    std::string name() const override;\n\n    std::array<double, 3> gravity() const override;\n\n    std::vector<std::string> modelNames() const override;\n\n    scenario::core::ModelPtr\n    getModel(const std::string& modelName) const override;\n\n    std::vector<core::ModelPtr> models( //\n        const std::vector<std::string>& modelNames = {}) const override;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_GAZEBO_WORLD_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/BasePoseTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_BASEPOSETARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_BASEPOSETARGET_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n#include <ignition/math/Pose3.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Base pose target used by floating base controllers.\n            using BasePoseTarget =\n                Component<ignition::math::Pose3d, class BasePoseTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.BasePoseTarget\",\n                BasePoseTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_BASEPOSETARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/BaseWorldAccelerationTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_BASEWORLDACCELERATIONTARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_BASEWORLDACCELERATIONTARGET_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n#include <ignition/math/Vector3.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Base world linear acceleration target used by\n            ///        floating base controllers.\n            using BaseWorldLinearAccelerationTarget =\n                Component<math::Vector3d,\n                          class BaseWorldLinearAccelerationTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.BaseWorldLinearAccelerationTarget\",\n                BaseWorldLinearAccelerationTarget)\n\n            /// \\brief Base world angular acceleration target used by\n            ///        floating base controllers.\n            using BaseWorldAngularAccelerationTarget =\n                Component<math::Vector3d,\n                          class BaseWorldAngularAccelerationTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.\"\n                \"BaseWorldAngularAccelerationTargetTarget\",\n                BaseWorldAngularAccelerationTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_BASEWORLDACCELERATIONTARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/BaseWorldVelocityTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_BASEWORLDVELOCITYTARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_BASEWORLDVELOCITYTARGET_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n#include <ignition/math/Vector3.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Base world linear velocity target used by\n            ///        floating base controllers.\n            using BaseWorldLinearVelocityTarget =\n                Component<math::Vector3d,\n                          class BaseWorldLinearVelocityTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.BaseWorldLinearVelocityTarget\",\n                BaseWorldLinearVelocityTarget)\n\n            /// \\brief Base world angular velocity target used by\n            ///        floating base controllers.\n            using BaseWorldAngularVelocityTarget =\n                Component<math::Vector3d,\n                          class BaseWorldAngularVelocityTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.\"\n                \"BaseWorldAngularVelocityTargetTarget\",\n                BaseWorldAngularVelocityTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_BASEWORLDVELOCITYTARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/ExternalWorldWrenchCmdWithDuration.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_EXTERNALWORLDWRENCHCMDWITHDURATION_H\n#define IGNITION_GAZEBO_COMPONENTS_EXTERNALWORLDWRENCHCMDWITHDURATION_H\n\n#include \"scenario/gazebo/helpers.h\"\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\n#include <chrono>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief A component type that contains the external wrench to be\n            ///        applied for a given duration on an entity expressed in\n            ///        the world frame and represented by\n            ///        ignition::msgs::Wrench. Currently this is used for\n            ///        applying wrenches on links. Although the msg::Wrench type\n            ///        has a force_offset member, the value is currently\n            ///        ignored. Instead, the force is applied at the link\n            ///        origin. The wrench uses SI units (N for force and N⋅m for\n            ///        torque).\n            using ExternalWorldWrenchCmdWithDuration =\n                Component<scenario::gazebo::utils::LinkWrenchCmd,\n                          class ExternalWorldWrenchCmdWithDurationTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.ExternalWorldWrenchCmdWithDuration\",\n                ExternalWorldWrenchCmdWithDuration)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_EXTERNALWORLDWRENCHCMDWITHDURATION_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/HistoryOfAppliedJointForces.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_HISTORYOFAPPLIEDJOINTFORCES_H\n#define IGNITION_GAZEBO_COMPONENTS_HISTORYOFAPPLIEDJOINTFORCES_H\n\n#include \"scenario/gazebo/helpers.h\"\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Fixed-size queue that stores a window of applied joint\n            ///        forces.\n            ///\n            /// The queue is associated to a joint and it is filled at each\n            /// physics step with as many values as degrees of freedom.\n            using HistoryOfAppliedJointForces =\n                Component<scenario::gazebo::utils::FixedSizeQueue,\n                          class HistoryOfAppliedJointForcesTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.HistoryOfAppliedJointForces\",\n                HistoryOfAppliedJointForces)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_HISTORYOFAPPLIEDJOINTFORCES_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointAcceleration.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATION_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATION_H\n\n#include <vector>\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition {\n    namespace gazebo {\n        // Inline bracket to help doxygen filtering.\n        inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n            namespace components {\n                /// \\brief Joint acceleration in SI units (rad/s/s for revolute,\n                /// m/s/s for prismatic). The component wraps a std::vector of\n                /// size equal to the degrees of freedom of the joint.\n                using JointAcceleration =\n                    Component<std::vector<double>,\n                              class JointAccelerationTag,\n                              serializers::VectorDoubleSerializer>;\n                IGN_GAZEBO_REGISTER_COMPONENT(\n                    \"ign_gazebo_components.JointAcceleration\",\n                    JointAcceleration)\n            } // namespace components\n        } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n    } // namespace gazebo\n} // namespace ignition\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATION_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointAccelerationTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATIONTARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATIONTARGET_H\n\n#include <vector>\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Joint acceleration target in SI units (rad/s/s for\n            ///        revolute, m/s/s for prismatic) used by joint\n            ///        controllers.\n            ///\n            /// The component wraps a std::vector of size equal to the\n            /// degrees of freedom of the joint.\n            using JointAccelerationTarget =\n                Component<std::vector<double>,\n                          class JointAccelerationTargetTag,\n                          serializers::VectorDoubleSerializer>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointAccelerationTarget\",\n                JointAccelerationTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTACCELERATIONTARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointControlMode.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLMODE_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLMODE_H\n\n#include \"scenario/gazebo/Joint.h\"\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace serializers {\n            class JointControlModeSerializer;\n        } // namespace serializers\n\n        namespace components {\n            /// \\brief Joint control mode.\n            using JointControlMode = Component<scenario::core::JointControlMode,\n                                               class JointControlModeTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointControlMode\",\n                JointControlMode)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLMODE_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointController.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLER_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLER_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Marks whether a model has a JointController plugin.\n            using JointController = Component<bool, class JointControllerTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointController\",\n                JointController)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLER_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointControllerPeriod.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLERPERIOD_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLERPERIOD_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n\n#include <chrono>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Joint controller period in seconds.\n            using JointControllerPeriod =\n                Component<std::chrono::steady_clock::duration,\n                          class JointControllerPeriodTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointControllerPeriod\",\n                JointControllerPeriod)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTCONTROLLERPERIOD_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointPID.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTPID_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTPID_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n#include <ignition/math/PID.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Joint PID controller.\n            using JointPID = Component<ignition::math::PID, class JointPIDTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\"ign_gazebo_components.JointPID\",\n                                          JointPID)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTPID_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointPositionTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTPOSITIONTARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTPOSITIONTARGET_H\n\n#include <vector>\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Joint position target in SI units (rad for revolute,\n            ///        m for prismatic) used by joint controllers.\n            ///\n            /// The component wraps a std::vector of size equal to the\n            /// degrees of freedom of the joint.\n            using JointPositionTarget =\n                Component<std::vector<double>, class JointPositionTargetTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointPositionTarget\",\n                JointPositionTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTPOSITIONTARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/JointVelocityTarget.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_JOINTVELOCITYTARGET_H\n#define IGNITION_GAZEBO_COMPONENTS_JOINTVELOCITYTARGET_H\n\n#include <vector>\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/components/Serialization.hh>\n#include <ignition/gazebo/config.hh>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief Joint velocity target in SI units (rad/s for\n            ///        revolute, m/s for prismatic) used by joint\n            ///        controllers.\n            ///\n            /// The component wraps a std::vector of size equal to the\n            /// degrees of freedom of the joint.\n            using JointVelocityTarget =\n                Component<std::vector<double>,\n                          class JointVelocityTargetTag,\n                          serializers::VectorDoubleSerializer>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\n                \"ign_gazebo_components.JointVelocityTarget\",\n                JointVelocityTarget)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_JOINTVELOCITYTARGET_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/SimulatedTime.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_SIMULATEDTIME_H\n#define IGNITION_GAZEBO_COMPONENTS_SIMULATEDTIME_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\n#include <chrono>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief A component that holds the world's simulated time in\n            ///        seconds.\n            using SimulatedTime = Component<std::chrono::steady_clock::duration,\n                                            class SimulatedTimeTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\"ign_gazebo_components.SimulatedTime\",\n                                          SimulatedTime)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_SIMULATEDTIME_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/components/Timestamp.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef IGNITION_GAZEBO_COMPONENTS_TIMESTAMP_H\n#define IGNITION_GAZEBO_COMPONENTS_TIMESTAMP_H\n\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Factory.hh>\n#include <ignition/gazebo/config.hh>\n\n#include <chrono>\n\nnamespace ignition::gazebo {\n    // Inline bracket to help doxygen filtering.\n    inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\n        namespace components {\n            /// \\brief A component that could store a timestamp.\n            using Timestamp = Component<std::chrono::steady_clock::duration,\n                                        class TimestampTag>;\n            IGN_GAZEBO_REGISTER_COMPONENT(\"ign_gazebo_components.Timestamp\",\n                                          Timestamp)\n        } // namespace components\n    } // namespace IGNITION_GAZEBO_VERSION_NAMESPACE\n} // namespace ignition::gazebo\n\n#endif // IGNITION_GAZEBO_COMPONENTS_TIMESTAMP_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/exceptions.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_EXCEPTIONS_H\n#define SCENARIO_GAZEBO_EXCEPTIONS_H\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/Types.hh>\n#include <ignition/gazebo/components/Factory.hh>\n\n#include <cstring>\n#include <stdexcept>\n#include <string>\n\nnamespace scenario::gazebo {\n    namespace exceptions {\n        class LinkError;\n        class JointError;\n        class ModelError;\n        class DOFMismatch;\n        class LinkNotFound;\n        class JointNotFound;\n        class ModelNotFound;\n        class ComponentNotFound;\n        class NotImplementedError;\n    } // namespace exceptions\n} // namespace scenario::gazebo\n\nclass scenario::gazebo::exceptions::LinkError : public std::runtime_error\n{\nprivate:\n    std::string linkName;\n\npublic:\n    explicit LinkError(const std::string& msg, const std::string& linkName = {})\n        : std::runtime_error(msg)\n        , linkName(linkName)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string prefix;\n\n        if (!linkName.empty()) {\n            prefix = \"[\" + linkName + \"] \";\n        }\n\n        std::string what = prefix + std::runtime_error::what();\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::JointError : public std::runtime_error\n{\nprivate:\n    std::string jointName;\n\npublic:\n    explicit JointError(const std::string& msg,\n                        const std::string& jointName = {})\n        : std::runtime_error(msg)\n        , jointName(jointName)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string prefix;\n\n        if (!jointName.empty()) {\n            prefix = \"[\" + jointName + \"] \";\n        }\n\n        std::string what = prefix + std::runtime_error::what();\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::ModelError : public std::runtime_error\n{\nprivate:\n    std::string modelName;\n\npublic:\n    explicit ModelError(const std::string& msg,\n                        const std::string& modelName = {})\n        : std::runtime_error(msg)\n        , modelName(modelName)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string prefix;\n\n        if (!modelName.empty()) {\n            prefix = \"[\" + modelName + \"] \";\n        }\n\n        std::string what = prefix + std::runtime_error::what();\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::DOFMismatch : public std::runtime_error\n{\nprivate:\n    size_t dataDoFs;\n    size_t jointDoFs;\n    std::string jointName;\n\npublic:\n    explicit DOFMismatch(const size_t jointDoFs,\n                         const size_t dataDoFs,\n                         const std::string& jointName = {})\n        : std::runtime_error(\"\")\n        , jointDoFs(jointDoFs)\n        , dataDoFs(dataDoFs)\n        , jointName(jointName)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string prefix;\n\n        if (!jointName.empty()) {\n            prefix = \"[\" + jointName + \"] \";\n        }\n\n        std::string what = prefix\n                           + \"Nr of DoFs joint=\" + std::to_string(jointDoFs)\n                           + \" data=\" + std::to_string(dataDoFs);\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::LinkNotFound : public std::runtime_error\n{\npublic:\n    explicit LinkNotFound(const std::string& error)\n        : std::runtime_error(error)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string linkName = std::runtime_error::what();\n        std::string prefix = \"[\" + linkName + \"] \";\n        std::string what = prefix + \"Link does not exist\";\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::JointNotFound : public std::runtime_error\n{\npublic:\n    explicit JointNotFound(const std::string& error)\n        : std::runtime_error(error)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string jointName = std::runtime_error::what();\n        std::string prefix = \"[\" + jointName + \"] \";\n        std::string what = prefix + \"Joint does not exist\";\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::ModelNotFound : public std::runtime_error\n{\npublic:\n    explicit ModelNotFound(const std::string& error)\n        : std::runtime_error(error)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string modelName = std::runtime_error::what();\n        std::string prefix = \"[\" + modelName + \"] \";\n        std::string what = prefix + \"Model does not exist\";\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::NotImplementedError\n    : public std::logic_error\n{\npublic:\n    explicit NotImplementedError(const std::string& symbol)\n        : std::logic_error(symbol)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string symbol = std::logic_error::what();\n        std::string what = \"Symbol not implemented: \" + symbol;\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\nclass scenario::gazebo::exceptions::ComponentNotFound\n    : public std::runtime_error\n{\n    ignition::gazebo::Entity entity;\n    ignition::gazebo::ComponentTypeId id;\n\npublic:\n    explicit ComponentNotFound(\n        const ignition::gazebo::ComponentTypeId id,\n        const ignition::gazebo::Entity entity = ignition::gazebo::kNullEntity)\n        : std::runtime_error(\"\")\n        , entity(entity)\n        , id(id)\n    {}\n\n    const char* what() const noexcept override\n    {\n        std::string prefix;\n\n        if (entity != ignition::gazebo::kNullEntity) {\n            prefix = \"[Entity=\" + std::to_string(entity) + \"] \";\n        }\n\n        // Get the name of the component from the factory\n        std::string componentName =\n            ignition::gazebo::components::Factory::Instance()->Name(id);\n\n        // Build the message\n        std::string what = prefix + \"Component not found: \" + componentName;\n\n        char* ptr = new char[what.size() + 1];\n        strcpy(ptr, what.c_str());\n\n        return ptr;\n    }\n};\n\n#endif // SCENARIO_GAZEBO_EXCEPTIONS_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/helpers.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_HELPERS_H\n#define SCENARIO_GAZEBO_HELPERS_H\n\n#include \"scenario/gazebo/Joint.h\"\n#include \"scenario/gazebo/Link.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/exceptions.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/math/PID.hh>\n#include <ignition/math/Pose3.hh>\n#include <ignition/math/Quaternion.hh>\n#include <ignition/math/Vector3.hh>\n#include <ignition/math/Vector4.hh>\n#include <ignition/msgs/Utility.hh>\n#include <ignition/msgs/contacts.pb.h>\n#include <ignition/msgs/vector3d.pb.h>\n#include <ignition/msgs/wrench.pb.h>\n#include <sdf/Element.hh>\n#include <sdf/Joint.hh>\n#include <sdf/Root.hh>\n\n#include <algorithm>\n#include <array>\n#include <chrono>\n#include <deque>\n#include <functional>\n#include <memory>\n#include <stdexcept>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace scenario::gazebo::utils {\n\n    std::shared_ptr<sdf::Root>\n    getSdfRootFromFile(const std::string& sdfFileName);\n    std::shared_ptr<sdf::Root>\n    getSdfRootFromString(const std::string& sdfString);\n\n    const std::string ScenarioVerboseEnvVar = \"SCENARIO_VERBOSE\";\n    bool verboseFromEnvironment();\n\n    std::chrono::steady_clock::duration\n    doubleToSteadyClockDuration(const double durationInSeconds);\n\n    double steadyClockDurationToDouble(\n        const std::chrono::steady_clock::duration duration);\n\n    void rowMajorToColumnMajor(std::vector<double>& input,\n                               const long rows,\n                               const long cols);\n\n    bool parentModelJustCreated(const GazeboEntity& gazeboEntity);\n\n    class FixedSizeQueue\n    {\n    public:\n        FixedSizeQueue(const size_t size = 100)\n            : m_size(size)\n            , m_deque(size, 0.0)\n        {}\n\n        void push(const double value)\n        {\n            if (m_deque.size() == m_size) {\n                m_deque.pop_front();\n            }\n\n            m_deque.push_back(value);\n        }\n\n        void resize(const size_t newSize)\n        {\n            m_size = newSize;\n            m_deque = std::deque<double>(newSize, 0.0);\n        }\n\n        inline std::vector<double> toStdVector() const\n        {\n            return {m_deque.begin(), m_deque.end()};\n        }\n\n    private:\n        size_t m_size;\n        std::deque<double> m_deque;\n    };\n\n    template <typename ComponentTypeT, typename ComponentDataTypeT>\n    auto getComponent(ignition::gazebo::EntityComponentManager* ecm,\n                      const ignition::gazebo::Entity entity,\n                      ComponentDataTypeT defaultValue = {});\n\n    template <typename ComponentTypeT>\n    auto getExistingComponent(ignition::gazebo::EntityComponentManager* ecm,\n                              const ignition::gazebo::Entity entity);\n\n    template <typename ComponentTypeT>\n    auto getComponentData(ignition::gazebo::EntityComponentManager* ecm,\n                          const ignition::gazebo::Entity entity)\n        -> decltype(ComponentTypeT().Data());\n\n    template <typename ComponentTypeT>\n    auto getExistingComponentData(ignition::gazebo::EntityComponentManager* ecm,\n                                  const ignition::gazebo::Entity entity)\n        -> decltype(ComponentTypeT().Data());\n\n    scenario::core::Pose\n    fromIgnitionPose(const ignition::math::Pose3d& ignitionPose);\n\n    ignition::math::Pose3d toIgnitionPose(const scenario::core::Pose& pose);\n\n    scenario::core::Contact\n    fromIgnitionContactMsgs(ignition::gazebo::EntityComponentManager* ecm,\n                            const ignition::msgs::Contact& contactMsg);\n\n    std::vector<scenario::core::Contact>\n    fromIgnitionContactsMsgs(ignition::gazebo::EntityComponentManager* ecm,\n                             const ignition::msgs::Contacts& contactsMsg);\n\n    sdf::World renameSDFWorld(const sdf::World& world,\n                              const std::string& newWorldName);\n\n    bool renameSDFModel(sdf::Root& sdfRoot, const std::string& newModelName);\n\n    bool updateSDFPhysics(sdf::Root& sdfRoot,\n                          const double maxStepSize,\n                          const double rtf,\n                          const double realTimeUpdateRate,\n                          const size_t worldIndex = 0);\n\n    sdf::ElementPtr getPluginSDFElement(const std::string& libName,\n                                        const std::string& className);\n\n    sdf::JointType toSdf(const scenario::core::JointType type);\n    scenario::core::JointType fromSdf(const sdf::JointType sdfType);\n\n    ignition::math::Vector3d fromModelToBaseLinearVelocity(\n        const ignition::math::Vector3d& linModelVelocity,\n        const ignition::math::Vector3d& angModelVelocity,\n        const ignition::math::Pose3d& M_H_B,\n        const ignition::math::Quaterniond& W_R_B);\n\n    ignition::math::Vector3d fromBaseToModelLinearVelocity(\n        const ignition::math::Vector3d& linBaseVelocity,\n        const ignition::math::Vector3d& angBaseVelocity,\n        const ignition::math::Pose3d& M_H_B,\n        const ignition::math::Quaterniond& W_R_B);\n\n    std::shared_ptr<World> getParentWorld(const GazeboEntity& gazeboEntity);\n\n    std::shared_ptr<Model> getParentModel(const GazeboEntity& gazeboEntity);\n\n    template <typename ComponentType>\n    ignition::gazebo::Entity getFirstParentEntityWithComponent(\n        ignition::gazebo::EntityComponentManager* ecm,\n        const ignition::gazebo::Entity entity)\n    {\n        ignition::gazebo::Entity candidateEntity = entity;\n\n        auto hasComponent = [&]() -> bool {\n            return ecm->EntityHasComponentType(candidateEntity,\n                                               ComponentType::typeId);\n        };\n\n        auto isNull = [&]() -> bool {\n            return candidateEntity == ignition::gazebo::kNullEntity;\n        };\n\n        while (!(hasComponent() || isNull())) {\n            candidateEntity = ecm->ParentEntity(candidateEntity);\n        }\n\n        return candidateEntity;\n    }\n\n    template <typename T>\n    auto defaultEqualityOperator(const T& a, const T& b) -> bool\n    {\n        return a == b;\n    }\n\n    template <typename ComponentTypeT, typename ComponentDataTypeT>\n    auto setComponentData(\n        ignition::gazebo::EntityComponentManager* ecm,\n        const ignition::gazebo::Entity entity,\n        const ComponentDataTypeT& data,\n        const std::function<bool(const ComponentDataTypeT& a,\n                                 const ComponentDataTypeT& b)>& eql =\n            defaultEqualityOperator<ComponentDataTypeT>);\n\n    template <typename ComponentTypeT, typename ComponentDataTypeT>\n    auto setExistingComponentData(\n        ignition::gazebo::EntityComponentManager* ecm,\n        const ignition::gazebo::Entity entity,\n        const ComponentDataTypeT& data,\n        const std::function<bool(const ComponentDataTypeT& a,\n                                 const ComponentDataTypeT& b)>& eql =\n            defaultEqualityOperator<ComponentDataTypeT>);\n\n    static inline std::array<double, 3>\n    fromIgnitionVector(const ignition::math::Vector3d& ignitionVector)\n    {\n        return {ignitionVector.X(), ignitionVector.Y(), ignitionVector.Z()};\n    }\n\n    static inline std::array<double, 4> fromIgnitionQuaternion(\n        const ignition::math::Quaterniond& ignitionQuaternion)\n    {\n        return {ignitionQuaternion.W(),\n                ignitionQuaternion.X(),\n                ignitionQuaternion.Y(),\n                ignitionQuaternion.Z()};\n    }\n\n    static inline ignition::math::Vector3d\n    toIgnitionVector3(const std::array<double, 3>& vector)\n    {\n        return {vector[0], vector[1], vector[2]};\n    }\n\n    static inline ignition::math::Vector4d\n    toIgnitionVector4(const std::array<double, 4>& vector)\n    {\n        return {vector[0], vector[1], vector[2], vector[3]};\n    }\n\n    static inline ignition::math::Quaterniond\n    toIgnitionQuaternion(const std::array<double, 4>& vector)\n    {\n        return {vector[0], vector[1], vector[2], vector[3]};\n    }\n\n    static inline ignition::math::PID\n    toIgnitionPID(const scenario::core::PID& pid)\n    {\n        return {pid.p,\n                pid.i,\n                pid.d,\n                pid.iMax,\n                pid.iMin,\n                pid.cmdMax,\n                pid.cmdMin,\n                pid.cmdOffset};\n    }\n\n    static inline scenario::core::PID\n    fromIgnitionPID(const ignition::math::PID& pid)\n    {\n        scenario::core::PID pidScenario(pid.PGain(), pid.IGain(), pid.DGain());\n        pidScenario.cmdMin = pid.CmdMin();\n        pidScenario.cmdMax = pid.CmdMax();\n        pidScenario.cmdOffset = pid.CmdOffset();\n        pidScenario.iMin = pid.IMin();\n        pidScenario.iMax = pid.IMax();\n\n        return pidScenario;\n    }\n\n    class WrenchWithDuration\n    {\n    public:\n        WrenchWithDuration(\n            const ignition::msgs::Wrench& wrench,\n            const std::chrono::steady_clock::duration& duration,\n            const std::chrono::steady_clock::duration& curSimTime)\n            : m_wrench(wrench)\n            , m_expiration(curSimTime + duration)\n        {}\n\n        WrenchWithDuration(\n            const ignition::math::Vector3d& force,\n            const ignition::math::Vector3d& torque,\n            const std::chrono::steady_clock::duration& duration,\n            const std::chrono::steady_clock::duration& curSimTime)\n            : m_expiration(curSimTime + duration)\n        {\n            ignition::msgs::Set(m_wrench.mutable_force(), force);\n            ignition::msgs::Set(m_wrench.mutable_torque(), torque);\n        }\n\n        WrenchWithDuration(\n            const std::array<double, 3>& force,\n            const std::array<double, 3>& torque,\n            const std::chrono::steady_clock::duration& duration,\n            const std::chrono::steady_clock::duration& curSimTime)\n            : WrenchWithDuration(toIgnitionVector3(force),\n                                 toIgnitionVector3(torque),\n                                 duration,\n                                 curSimTime)\n        {}\n\n        const ignition::msgs::Vector3d& force() const\n        {\n            return m_wrench.force();\n        }\n\n        const ignition::msgs::Vector3d& torque() const\n        {\n            return m_wrench.torque();\n        }\n\n        const std::chrono::steady_clock::duration& expiration()\n        {\n            return m_expiration;\n        }\n\n        inline bool\n        expired(const std::chrono::steady_clock::duration& curSimTime) const\n        {\n            return curSimTime >= m_expiration;\n        }\n\n    private:\n        ignition::msgs::Wrench m_wrench;\n        std::chrono::steady_clock::duration m_expiration;\n    };\n\n    class LinkWrenchCmd\n    {\n    public:\n        LinkWrenchCmd() = default;\n\n        bool empty() const { return m_wrenches.empty(); }\n\n        inline void addWorldWrench(const WrenchWithDuration& wrench)\n        {\n            m_wrenches.push_back(wrench);\n        }\n\n        inline ignition::msgs::Wrench totalWrench() const\n        {\n            using namespace ignition;\n\n            msgs::Wrench totalWrench;\n            msgs::Set(totalWrench.mutable_force(), {0, 0, 0});\n            msgs::Set(totalWrench.mutable_torque(), {0, 0, 0});\n\n            for (const auto& wrench : m_wrenches) {\n                const auto force = msgs::Convert(wrench.force());\n                const auto torque = msgs::Convert(wrench.torque());\n                const auto tmpForce = msgs::Convert(totalWrench.force());\n                const auto tmpTorque = msgs::Convert(totalWrench.torque());\n\n                msgs::Set(totalWrench.mutable_force(), tmpForce + force);\n                msgs::Set(totalWrench.mutable_torque(), tmpTorque + torque);\n            }\n\n            return totalWrench;\n        }\n\n        void cleanExpired(const std::chrono::steady_clock::duration& now)\n        {\n            if (m_wrenches.empty())\n                return;\n\n            // Remove the expired wrenches\n            m_wrenches.erase( //\n                std::remove_if(m_wrenches.begin(),\n                               m_wrenches.end(),\n                               [&](const WrenchWithDuration& w) {\n                                   return w.expired(now);\n                               }),\n                m_wrenches.end());\n        }\n\n    private:\n        std::vector<WrenchWithDuration> m_wrenches;\n    };\n} // namespace scenario::gazebo::utils\n\ntemplate <typename ComponentTypeT, typename ComponentDataTypeT>\nauto scenario::gazebo::utils::getComponent(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity,\n    ComponentDataTypeT defaultValue)\n{\n    if (!ecm) {\n        throw std::runtime_error(\"ECM pointer not valid\");\n    }\n\n    auto* component = ecm->Component<ComponentTypeT>(entity);\n\n    if (!component) {\n        ecm->CreateComponent(entity, ComponentTypeT(defaultValue));\n        component = ecm->Component<ComponentTypeT>(entity);\n    }\n\n    return component;\n}\n\ntemplate <typename ComponentTypeT>\nauto scenario::gazebo::utils::getExistingComponent(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity)\n{\n    if (!ecm) {\n        throw std::runtime_error(\"ECM pointer not valid\");\n    }\n\n    auto* component = ecm->Component<ComponentTypeT>(entity);\n\n    if (!component) {\n        throw exceptions::ComponentNotFound(ComponentTypeT::typeId, entity);\n    }\n\n    return component;\n}\n\ntemplate <typename ComponentTypeT>\nauto scenario::gazebo::utils::getComponentData(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity) -> decltype(ComponentTypeT().Data())\n{\n    using ComponentDataType =\n        typename std::remove_reference<decltype(ComponentTypeT().Data())>::type;\n\n    auto component =\n        getComponent<ComponentTypeT, ComponentDataType>(ecm, entity);\n\n    return component->Data();\n}\n\ntemplate <typename ComponentTypeT>\nauto scenario::gazebo::utils::getExistingComponentData(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity) -> decltype(ComponentTypeT().Data())\n{\n    auto component = getExistingComponent<ComponentTypeT>(ecm, entity);\n\n    return component->Data();\n}\n\ntemplate <typename ComponentTypeT, typename ComponentDataTypeT>\nauto scenario::gazebo::utils::setComponentData(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity,\n    const ComponentDataTypeT& data,\n    const std::function<bool(const ComponentDataTypeT&,\n                             const ComponentDataTypeT&)>& eql)\n{\n    auto component =\n        utils::getComponent<ComponentTypeT, ComponentDataTypeT>(ecm, entity);\n\n    component->SetData(data, eql);\n}\n\ntemplate <typename ComponentTypeT, typename ComponentDataTypeT>\nauto scenario::gazebo::utils::setExistingComponentData(\n    ignition::gazebo::EntityComponentManager* ecm,\n    const ignition::gazebo::Entity entity,\n    const ComponentDataTypeT& data,\n    const std::function<bool(const ComponentDataTypeT&,\n                             const ComponentDataTypeT&)>& eql)\n{\n    auto component = utils::getExistingComponent<ComponentTypeT>(ecm, entity);\n    component->SetData(data, eql);\n}\n\n#endif // SCENARIO_GAZEBO_HELPERS_H\n"
  },
  {
    "path": "scenario/src/gazebo/include/scenario/gazebo/utils.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_GAZEBO_UTILS_H\n#define SCENARIO_GAZEBO_UTILS_H\n\n#include \"scenario/gazebo/GazeboEntity.h\"\n#include <memory>\n#include <string>\n#include <vector>\n\n#ifdef NDEBUG\n#define DEFAULT_VERBOSITY Verbosity::Warning\n#else\n#define DEFAULT_VERBOSITY Verbosity::Debug\n#endif\n\nnamespace scenario::base {\n    class Model;\n}\n\nnamespace scenario::gazebo {\n    class Model;\n}\n\nnamespace scenario::gazebo::utils {\n    enum class Verbosity\n    {\n        SuppressAll = 0,\n        Error = 1,\n        Warning = 2,\n        Info = 3,\n        Debug = 4,\n    };\n\n    /**\n     * Set the verbosity process-wise.\n     *\n     * Accepted levels are the following:\n     *\n     * - ``Verbosity::SuppressAll``: No messages.\n     * - ``Verbosity::Error``: Error messages.\n     * - ``Verbosity::Warning``: Error and warning messages.\n     * - ``Verbosity::Info``: Error, warning, and info messages.\n     * - ``Verbosity::Debug``: Error, warning, info, and debug messages.\n     *\n     * If called without specifying the level, it will use\n     * ``Verbosity::Warning`` or ``Verbosity::Debug`` depending if the project\n     * was compiled respectively with Release or Debug flags.\n     *\n     * @param level The verbosity level.\n     */\n    void setVerbosity(const Verbosity level = DEFAULT_VERBOSITY);\n\n    /**\n     * Find a SDF file in the filesystem.\n     *\n     * The search path is defined with the ``IGN_GAZEBO_RESOURCE_PATH``\n     * environment variable.\n     *\n     * @param fileName The SDF file name.\n     * @return The absolute path to the file if found, an empty string\n     *         otherwise.\n     */\n    std::string findSdfFile(const std::string& fileName);\n\n    /**\n     * Check if a SDF string is valid.\n     *\n     * An SDF string could contain for instance an SDF model or\n     * an SDF world, and it is valid if it can be parsed successfully\n     * by the SDFormat library.\n     *\n     * @param sdfString The SDF string to check.\n     * @return True if the SDF string is valid, false otherwise.\n     */\n    bool sdfStringValid(const std::string& sdfString);\n\n    /**\n     * Get an SDF string from a SDF file.\n     *\n     * @param fileName An SDF file. It could be either an absolute path\n     *        to the file or the file name if the parent folder is part\n     *        of the ``IGN_GAZEBO_RESOURCE_PATH`` environment variable.\n     * @return The SDF string if the file was found and is valid, an\n     *         empty string otherwise.\n     */\n    std::string getSdfString(const std::string& fileName);\n\n    /**\n     * Get the name of a model from a SDF file.\n     *\n     * @note sdformat supports only one model per SDF file.\n     *\n     * @param fileName An SDF file. It could be either an absolute path\n     *        to the file or the file name if the parent folder is part\n     *        of the ``IGN_GAZEBO_RESOURCE_PATH`` environment variable.\n     * @return The name of the model if the file was found and is valid,\n     *         an empty string otherwise.\n     */\n    std::string getModelNameFromSdf(const std::string& fileName);\n\n    /**\n     * Get the name of a world from a SDF file.\n     *\n     * @param fileName An SDF file. It could be either an absolute path\n     *        to the file or the file name if the parent folder is part\n     *        of the ``IGN_GAZEBO_RESOURCE_PATH`` environment variable.\n     * @param worldIndex The index of the world in the SDF file. By\n     *        default it finds the first world.\n     * @return The name of the world if the file was found and is valid,\n     *         an empty string otherwise.\n     */\n    std::string getWorldNameFromSdf(const std::string& fileName,\n                                    const size_t worldIndex = 0);\n\n    /**\n     * Return a SDF string with an empty world.\n     *\n     * An empty world only has a sun and the default DART\n     * physics profile enabled.\n     *\n     * @note The empty world does not have any ground plane.\n     *\n     * @return A SDF string with the empty world.\n     */\n    std::string getEmptyWorld();\n\n    /**\n     * Get a SDF model file from a Fuel URI.\n     *\n     * @note A valid URI has the following form:\n     * https://fuel.ignitionrobotics.org/openrobotics/models/model_name\n     *\n     * @param URI A valid Fuel URI.\n     * @param useCache Load the model from the local cache.\n     * @return The absolute path to the SDF model.\n     */\n    std::string getModelFileFromFuel(const std::string& URI,\n                                     const bool useCache = false);\n\n    /**\n     * Generate a random alpha numeric string.\n     *\n     * @param length The length of the string.\n     * @return The random string.\n     */\n    std::string getRandomString(const size_t length);\n\n    /**\n     * Convert a URDF file to a SDF string.\n     *\n     * @param urdfFile The absolute path to the URDF file.\n     * @return The SDF string if the file exists and it was successfully\n     *         converted, an empty string otherwise.\n     */\n    std::string URDFFileToSDFString(const std::string& urdfFile);\n\n    /**\n     * Convert a URDF string to a SDF string.\n     *\n     * @param urdfFile A URDF string.\n     * @return The SDF string if the URDF string was successfully\n     *         converted, an empty string otherwise.\n     */\n    std::string URDFStringToSDFString(const std::string& urdfString);\n\n    /**\n     * Normalize a vector in [-1, 1].\n     *\n     * The normalization applies the following equation, where\n     * \\f$ v \\f$ is the input, \\f$ l \\f$ and \\f$ h \\f$ are respectively\n     * the lower and higher limits:\n     *\n     * \\f$ v_{normalized} = 2 \\frac{v - l}{h - l} - 1 \\f$\n     *\n     * The input, low and high arguments are broadcasted to a common\n     * size. Refer to the following for broadcasting definition:\n     *\n     * https://numpy.org/doc/stable/user/basics.broadcasting.html\n     *\n     * @note If the lower limit matches the higher limit, the\n     * corresponding input value is not normalized.\n     *\n     * @param input The input vector.\n     * @param low The lower limit.\n     * @param high The higher limit.\n     * @throw std::invalid_argument If the arguments cannot be\n     * broadcasted.\n     * @return The normalized input.\n     */\n    std::vector<double> normalize(const std::vector<double>& input,\n                                  const std::vector<double>& low,\n                                  const std::vector<double>& high);\n\n    /**\n     * Denormalize a vector from [-1, 1].\n     *\n     * The denormalization applies the following equation, where\n     * \\f$ v \\f$ is the input, \\f$ l \\f$ and \\f$ h \\f$ are respectively\n     * the lower and higher limits:\n     *\n     * \\f$ v_{denormalized} = \\frac{1}{2} (v + 1)(h - l) - l \\f$\n     *\n     * The input, low and high arguments are broadcasted to a common\n     * size. Refer to the following for broadcasting definition:\n     *\n     * https://numpy.org/doc/stable/user/basics.broadcasting.html\n     *\n     * @param input The input vector.\n     * @param low The lower limit.\n     * @param high The higher limit.\n     * @throw std::invalid_argument If the arguments cannot be\n     * broadcasted.\n     * @return The denormalized input.\n     */\n    std::vector<double> denormalize(const std::vector<double>& input,\n                                    const std::vector<double>& low,\n                                    const std::vector<double>& high);\n\n    /**\n     * Insert a plugin to any Gazebo entity.\n     *\n     * @note This function will not return true if the plugin is successful.\n     * This function just triggers an event that notifies the server to load a\n     * plugin, and it does not receive any return value that could be used to\n     * assess the outcome.\n     *\n     * @param gazeboEntity The Gazebo entity (world, model, joint, ...).\n     * @param libName The name of the plugin library.\n     * @param className The name of the class implementing the plugin.\n     * @param context The optional plugin SDF context.\n     * @return True if the entity is valid, false otherwise.\n     */\n    bool insertPluginToGazeboEntity(const GazeboEntity& gazeboEntity,\n                                    const std::string& libName,\n                                    const std::string& className,\n                                    const std::string& context = \"\");\n} // namespace scenario::gazebo::utils\n\n#endif // SCENARIO_GAZEBO_UTILS_H\n"
  },
  {
    "path": "scenario/src/gazebo/src/GazeboSimulator.cpp",
    "content": "/*\n * Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/GazeboSimulator.h\"\n#include \"process.hpp\"\n#include \"scenario/core/utils/signals.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/components/SimulatedTime.h\"\n#include \"scenario/gazebo/components/Timestamp.h\"\n#include \"scenario/gazebo/helpers.h\"\n#include \"scenario/gazebo/utils.h\"\n\n#include <ignition/fuel_tools.hh>\n#include <ignition/gazebo/Server.hh>\n#include <ignition/gazebo/ServerConfig.hh>\n#include <ignition/gazebo/Util.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/Physics.hh>\n#include <ignition/gazebo/components/PhysicsCmd.hh>\n#include <ignition/gazebo/components/Pose.hh>\n#include <ignition/gazebo/components/World.hh>\n#include <ignition/transport/Node.hh>\n#include <ignition/transport/Publisher.hh>\n#include <sdf/sdf.hh>\n\n#include <algorithm>\n#include <cassert>\n#include <chrono>\n#include <cmath>\n#include <csignal>\n#include <functional>\n#include <limits>\n#include <optional>\n#include <thread>\n#include <unordered_map>\n\nusing namespace scenario::gazebo;\n\nnamespace scenario::gazebo::detail {\n    class ECMProvider;\n    struct PhysicsData;\n    struct SimulationResources\n    {\n        ignition::gazebo::EventManager* eventMgr = nullptr;\n        ignition::gazebo::EntityComponentManager* ecm = nullptr;\n    };\n} // namespace scenario::gazebo::detail\n\nstruct detail::PhysicsData\n{\n    double rtf = -1;\n    double maxStepSize = -1;\n    double realTimeUpdateRate = -1;\n\n    bool valid() const { return this->rtf > 0 && this->maxStepSize > 0; }\n};\n\nclass scenario::gazebo::detail::ECMProvider final\n    : public ignition::gazebo::System\n    , public ignition::gazebo::ISystemConfigure\n{\npublic:\n    ECMProvider()\n        : ignition::gazebo::System()\n    {}\n\n    void Configure(const ignition::gazebo::Entity& entity,\n                   const std::shared_ptr<const sdf::Element>& /*sdf*/,\n                   ignition::gazebo::EntityComponentManager& ecm,\n                   ignition::gazebo::EventManager& eventMgr);\n\n    std::string worldName;\n    ignition::gazebo::EventManager* eventMgr = nullptr;\n    ignition::gazebo::EntityComponentManager* ecm = nullptr;\n};\n\n// ==============\n// Implementation\n// ==============\n\nclass GazeboSimulator::Impl\n{\npublic:\n    sdf::ElementPtr sdfElement = nullptr;\n\n    struct\n    {\n        detail::PhysicsData physics;\n        uint64_t numOfIterations = 0;\n        std::unique_ptr<TinyProcessLib::Process> gui;\n        std::shared_ptr<ignition::gazebo::Server> server;\n    } gazebo;\n\n    using WorldName = std::string;\n    using GazeboWorldPtr = std::shared_ptr<scenario::gazebo::World>;\n\n    std::unordered_map<WorldName, GazeboWorldPtr> worlds;\n    std::unordered_map<WorldName, detail::SimulationResources> resources;\n\n    bool insertSDFWorld(const sdf::World& world);\n    std::shared_ptr<ignition::gazebo::Server> getServer();\n\n    static std::shared_ptr<World>\n    CreateGazeboWorld(const std::string& worldName,\n                      const detail::SimulationResources& resources);\n\n    bool sceneBroadcasterActive(const std::string& worldName);\n};\n\n// ===============\n// GazeboSimulator\n// ===============\n\nGazeboSimulator::GazeboSimulator(const double stepSize,\n                                 const double rtf,\n                                 const size_t stepsPerRun)\n    : pImpl{std::make_unique<GazeboSimulator::Impl>()}\n{\n    // Configure gazebo\n    pImpl->gazebo.numOfIterations = stepsPerRun;\n\n    // Configure the physics profile\n    pImpl->gazebo.physics.rtf = rtf;\n    pImpl->gazebo.physics.maxStepSize = stepSize;\n\n    // Configure Fuel Callback\n    sdf::setFindCallback([](const std::string& uri) -> std::string {\n        auto fuelClient = ignition::fuel_tools::FuelClient();\n        const auto path =\n            ignition::fuel_tools::fetchResourceWithClient(uri, fuelClient);\n        return path;\n    });\n}\n\nGazeboSimulator::~GazeboSimulator()\n{\n    this->close();\n}\n\ndouble GazeboSimulator::stepSize() const\n{\n    if (!this->initialized()) {\n        return pImpl->gazebo.physics.maxStepSize;\n    }\n\n    // Get the first world\n    const auto world = this->getWorld(this->worldNames().front());\n\n    // Get the active physics parameters\n    const auto& physics = utils::getExistingComponentData< //\n        ignition::gazebo::components::Physics>(world->ecm(), world->entity());\n\n    return physics.MaxStepSize();\n}\n\ndouble GazeboSimulator::realTimeFactor() const\n{\n    if (!this->initialized()) {\n        return pImpl->gazebo.physics.rtf;\n    }\n\n    // Get the first world\n    const auto world = this->getWorld(this->worldNames().front());\n\n    // Get the active physics parameters\n    const auto& physics = utils::getExistingComponentData< //\n        ignition::gazebo::components::Physics>(world->ecm(), world->entity());\n\n    return physics.RealTimeFactor();\n}\n\nsize_t GazeboSimulator::stepsPerRun() const\n{\n    return pImpl->gazebo.numOfIterations;\n}\n\nbool GazeboSimulator::initialize()\n{\n    if (this->initialized()) {\n        sMessage << \"The simulator is already initialized\" << std::endl;\n        return true;\n    }\n\n    // Initialize the server\n    if (!pImpl->getServer()) {\n        sError << \"Failed to get the Gazebo server\" << std::endl;\n        return false;\n    }\n\n    auto cb = [&](int sig) {\n        this->close();\n        exit(sig);\n    };\n\n    // Setup signals callbacks.\n    // It must be done after the creation of the simulator since\n    // we override their callbacks.\n    core::utils::SignalManager::Instance().setCallback(SIGINT, cb);\n    core::utils::SignalManager::Instance().setCallback(SIGTERM, cb);\n    core::utils::SignalManager::Instance().setCallback(SIGABRT, cb);\n\n    return true;\n}\n\nbool GazeboSimulator::initialized() const\n{\n    return bool(pImpl->gazebo.server);\n}\n\nbool GazeboSimulator::run(const bool paused)\n{\n    if (!this->initialized()) {\n        sError << \"The simulator was not initialized\" << std::endl;\n        return false;\n    }\n\n    // Get the gazebo server\n    auto server = pImpl->getServer();\n    if (!server) {\n        sError << \"Failed to get the ignition server\" << std::endl;\n        return false;\n    }\n\n    // If the server was configured to run in background (iterations = 0)\n    // only the first call to this run method should trigger the start of\n    // the simulation in non-blocking mode.\n    // NOTE: non-blocking implementation is partial and not supported\n    bool deterministic = pImpl->gazebo.numOfIterations != 0 ? true : false;\n\n    if (!deterministic && server->Running()) {\n        sWarning << \"The server is already running in background\" << std::endl;\n        return true;\n    }\n\n    size_t iterations = pImpl->gazebo.numOfIterations;\n\n    // Allow executing a single paused step in non-blocking mode,\n    // allowing to refresh the visualized world state\n    if (!deterministic && !server->Running() && paused) {\n        deterministic = true;\n        iterations = 1;\n    }\n\n    // Recent versions of Ignition Gazebo optimize the streaming of pose updates\n    // in order to reduce the bandwidth between server and client.\n    // However, it does not take into account paused steps.\n    // Here below we force all the Pose components to be streamed by manually\n    // setting them as changed.\n    if (paused) {\n\n        // Process all worlds\n        for (const auto& worldName : this->worldNames()) {\n\n            // Get the ECM\n            assert(this->pImpl->resources.find(worldName)\n                   != this->pImpl->resources.end());\n            auto* ecm = this->pImpl->resources.at(worldName).ecm;\n\n            // Mark all all entities with Pose component as Changed\n            ecm->Each<ignition::gazebo::components::Pose>(\n                [&](const ignition::gazebo::Entity& entity,\n                    ignition::gazebo::components::Pose*) -> bool {\n                    ecm->SetChanged(\n                        entity,\n                        ignition::gazebo::components::Pose::typeId,\n                        ignition::gazebo::ComponentState::OneTimeChange);\n                    return true;\n                });\n        }\n    }\n\n    // Paused simulation run\n    if (paused && !server->RunOnce(/*paused=*/true)) {\n        sError << \"The server couldn't execute the paused step\" << std::endl;\n        return false;\n    }\n\n    // Unpaused simulation run\n    if (!paused\n        && !server->Run(/*blocking=*/deterministic,\n                        /*iterations=*/iterations,\n                        /*paused=*/false)) {\n        sError << \"The server couldn't execute the step\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool GazeboSimulator::gui(const int verbosity)\n{\n    if (!this->initialized()) {\n        sError << \"The simulator was not initialized\" << std::endl;\n        return false;\n    }\n\n    // If ign-gazebo-gui is already running, return without doing anything\n    int exit_status;\n    if (pImpl->gazebo.gui\n        && !pImpl->gazebo.gui->try_get_exit_status(exit_status)) {\n        return true;\n    }\n\n    const std::vector<std::string>& worldNames = this->worldNames();\n\n    if (worldNames.empty()) {\n        sError << \"Failed to find any world in the simulator\" << std::endl;\n        return false;\n    }\n\n    // NOTE: we connect to the first world\n    const std::string& worldName = worldNames[0];\n\n    if (!pImpl->sceneBroadcasterActive(worldName)) {\n        sDebug << \"Starting the SceneBroadcaster plugin\" << std::endl;\n        auto world = this->getWorld(worldName);\n        if (!std::static_pointer_cast<World>(world)->insertWorldPlugin(\n                \"ignition-gazebo-scene-broadcaster-system\",\n                \"ignition::gazebo::systems::SceneBroadcaster\")) {\n            sError << \"Failed to load SceneBroadcaster plugin\" << std::endl;\n            return false;\n        }\n    }\n\n    // Allow specifying a GUI verbosity different than the server verbosity\n    int guiVerbosity = verbosity;\n\n    if (guiVerbosity < 0) {\n        // Get the verbosity level\n        guiVerbosity = ignition::common::Console::Verbosity();\n    }\n\n#if defined(WIN32) || defined(_WIN32)\n    const std::string redirect = \"\";\n#else\n    // Suppress GUI stderr.\n    // Recent versions of the GUI segfault printing an annoying stacktrace.\n    const std::string redirect = guiVerbosity >= 4 ? \"\" : \" 2>/dev/null\";\n#endif\n\n    // Spawn a new process with the GUI\n    pImpl->gazebo.gui = std::make_unique<TinyProcessLib::Process>(\n        \"ign gazebo -g -v \" + std::to_string(guiVerbosity) + redirect);\n\n    bool guiServiceExists = false;\n    ignition::transport::Node node;\n    std::vector<std::string> serviceList;\n\n    do {\n        sDebug << \"Waiting GUI to show up... \" << std::endl;\n        node.ServiceList(serviceList);\n\n        for (const auto& serviceName : serviceList) {\n            if (serviceName.find(\"/gui/\") == 0) {\n                guiServiceExists = true;\n                break;\n            }\n        }\n\n        std::this_thread::sleep_for(std::chrono::milliseconds(100));\n    } while (!guiServiceExists);\n\n    sDebug << \"GUI up and running\" << std::endl;\n    return true;\n}\n\nbool GazeboSimulator::close()\n{\n    if (pImpl->gazebo.gui) {\n#if defined(WIN32) || defined(_WIN32)\n        const bool force = false;\n#else\n        const bool force = true;\n#endif\n        pImpl->gazebo.gui->kill(force);\n    }\n\n    // Pause the simulator before tearing it down\n    if (pImpl->gazebo.server && this->running()) {\n        this->pause();\n    }\n\n    // Delete the simulator\n    pImpl->gazebo.server.reset();\n\n    return true;\n}\n\nbool GazeboSimulator::pause()\n{\n    if (!this->initialized()) {\n        sMessage << \"Couldn't pause the simulator, it was never initialized\"\n                 << std::endl;\n        return true;\n    }\n\n    if (!this->running()) {\n        sMessage << \"The simulation is already paused\" << std::endl;\n        return true;\n    }\n\n    const size_t numOfWorlds = this->worldNames().size();\n\n    for (unsigned worldIdx = 0; worldIdx < numOfWorlds; ++worldIdx) {\n        pImpl->getServer()->SetPaused(true, worldIdx);\n    }\n\n    return !this->running();\n}\n\nbool GazeboSimulator::running() const\n{\n    if (!this->initialized()) {\n        sMessage << \"The simulator was not initialized\" << std::endl;\n        return false;\n    }\n\n    return pImpl->gazebo.server->Running();\n}\n\nbool GazeboSimulator::insertWorldFromSDF(const std::string& worldFile,\n                                         const std::string& worldName)\n{\n    if (this->initialized()) {\n        sError << \"Worlds must be inserted before the initialization\"\n               << std::endl;\n        return false;\n    }\n\n    std::shared_ptr<sdf::Root> sdfRoot = nullptr;\n\n    if (!worldFile.empty()) {\n        // Load the world file\n        sdfRoot = utils::getSdfRootFromFile(worldFile);\n    }\n    else {\n        sMessage << \"No world file passed, using the default empty world\"\n                 << std::endl;\n        sdfRoot = utils::getSdfRootFromString(utils::getEmptyWorld());\n    }\n\n    if (!sdfRoot) {\n        // Error printed in the function call\n        return false;\n    }\n\n    if (sdfRoot->WorldCount() != 1) {\n        sError << \"The world file has more than one world\" << std::endl;\n        return false;\n    }\n\n    sdf::World world = *const_cast<sdf::World*>(sdfRoot->WorldByIndex(0));\n\n    if (!worldName.empty()) {\n        // Rename the world and get the new World pointer\n        world = utils::renameSDFWorld(world, worldName);\n\n        if (world.Name() != worldName) {\n            return false;\n        }\n    }\n\n    return pImpl->insertSDFWorld(world);\n}\n\nbool GazeboSimulator::insertWorldsFromSDF(\n    const std::string& worldFile,\n    const std::vector<std::string>& worldNames)\n{\n    if (this->initialized()) {\n        sMessage << \"Worlds must be inserted before the initialization\"\n                 << std::endl;\n        return false;\n    }\n\n    // Load the world file\n    auto sdfRoot = utils::getSdfRootFromFile(worldFile);\n\n    if (!sdfRoot) {\n        // Error printed in the function call\n        return false;\n    }\n\n    if (sdfRoot->WorldCount() == 0) {\n        sError << \"Failed to find any world in the SDF file\" << std::endl;\n        return false;\n    }\n\n    if (!worldNames.empty() && sdfRoot->WorldCount() != worldNames.size()) {\n        sError << \"The number of world names does not match the number of \"\n               << \"worlds found in the SDF file\" << std::endl;\n        return false;\n    }\n\n    for (size_t worldIdx = 0; worldIdx < sdfRoot->WorldCount(); ++worldIdx) {\n\n        // Get the world\n        sdf::World thisWorld =\n            *const_cast<sdf::World*>(sdfRoot->WorldByIndex(worldIdx));\n\n        // Optionally rename it\n        if (!worldNames.empty()) {\n            const std::string& worldName = worldNames[worldIdx];\n            thisWorld = utils::renameSDFWorld(thisWorld, worldName);\n\n            if (thisWorld.Name() != worldName) {\n                return false;\n            }\n        }\n\n        if (!pImpl->insertSDFWorld(thisWorld)) {\n            sError << \"Failed to insert world \" << thisWorld.Name()\n                   << std::endl;\n            return false;\n        }\n    }\n\n    return true;\n}\n\nstd::vector<std::string> GazeboSimulator::worldNames() const\n{\n    if (!this->initialized()) {\n        sError << \"The simulator was not initialized\" << std::endl;\n        return {};\n    }\n\n    std::vector<std::string> worldNames;\n\n    for (const auto& [name, _] : this->pImpl->worlds) {\n        worldNames.push_back(name);\n    }\n\n    return worldNames;\n}\n\nstd::shared_ptr<scenario::gazebo::World>\nGazeboSimulator::getWorld(const std::string& worldName) const\n{\n    if (!this->initialized()) {\n        sError << \"The simulator was not initialized\" << std::endl;\n        return nullptr;\n    }\n\n    // Get the existing world names.\n    // In most cases there will be only one world. In this case we allow\n    // omitting to specify the world name and automatically get the default.\n    const std::vector<std::string>& worldNames = this->worldNames();\n\n    if (worldName.empty() && worldNames.size() == 0) {\n        sError << \"The simulator does not have any world\" << std::endl;\n        return nullptr;\n    }\n\n    if (worldName.empty() && worldNames.size() > 1) {\n        sError << \"Found multiple worlds. You must specify the world name.\"\n               << std::endl;\n        return nullptr;\n    }\n\n    // Either use the method argument or the default world\n    const std::string nameOfReturnedWorld =\n        worldName.empty() ? worldNames[0] : worldName;\n\n    // All the worlds objects are created and cached during the simulator\n    // initialization. If there is no world, something has gone wrong.\n    if (pImpl->worlds.find(nameOfReturnedWorld) == pImpl->worlds.end()) {\n        sError << \"World \" << nameOfReturnedWorld << \" not found\" << std::endl;\n        return nullptr;\n    }\n\n    assert(pImpl->worlds.at(nameOfReturnedWorld));\n    return pImpl->worlds.at(nameOfReturnedWorld);\n}\n\n// ==============\n// Implementation\n// ==============\n\nvoid detail::ECMProvider::Configure(\n    const ignition::gazebo::Entity& entity,\n    const std::shared_ptr<const sdf::Element>&,\n    ignition::gazebo::EntityComponentManager& ecm,\n    ignition::gazebo::EventManager& eventMgr)\n{\n    if (!ecm.EntityHasComponentType(\n            entity, ignition::gazebo::components::World::typeId)) {\n        sError << \"The ECMProvider system was not inserted \"\n               << \"in a world element\" << std::endl;\n        return;\n    }\n\n    this->worldName = utils::getExistingComponentData< //\n        ignition::gazebo::components::Name>(&ecm, entity);\n\n    this->ecm = &ecm;\n    this->eventMgr = &eventMgr;\n\n    sDebug << \"World '\" << this->worldName\n           << \"' successfully processed by ECMProvider\" << std::endl;\n}\n\nbool GazeboSimulator::Impl::insertSDFWorld(const sdf::World& world)\n{\n    if (!sdfElement) {\n        sdfElement = sdf::SDF::WrapInRoot(world.Element()->Clone());\n    }\n    else {\n        // Check that there are no worlds with the same name already stored\n        const auto root = utils::getSdfRootFromString(sdfElement->ToString(\"\"));\n\n        if (!root) {\n            return false;\n        }\n\n        if (root->WorldNameExists(world.Name())) {\n            sError << \"Another world with name \" << world.Name()\n                   << \" already exists\" << std::endl;\n            return false;\n        }\n\n        // Insert the new world in the DOM\n        sdfElement->InsertElement(world.Element()->Clone());\n    }\n\n    return true;\n}\n\nstd::shared_ptr<ignition::gazebo::Server> GazeboSimulator::Impl::getServer()\n{\n    // Lazy initialization of the server\n    if (gazebo.server) {\n        return gazebo.server;\n    }\n\n    // =================\n    // Create the server\n    // =================\n\n    if (gazebo.numOfIterations == 0) {\n        sError << \"Non-deterministic mode (iterations=0) is not \"\n               << \"currently supported\" << std::endl;\n        return nullptr;\n    }\n\n    sdf::Root root;\n\n    if (!sdfElement) {\n        sMessage << \"Using default empty world\" << std::endl;\n        auto errors = root.LoadSdfString(utils::getEmptyWorld());\n        assert(errors.empty()); // TODO\n    }\n    else {\n        auto errors = root.LoadSdfString(sdfElement->ToString(\"\"));\n        assert(errors.empty()); // TODO\n    }\n\n    if (root.WorldCount() == 0) {\n        sError << \"Failed to find a world in the SDF root\" << std::endl;\n        return nullptr;\n    }\n\n    // Check if there are sdf parsing errors\n    assert(utils::sdfStringValid(root.Element()->Clone()->ToString(\"\")));\n\n    if (utils::verboseFromEnvironment()) {\n        sDebug << \"Loading the following SDF file in the gazebo server:\"\n               << std::endl;\n        std::cout << root.Element()->ToString(\"\") << std::endl;\n    }\n\n    // Set the following environment variable to disable loading the default\n    // server plugins, which include upstream's Physics that is not compatible.\n    // https://github.com/ignitionrobotics/ign-gazebo/pull/281\n    // TODO: this will not likely work in Windows.\n    std::string value;\n    if (!ignition::common::env(\n            ignition::gazebo::kServerConfigPathEnv, value, true)\n        && !ignition::common::setenv(ignition::gazebo::kServerConfigPathEnv,\n                                     \"\")) {\n        sError << \"Failed to set \" << ignition::gazebo::kServerConfigPathEnv\n               << std::endl;\n        return nullptr;\n    }\n\n    ignition::gazebo::ServerConfig config;\n    config.SetSeed(0);\n    config.SetUseLevels(false);\n    config.SetSdfString(root.Element()->ToString(\"\"));\n\n    // Create the server.\n    // The worlds are initialized with the physics parameters\n    // (rtf and physics step) defined in the SDF.\n    // They get overridden below.\n    auto server = std::make_shared<ignition::gazebo::Server>(config);\n    assert(server);\n\n    // Add a Configure-only system to get the ECM pointer\n    for (size_t worldIdx = 0; worldIdx < root.WorldCount(); ++worldIdx) {\n\n        auto provider = std::make_shared<detail::ECMProvider>();\n        if (const auto ok = server->AddSystem(provider, worldIdx); !ok) {\n            sError << \"Failed to insert ECMProvider to world \" << worldIdx\n                   << std::endl;\n            return nullptr;\n        }\n\n        // Get the ECM and EventManager pointers\n        detail::SimulationResources resources;\n        resources.ecm = provider->ecm;\n        resources.eventMgr = provider->eventMgr;\n        this->resources[provider->worldName] = resources;\n    }\n\n    std::this_thread::sleep_for(std::chrono::seconds(3));\n\n    sDebug << \"Starting the gazebo server\" << std::endl;\n\n    // TODO: is this redundant now?\n    if (!server->RunOnce(/*paused=*/true)) {\n        sError << \"Failed to initialize the first gazebo server run\"\n               << std::endl;\n        return nullptr;\n    }\n\n    if (!gazebo.physics.valid()) {\n        sError << \"The physics parameters are not valid\" << std::endl;\n        return nullptr;\n    }\n\n    // Set the Physics parameters.\n    // Note: all worlds must share the same parameters.\n    for (const auto& [worldName, resources] : this->resources) {\n\n        // Get the world entity\n        const auto worldEntity = resources.ecm->EntityByComponents(\n            ignition::gazebo::components::World(),\n            ignition::gazebo::components::Name(worldName));\n\n        // Create a new PhysicsCmd component\n        auto& physics =\n            utils::getComponentData<ignition::gazebo::components::PhysicsCmd>(\n                resources.ecm, worldEntity);\n\n        // Store the physics parameters.\n        // They are processed the next simulator step.\n        physics.set_max_step_size(gazebo.physics.maxStepSize);\n        physics.set_real_time_factor(gazebo.physics.rtf);\n        physics.set_real_time_update_rate(gazebo.physics.realTimeUpdateRate);\n    }\n\n    // Step the server to process the physics parameters.\n    // This call executes SimulationRunner::SetStepSize, updating the\n    // rate at which all systems are called.\n    // Note: it processes only the parameters of the first world.\n    if (!server->RunOnce(/*paused=*/true)) {\n        sError << \"Failed to step the server to configure the physics\"\n               << std::endl;\n        return nullptr;\n    }\n\n    for (size_t worldIdx = 0; worldIdx < root.WorldCount(); ++worldIdx) {\n        // Get the world name\n        const auto& worldName = root.WorldByIndex(worldIdx)->Name();\n\n        sDebug << \"Creating and caching World '\" << worldName << \"'\"\n               << std::endl;\n\n        // Create the world object.\n        // Note: performing this operation is important because the\n        //       World objects are created and cached. During the first\n        //       initialization, the World objects create important\n        //       componentes like Timestamp and SimulatedTime.\n        const auto& world =\n            Impl::CreateGazeboWorld(worldName, this->resources[worldName]);\n\n        if (!(world && world->valid())) {\n            sError << \"Failed to create world \" << worldName << std::endl;\n            return nullptr;\n        }\n\n        // Cache the world object\n        assert(this->worlds.find(worldName) == this->worlds.end());\n        this->worlds[worldName] = world;\n    }\n\n    // Store and return the server\n    gazebo.server = server;\n    return gazebo.server;\n}\n\nstd::shared_ptr<World> GazeboSimulator::Impl::CreateGazeboWorld(\n    const std::string& worldName,\n    const detail::SimulationResources& resources)\n{\n    // Get the world entity\n    const auto worldEntity = resources.ecm->EntityByComponents(\n        ignition::gazebo::components::World(),\n        ignition::gazebo::components::Name(worldName));\n\n    // Create the world object\n    auto world = std::make_shared<scenario::gazebo::World>();\n\n    if (!world->initialize(worldEntity, resources.ecm, resources.eventMgr)) {\n        sError << \"Failed to initialize the world\" << std::endl;\n        return nullptr;\n    }\n\n    if (!world->createECMResources()) {\n        sError << \"Failed to initialize the ECM world resources\" << std::endl;\n        return nullptr;\n    }\n\n    if (world->id() == 0) {\n        sError << \"The id of the world is 0. Something went wrong\" << std::endl;\n        return nullptr;\n    }\n\n    return world;\n}\n\nbool GazeboSimulator::Impl::sceneBroadcasterActive(const std::string& worldName)\n{\n    ignition::transport::Node node;\n    std::vector<ignition::transport::ServicePublisher> publishers;\n\n    std::string serviceName{\"/world/\" + worldName + \"/scene/info\"};\n    node.ServiceInfo(serviceName, publishers);\n\n    return !publishers.empty();\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/Joint.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/Joint.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/components/HistoryOfAppliedJointForces.h\"\n#include \"scenario/gazebo/components/JointAcceleration.h\"\n#include \"scenario/gazebo/components/JointAccelerationTarget.h\"\n#include \"scenario/gazebo/components/JointControlMode.h\"\n#include \"scenario/gazebo/components/JointController.h\"\n#include \"scenario/gazebo/components/JointControllerPeriod.h\"\n#include \"scenario/gazebo/components/JointPID.h\"\n#include \"scenario/gazebo/components/JointPositionTarget.h\"\n#include \"scenario/gazebo/components/JointVelocityTarget.h\"\n#include \"scenario/gazebo/components/Timestamp.h\"\n#include \"scenario/gazebo/exceptions.h\"\n#include \"scenario/gazebo/helpers.h\"\n#include \"scenario/gazebo/utils.h\"\n\n#include <ignition/gazebo/components/JointAxis.hh>\n#include <ignition/gazebo/components/JointForce.hh>\n#include <ignition/gazebo/components/JointForceCmd.hh>\n#include <ignition/gazebo/components/JointPosition.hh>\n#include <ignition/gazebo/components/JointPositionReset.hh>\n#include <ignition/gazebo/components/JointType.hh>\n#include <ignition/gazebo/components/JointVelocity.hh>\n#include <ignition/gazebo/components/JointVelocityCmd.hh>\n#include <ignition/gazebo/components/JointVelocityReset.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/ParentEntity.hh>\n#include <ignition/math/PID.hh>\n#include <sdf/Joint.hh>\n#include <sdf/JointAxis.hh>\n\n#include <cassert>\n#include <utility>\n\nusing namespace scenario::gazebo;\nconst ignition::math::PID DefaultPID(1, 0.1, 0.01, -1, 0, -1, 0, 0);\n\nclass Joint::Impl\n{\npublic:\n};\n\nJoint::Joint()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nJoint::~Joint() = default;\n\nuint64_t Joint::id() const\n{\n    // Get the parent world\n    const core::WorldPtr parentWorld = utils::getParentWorld(*this);\n    assert(parentWorld);\n\n    // Build a unique string identifier of this joint\n    const std::string scopedJointName =\n        parentWorld->name() + \"::\" + this->name(/*scoped=*/true);\n\n    // Return the hashed string\n    return std::hash<std::string>{}(scopedJointName);\n}\n\nbool Joint::initialize(const ignition::gazebo::Entity jointEntity,\n                       ignition::gazebo::EntityComponentManager* ecm,\n                       ignition::gazebo::EventManager* eventManager)\n{\n    if (jointEntity == ignition::gazebo::kNullEntity || !ecm || !eventManager) {\n        sError << \"Failed to initialize Joint\" << std::endl;\n        return false;\n    }\n\n    m_ecm = ecm;\n    m_entity = jointEntity;\n    m_eventManager = eventManager;\n\n    if (this->dofs() > 1) {\n        sError << \"Joints with DoFs > 1 are not currently supported\"\n               << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Joint::createECMResources()\n{\n    sMessage << \"  [\" << m_entity << \"] \" << this->name() << std::endl;\n\n    using namespace ignition::gazebo;\n\n    const std::vector<double> zero(this->dofs(), 0.0);\n\n    // Create required components\n    m_ecm->CreateComponent(m_entity, components::JointForce(zero));\n    m_ecm->CreateComponent(m_entity, components::JointPosition(zero));\n    m_ecm->CreateComponent(m_entity, components::JointVelocity(zero));\n    m_ecm->CreateComponent(m_entity, components::JointAcceleration(zero));\n    m_ecm->CreateComponent(m_entity, components::JointPID(DefaultPID));\n    m_ecm->CreateComponent(\n        m_entity, components::JointControlMode(core::JointControlMode::Idle));\n\n    return true;\n}\n\nbool Joint::insertJointPlugin(const std::string& libName,\n                              const std::string& className,\n                              const std::string& context)\n{\n    return utils::insertPluginToGazeboEntity(\n        *this, libName, className, context);\n}\n\nbool Joint::resetPosition(const double position, size_t dof)\n{\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointPositionReset = utils::getComponentData< //\n        ignition::gazebo::components::JointPositionReset>(m_ecm, m_entity);\n\n    if (jointPositionReset.size() != this->dofs()) {\n        assert(jointPositionReset.size() == 0);\n        jointPositionReset = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    // Reset the PID\n    auto& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n    pid.Reset();\n\n    jointPositionReset[dof] = position;\n    return true;\n}\n\nbool Joint::resetVelocity(const double velocity, const size_t dof)\n{\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointVelocityReset = utils::getComponentData< //\n        ignition::gazebo::components::JointVelocityReset>(m_ecm, m_entity);\n\n    if (jointVelocityReset.size() != this->dofs()) {\n        assert(jointVelocityReset.size() == 0);\n        jointVelocityReset = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    // Reset the PID\n    auto& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n    pid.Reset();\n\n    jointVelocityReset[dof] = velocity;\n    return true;\n}\n\nbool Joint::reset(const double position, const double velocity, size_t dof)\n{\n    bool ok = true;\n\n    // These methods also reset the PID\n    ok = ok && this->resetPosition(position, dof);\n    ok = ok && this->resetVelocity(velocity, dof);\n\n    if (!ok) {\n        sError << \"Failed to reset state of joint '\" << this->name() << \"'\"\n               << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Joint::resetJointPosition(const std::vector<double>& position)\n{\n    if (position.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointPositionReset = utils::getComponentData< //\n        ignition::gazebo::components::JointPositionReset>(m_ecm, m_entity);\n\n    // Update the position\n    jointPositionReset = position;\n\n    // Reset the PID\n    auto& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n    pid.Reset();\n\n    return true;\n}\n\nbool Joint::resetJointVelocity(const std::vector<double>& velocity)\n{\n    if (velocity.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointVelocityReset = utils::getComponentData< //\n        ignition::gazebo::components::JointVelocityReset>(m_ecm, m_entity);\n\n    // Update the velocity\n    jointVelocityReset = velocity;\n\n    // Reset the PID\n    auto& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n    pid.Reset();\n\n    return true;\n}\n\nbool Joint::resetJoint(const std::vector<double>& position,\n                       const std::vector<double>& velocity)\n{\n    bool ok = true;\n\n    ok = ok && this->resetJointPosition(position);\n    ok = ok && this->resetJointVelocity(velocity);\n\n    if (!ok) {\n        sError << \"Failed to reset joint '\" << this->name() << \"'\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Joint::setCoulombFriction(const double value)\n{\n    if (!utils::parentModelJustCreated(*this)) {\n        sError << \"The model has been already processed and its \"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic:\n        case core::JointType::Ball: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            axis.SetFriction(value);\n            return true;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no friction defined.\"\n                     << std::endl;\n            return false;\n    }\n\n    return false;\n}\n\nbool Joint::setViscousFriction(const double value)\n{\n    if (!utils::parentModelJustCreated(*this)) {\n        sError << \"The model has been already processed and its \"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic:\n        case core::JointType::Ball: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            axis.SetDamping(value);\n            return true;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no friction defined.\"\n                     << std::endl;\n            return false;\n    }\n\n    return false;\n}\n\nbool Joint::valid() const\n{\n    return this->validEntity();\n}\n\nsize_t Joint::dofs() const\n{\n    switch (this->type()) {\n        case core::JointType::Invalid:\n            return 0;\n        case core::JointType::Fixed:\n            return 0;\n        case core::JointType::Revolute:\n            return 1;\n        case core::JointType::Prismatic:\n            return 1;\n        case core::JointType::Ball:\n            return 3;\n    }\n\n    assert(false);\n    return 0;\n}\n\nstd::string Joint::name(const bool scoped) const\n{\n    std::string jointName = utils::getExistingComponentData< //\n        ignition::gazebo::components::Name>(m_ecm, m_entity);\n\n    if (scoped) {\n        jointName = utils::getParentModel(*this)->name() + \"::\" + jointName;\n    }\n\n    return jointName;\n}\n\nscenario::core::JointType Joint::type() const\n{\n    // Get the joint type\n    const sdf::JointType sdfType = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointType>(m_ecm, m_entity);\n\n    // Convert the joint type\n    const core::JointType type = utils::fromSdf(sdfType);\n\n    return type;\n}\n\nscenario::core::JointControlMode Joint::controlMode() const\n{\n    const core::JointControlMode mode = utils::getExistingComponentData<\n        ignition::gazebo::components::JointControlMode>(m_ecm, m_entity);\n\n    return mode;\n}\n\nbool Joint::setControlMode(const scenario::core::JointControlMode mode)\n{\n    if (mode == core::JointControlMode::PositionInterpolated) {\n        sError << \"PositionInterpolated not yet supported\" << std::endl;\n        return false;\n    }\n\n    // Insert the JointController plugin to the model if the control\n    // mode is either Position or Velocity\n    if (mode == core::JointControlMode::Position\n        || mode == core::JointControlMode::Velocity\n        || mode == core::JointControlMode::VelocityFollowerDart) {\n\n        // Get the parent model\n        const auto parentModel = utils::getParentModel(*this);\n\n        if (!parentModel) {\n            sError << \"Failed to get the parent model of joint '\"\n                   << this->name() << \"' for inserting the \"\n                   << \"JointController\" << std::endl;\n            return false;\n        }\n\n        // Insert the plugin if the model does not have it already\n        if (!m_ecm->EntityHasComponentType(\n                parentModel->entity(),\n                ignition::gazebo::components::JointController::typeId)) {\n\n            sDebug << \"Loading JointController plugin for model '\"\n                   << parentModel->name() << \"'\" << std::endl;\n\n            // Load the JointController plugin\n            if (!parentModel->insertModelPlugin(\n                    \"JointController\",\n                    \"scenario::plugins::gazebo::JointController\")) {\n                sError << \"Failed to insert JointController plugin for model '\"\n                       << parentModel->name() << \"'\" << std::endl;\n                return false;\n            }\n        }\n    }\n\n    utils::setExistingComponentData<\n        ignition::gazebo::components::JointControlMode>(m_ecm, m_entity, mode);\n\n    // Delete the existing targets if they exist\n    sDebug << \"Deleting existing targets after changing control mode\"\n           << std::endl;\n    m_ecm->RemoveComponent(\n        m_entity, ignition::gazebo::components::JointPositionTarget::typeId);\n    m_ecm->RemoveComponent(\n        m_entity, ignition::gazebo::components::JointVelocityTarget::typeId);\n    m_ecm->RemoveComponent(\n        m_entity,\n        ignition::gazebo::components::JointAccelerationTarget::typeId);\n    m_ecm->RemoveComponent(\n        m_entity, ignition::gazebo::components::JointVelocityCmd::typeId);\n    m_ecm->RemoveComponent(m_entity,\n                           ignition::gazebo::components::JointForceCmd::typeId);\n\n    // Initialize the target as the current position / velocity\n    switch (mode) {\n        case core::JointControlMode::Position:\n        case core::JointControlMode::PositionInterpolated:\n            utils::setComponentData<\n                ignition::gazebo::components::JointPositionTarget>(\n                m_ecm, m_entity, this->jointPosition());\n            break;\n        case core::JointControlMode::Velocity:\n        case core::JointControlMode::VelocityFollowerDart:\n            utils::setComponentData<\n                ignition::gazebo::components::JointVelocityTarget>(\n                m_ecm, m_entity, this->jointVelocity());\n            break;\n        case core::JointControlMode::Idle:\n        case core::JointControlMode::Force:\n            utils::setComponentData<\n                ignition::gazebo::components::JointForceCmd>(\n                m_ecm, m_entity, std::vector<double>(this->dofs(), 0.0));\n            break;\n        case core::JointControlMode::Invalid:\n            sError << \"You cannot set the Invalid control mode\" << std::endl;\n            return false;\n    }\n\n    // Reset the PID\n    auto& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n    pid.Reset();\n\n    return true;\n}\n\ndouble Joint::controllerPeriod() const\n{\n    auto duration = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointControllerPeriod>(\n        m_ecm, m_ecm->ParentEntity(m_entity));\n\n    return utils::steadyClockDurationToDouble(duration);\n}\n\nscenario::core::PID Joint::pid() const\n{\n    const ignition::math::PID& pid = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointPID>(m_ecm, m_entity);\n\n    return utils::fromIgnitionPID(pid);\n}\n\nbool Joint::setPID(const scenario::core::PID& pid)\n{\n    auto eqOp = [](const ignition::math::PID& a,\n                   const ignition::math::PID& b) -> bool {\n        bool equal = true;\n        const double epsilon = std::numeric_limits<double>::epsilon();\n\n        equal = equal && std::abs(a.PGain() - b.PGain()) > epsilon;\n        equal = equal && std::abs(a.IGain() - b.IGain()) > epsilon;\n        equal = equal && std::abs(a.DGain() - b.DGain()) > epsilon;\n        equal = equal && std::abs(a.IMin() - b.IMin()) > epsilon;\n        equal = equal && std::abs(a.IMax() - b.IMax()) > epsilon;\n        equal = equal && std::abs(a.CmdMin() - b.CmdMin()) > epsilon;\n        equal = equal && std::abs(a.CmdMax() - b.CmdMax()) > epsilon;\n        equal = equal && std::abs(a.CmdOffset() - b.CmdOffset()) > epsilon;\n        return equal;\n    };\n\n    if (this->dofs() > 1) {\n        sError << \"Setting PIDs of joints with more than 1 DoF is not \"\n               << \"currently supported\" << std::endl;\n        return false;\n    }\n\n    scenario::core::PID pidParams = pid;\n    const auto minForce = -this->maxGeneralizedForce(0);\n    const auto maxForce = this->maxGeneralizedForce(0);\n\n    if (pidParams.cmdMin < minForce || pidParams.cmdMax > maxForce) {\n        sWarning << \"The output limits of the PID are less limiting than \"\n                 << \"the maximum force that can be exerted on the joint. \"\n                 << \"Ignoring the specified PID limits.\" << std::endl;\n        pidParams.cmdMin = minForce;\n        pidParams.cmdMax = maxForce;\n    }\n\n    // Create the new PID\n    const ignition::math::PID& pidIgnitionMath =\n        utils::toIgnitionPID(pidParams);\n\n    // Store the new PID in the ECM\n    utils::setExistingComponentData<ignition::gazebo::components::JointPID,\n                                    ignition::math::PID>(\n        m_ecm, m_entity, pidIgnitionMath, eqOp);\n\n    return true;\n}\n\nbool Joint::historyOfAppliedJointForcesEnabled() const\n{\n    return m_ecm->EntityHasComponentType(\n        m_entity,\n        ignition::gazebo::components::HistoryOfAppliedJointForces::typeId);\n}\n\nbool Joint::enableHistoryOfAppliedJointForces(const bool enable,\n                                              const size_t maxHistorySize)\n{\n    if (enable) {\n        // If the component already exists, its value is not overridden\n        utils::getComponent<\n            ignition::gazebo::components::HistoryOfAppliedJointForces>(\n            m_ecm, m_entity, utils::FixedSizeQueue(maxHistorySize));\n    }\n    else {\n        m_ecm->RemoveComponent(\n            m_entity,\n            ignition::gazebo::components::HistoryOfAppliedJointForces::typeId);\n    }\n\n    return true;\n}\n\nstd::vector<double> Joint::historyOfAppliedJointForces() const\n{\n    if (!this->historyOfAppliedJointForcesEnabled()) {\n        return {};\n    }\n\n    const auto& fixedSizeQueue = utils::getExistingComponentData<\n        ignition::gazebo::components::HistoryOfAppliedJointForces>(m_ecm,\n                                                                   m_entity);\n\n    return fixedSizeQueue.toStdVector();\n}\n\ndouble Joint::coulombFriction() const\n{\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic:\n        case core::JointType::Ball: {\n            const sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            return axis.Friction();\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no friction defined.\"\n                     << std::endl;\n            return 0.0;\n    }\n\n    assert(false);\n    return 0.0;\n}\n\ndouble Joint::viscousFriction() const\n{\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic:\n        case core::JointType::Ball: {\n            const sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            return axis.Damping();\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no friction defined.\"\n                     << std::endl;\n            return 0.0;\n    }\n\n    assert(false);\n    return 0.0;\n}\n\nscenario::core::Limit Joint::positionLimit(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const auto& jointLimit = this->jointPositionLimit();\n    assert(dof < jointLimit.min.size());\n    assert(dof < jointLimit.max.size());\n\n    return core::Limit(jointLimit.min[dof], jointLimit.max[dof]);\n}\n\nscenario::core::Limit Joint::velocityLimit(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const auto& jointLimit = this->jointVelocityLimit();\n    assert(dof < jointLimit.min.size());\n    assert(dof < jointLimit.max.size());\n\n    return core::Limit(jointLimit.min[dof], jointLimit.max[dof]);\n}\n\nbool Joint::setVelocityLimit(const double maxVelocity, const size_t dof)\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n    auto velocityLimit = this->jointVelocityLimit();\n    velocityLimit.max[dof] = maxVelocity;\n    return this->setJointVelocityLimit(velocityLimit.max);\n}\n\ndouble Joint::maxGeneralizedForce(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& maxForce = this->jointMaxGeneralizedForce();\n    return maxForce[dof];\n}\n\nbool Joint::setMaxGeneralizedForce(const double maxForce, const size_t dof)\n{\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto maxGeneralizedForce = this->jointMaxGeneralizedForce();\n    maxGeneralizedForce[dof] = maxForce;\n    return this->setJointMaxGeneralizedForce(maxGeneralizedForce);\n}\n\ndouble Joint::position(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& position = this->jointPosition();\n    return position[dof];\n}\n\ndouble Joint::velocity(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& velocity = this->jointVelocity();\n    return velocity[dof];\n}\n\ndouble Joint::acceleration(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& acceleration = this->jointAcceleration();\n    return acceleration[dof];\n}\n\ndouble Joint::generalizedForce(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& force = this->jointGeneralizedForce();\n    return force[dof];\n}\n\nbool Joint::setPositionTarget(const double position, const size_t dof)\n{\n    const std::vector<core::JointControlMode> allowedControlModes = {\n        core::JointControlMode::Position,\n        core::JointControlMode::PositionInterpolated,\n        core::JointControlMode::Idle,\n        core::JointControlMode::Force};\n\n    auto it = std::find(allowedControlModes.begin(),\n                        allowedControlModes.end(),\n                        this->controlMode());\n\n    if (it == allowedControlModes.end()) {\n        sError << \"The active joint control mode does not accept a \"\n               << \"position target\" << std::endl;\n        return false;\n    }\n\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointPositionTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointPositionTarget>(m_ecm, m_entity);\n\n    if (jointPositionTarget.size() != this->dofs()) {\n        assert(jointPositionTarget.size() == 0);\n        jointPositionTarget = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    jointPositionTarget[dof] = position;\n    return true;\n}\n\nbool Joint::setVelocityTarget(const double velocity, const size_t dof)\n{\n    if (!(this->controlMode() == core::JointControlMode::Velocity\n          || this->controlMode() == core::JointControlMode::VelocityFollowerDart\n          || this->controlMode() == core::JointControlMode::Force)) {\n        sError << \"The active joint control mode does not accept a \"\n               << \"velocity target\" << std::endl;\n        return false;\n    }\n\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointVelocityTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointVelocityTarget>(m_ecm, m_entity);\n\n    if (jointVelocityTarget.size() != this->dofs()) {\n        assert(jointVelocityTarget.size() == 0);\n        jointVelocityTarget = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    jointVelocityTarget[dof] = velocity;\n    return true;\n}\n\nbool Joint::setAccelerationTarget(const double acceleration, const size_t dof)\n{\n    if (!(this->controlMode() == core::JointControlMode::Idle\n          || this->controlMode() == core::JointControlMode::Force)) {\n        sError << \"The active joint control mode does not accept an \"\n               << \"acceleration target\" << std::endl;\n        return false;\n    }\n\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointAccelerationTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointAccelerationTarget>(m_ecm, m_entity);\n\n    if (jointAccelerationTarget.size() != this->dofs()) {\n        assert(jointAccelerationTarget.size() == 0);\n        jointAccelerationTarget = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    jointAccelerationTarget[dof] = acceleration;\n    return true;\n}\n\nbool Joint::setGeneralizedForceTarget(const double force, const size_t dof)\n{\n    const std::vector<core::JointControlMode> allowedControlModes = {\n        core::JointControlMode::Force,\n        core::JointControlMode::Position,\n        core::JointControlMode::PositionInterpolated,\n        core::JointControlMode::Velocity};\n\n    auto it = std::find(allowedControlModes.begin(),\n                        allowedControlModes.end(),\n                        this->controlMode());\n\n    if (it == allowedControlModes.end()) {\n        sError << \"The active joint control mode does not accept a force \"\n               << \"target\" << std::endl;\n        return false;\n    }\n\n    if (dof >= this->dofs()) {\n        sError << \"Joint '\" << this->name() << \"' does not have DoF#\" << dof\n               << std::endl;\n        return false;\n    }\n\n    auto& jointForce = utils::getComponentData< //\n        ignition::gazebo::components::JointForceCmd>(m_ecm, m_entity);\n\n    if (jointForce.size() != this->dofs()) {\n        assert(jointForce.size() == 0);\n        jointForce = std::vector<double>(this->dofs(), 0.0);\n    }\n\n    if (std::abs(force) > this->maxGeneralizedForce(dof)) {\n        sWarning << \"The force target is higher than the limit. \"\n                 << \"The physics engine might clip it.\" << std::endl;\n    }\n\n    // Set the component data\n    jointForce[dof] = force;\n\n    return true;\n}\n\ndouble Joint::positionTarget(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& positionTarget = this->jointPositionTarget();\n    return positionTarget[dof];\n}\n\ndouble Joint::velocityTarget(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& velocityTarget = this->jointVelocityTarget();\n    return velocityTarget[dof];\n}\n\ndouble Joint::accelerationTarget(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& accelerationTarget =\n        this->jointAccelerationTarget();\n    return accelerationTarget[dof];\n}\n\ndouble Joint::generalizedForceTarget(const size_t dof) const\n{\n    if (dof >= this->dofs()) {\n        throw exceptions::DOFMismatch(this->dofs(), dof, this->name());\n    }\n\n    const std::vector<double>& force = this->jointGeneralizedForceTarget();\n    return force[dof];\n}\n\nscenario::core::JointLimit Joint::jointPositionLimit() const\n{\n    core::JointLimit jointLimit(this->dofs());\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            jointLimit.min[0] = axis.Lower();\n            jointLimit.max[0] = axis.Upper();\n            break;\n        }\n        case core::JointType::Fixed:\n            sWarning << \"Fixed joints do not have DOFs, limits are not defined\"\n                     << std::endl;\n            break;\n        case core::JointType::Invalid:\n        case core::JointType::Ball:\n            sWarning << \"Type of Joint '\" << this->name() << \"' has no limits\"\n                     << std::endl;\n            break;\n    }\n\n    return jointLimit;\n}\n\nscenario::core::JointLimit Joint::jointVelocityLimit() const\n{\n    core::JointLimit jointLimit(this->dofs());\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            jointLimit.min[0] = -axis.MaxVelocity();\n            jointLimit.max[0] = axis.MaxVelocity();\n            break;\n        }\n        case core::JointType::Fixed:\n            sWarning << \"Fixed joints do not have DOFs, limits are not defined\"\n                     << std::endl;\n            break;\n        case core::JointType::Invalid:\n        case core::JointType::Ball:\n            sWarning << \"Type of Joint '\" << this->name() << \"' has no limits\"\n                     << std::endl;\n            break;\n    }\n\n    return jointLimit;\n}\n\nbool Joint::setJointVelocityLimit(const std::vector<double>& maxVelocity)\n{\n    if (!utils::parentModelJustCreated(*this)) {\n        sError << \"The model has been already processed and its \"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    if (maxVelocity.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            axis.SetMaxVelocity(maxVelocity[0]);\n            return true;\n        }\n        case core::JointType::Ball: {\n            const auto maxVelocity0 = maxVelocity[0];\n\n            for (const auto max : maxVelocity) {\n                if (max != maxVelocity0) {\n                    sWarning << \"Setting different velocity limits for each \"\n                             << \"DOF is not supported. \"\n                             << \"Using the limit of the first DOF.\"\n                             << std::endl;\n                    break;\n                }\n            }\n\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            axis.SetMaxVelocity(maxVelocity0);\n            return true;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no friction defined.\"\n                     << std::endl;\n            return false;\n    }\n\n    return false;\n}\n\nstd::vector<double> Joint::jointMaxGeneralizedForce() const\n{\n    std::vector<double> maxGeneralizedForce;\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic: {\n            const sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            maxGeneralizedForce = {axis.Effort()};\n            break;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n        case core::JointType::Ball:\n            sWarning << \"Type of Joint '\" << this->name()\n                     << \"' has no max effort defined\" << std::endl;\n            break;\n    }\n\n    return maxGeneralizedForce;\n}\n\nbool Joint::setJointMaxGeneralizedForce(const std::vector<double>& maxForce)\n{\n    if (!utils::parentModelJustCreated(*this)) {\n        sError << \"The model has been already processed and its \"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    if (maxForce.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    switch (this->type()) {\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic:\n        case core::JointType::Ball: {\n            sdf::JointAxis& axis = utils::getExistingComponentData< //\n                ignition::gazebo::components::JointAxis>(m_ecm, m_entity);\n            assert(maxForce.size() == 1);\n            axis.SetEffort(maxForce[0]);\n            return true;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Invalid:\n            sWarning << \"Fixed and Invalid joints have no maxim effort defined.\"\n                     << std::endl;\n            return false;\n    }\n\n    return false;\n}\n\nstd::vector<double> Joint::jointPosition() const\n{\n    const std::vector<double>& jointPosition = utils::getExistingComponentData<\n        ignition::gazebo::components::JointPosition>(m_ecm, m_entity);\n\n    if (jointPosition.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), jointPosition.size(), this->name());\n    }\n\n    return jointPosition;\n}\n\nstd::vector<double> Joint::jointVelocity() const\n{\n    const std::vector<double>& jointVelocity = utils::getExistingComponentData<\n        ignition::gazebo::components::JointVelocity>(m_ecm, m_entity);\n\n    if (jointVelocity.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), jointVelocity.size(), this->name());\n    }\n\n    return jointVelocity;\n}\n\nstd::vector<double> Joint::jointAcceleration() const\n{\n    const std::vector<double>& jointAcceleration =\n        utils::getExistingComponentData< //\n            ignition::gazebo::components::JointAcceleration>(m_ecm, m_entity);\n\n    if (jointAcceleration.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), jointAcceleration.size(), this->name());\n    }\n\n    return jointAcceleration;\n}\n\nstd::vector<double> Joint::jointGeneralizedForce() const\n{\n    const std::vector<double>& jointGeneralizedForce =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::JointForce>(m_ecm, m_entity);\n\n    if (jointGeneralizedForce.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), jointGeneralizedForce.size(), this->name());\n    }\n\n    return jointGeneralizedForce;\n}\n\nbool Joint::setJointPositionTarget(const std::vector<double>& position)\n{\n    if (position.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointPositionTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointPositionTarget>(m_ecm, m_entity);\n\n    jointPositionTarget = position;\n    return true;\n}\n\nbool Joint::setJointVelocityTarget(const std::vector<double>& velocity)\n{\n    if (velocity.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointVelocityTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointVelocityTarget>(m_ecm, m_entity);\n\n    jointVelocityTarget = velocity;\n    return true;\n}\n\nbool Joint::setJointAccelerationTarget(const std::vector<double>& acceleration)\n{\n    if (acceleration.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointAccelerationTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointAccelerationTarget>(m_ecm, m_entity);\n\n    jointAccelerationTarget = acceleration;\n    return true;\n}\n\nbool Joint::setJointGeneralizedForceTarget(const std::vector<double>& force)\n{\n    if (force.size() != this->dofs()) {\n        sError << \"Wrong number of elements (joint_dofs=\" << this->dofs() << \")\"\n               << std::endl;\n        return false;\n    }\n\n    auto& jointForceTarget = utils::getComponentData< //\n        ignition::gazebo::components::JointForceCmd>(m_ecm, m_entity);\n\n    const std::vector<double>& maxForce = this->jointMaxGeneralizedForce();\n\n    for (size_t dof = 0; dof < this->dofs(); ++dof) {\n        if (std::abs(force[dof]) > maxForce[dof]) {\n            sWarning << \"The force target is higher than the limit. \"\n                     << \"The physics engine might clip it.\" << std::endl;\n        }\n    }\n\n    // Set the component data\n    jointForceTarget = force;\n    return true;\n}\n\nstd::vector<double> Joint::jointPositionTarget() const\n{\n    const std::vector<double>& target = utils::getExistingComponentData<\n        ignition::gazebo::components::JointPositionTarget>(m_ecm, m_entity);\n\n    if (target.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), target.size(), this->name());\n    }\n\n    return target;\n}\n\nstd::vector<double> Joint::jointVelocityTarget() const\n{\n    const std::vector<double>& target = utils::getExistingComponentData<\n        ignition::gazebo::components::JointVelocityTarget>(m_ecm, m_entity);\n\n    if (target.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), target.size(), this->name());\n    }\n\n    return target;\n}\n\nstd::vector<double> Joint::jointAccelerationTarget() const\n{\n    const std::vector<double>& target = utils::getExistingComponentData<\n        ignition::gazebo::components::JointAccelerationTarget>(m_ecm, m_entity);\n\n    if (target.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), target.size(), this->name());\n    }\n\n    return target;\n}\n\nstd::vector<double> Joint::jointGeneralizedForceTarget() const\n{\n    const std::vector<double>& target = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointForceCmd>(m_ecm, m_entity);\n\n    if (target.size() != this->dofs()) {\n        throw exceptions::DOFMismatch(\n            this->dofs(), target.size(), this->name());\n    }\n\n    return target;\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/Link.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/Link.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/components/ExternalWorldWrenchCmdWithDuration.h\"\n#include \"scenario/gazebo/components/SimulatedTime.h\"\n#include \"scenario/gazebo/exceptions.h\"\n#include \"scenario/gazebo/helpers.h\"\n#include \"scenario/gazebo/utils.h\"\n\n#include <ignition/gazebo/Link.hh>\n#include <ignition/gazebo/components/AngularAcceleration.hh>\n#include <ignition/gazebo/components/AngularVelocity.hh>\n#include <ignition/gazebo/components/CanonicalLink.hh>\n#include <ignition/gazebo/components/Collision.hh>\n#include <ignition/gazebo/components/ContactSensorData.hh>\n#include <ignition/gazebo/components/Inertial.hh>\n#include <ignition/gazebo/components/LinearAcceleration.hh>\n#include <ignition/gazebo/components/LinearVelocity.hh>\n#include <ignition/gazebo/components/Model.hh>\n#include <ignition/gazebo/components/ParentEntity.hh>\n#include <ignition/gazebo/components/Pose.hh>\n#include <ignition/math/Inertial.hh>\n#include <ignition/math/Pose3.hh>\n#include <ignition/math/Quaternion.hh>\n#include <ignition/math/Vector3.hh>\n#include <ignition/msgs/contacts.pb.h>\n\n#include <cassert>\n#include <chrono>\n#include <optional>\n\nusing namespace scenario::gazebo;\n\nclass Link::Impl\n{\npublic:\n    ignition::gazebo::Link link;\n\n    static ignition::math::Pose3d GetWorldPose(const Link& link,\n                                               const Link::Impl& impl)\n    {\n        if (!impl.link.IsCanonical(*link.ecm())) {\n            const auto& linkPoseOptional = impl.link.WorldPose(*link.ecm());\n\n            if (!linkPoseOptional.has_value()) {\n                throw exceptions::LinkError(\"Failed to get world position\",\n                                            link.name());\n            }\n\n            return linkPoseOptional.value();\n        }\n        else {\n            const auto& parentModelOptional =\n                impl.link.ParentModel(*link.ecm());\n            assert(parentModelOptional.has_value());\n\n            const ignition::gazebo::Model& parentModel =\n                parentModelOptional.value();\n            const ignition::gazebo::Entity parentModelEntity =\n                parentModel.Entity();\n\n            auto W_H_M = utils::getExistingComponentData<\n                ignition::gazebo::components::Pose>(link.ecm(),\n                                                    parentModelEntity);\n\n            auto M_H_B = utils::getExistingComponentData<\n                ignition::gazebo::components::Pose>(link.ecm(), link.entity());\n\n            return W_H_M * M_H_B;\n        }\n    }\n};\n\nLink::Link()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nLink::~Link() = default;\n\nuint64_t Link::id() const\n{\n    // Get the parent world\n    const core::WorldPtr parentWorld = utils::getParentWorld(*this);\n    assert(parentWorld);\n\n    // Build a unique string identifier of this joint\n    const std::string scopedLinkName =\n        parentWorld->name() + \"::\" + this->name(/*scoped=*/true);\n\n    // Return the hashed string\n    return std::hash<std::string>{}(scopedLinkName);\n}\n\nbool Link::initialize(const ignition::gazebo::Entity linkEntity,\n                      ignition::gazebo::EntityComponentManager* ecm,\n                      ignition::gazebo::EventManager* eventManager)\n{\n    if (linkEntity == ignition::gazebo::kNullEntity || !ecm || !eventManager) {\n        sError << \"Failed to initialize Link\" << std::endl;\n        return false;\n    }\n\n    m_ecm = ecm;\n    m_entity = linkEntity;\n    m_eventManager = eventManager;\n\n    pImpl->link = ignition::gazebo::Link(linkEntity);\n\n    // Check that the link is valid\n    if (!pImpl->link.Valid(*ecm)) {\n        sError << \"The link entity is not valid\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Link::createECMResources()\n{\n    sMessage << \"  [\" << m_entity << \"] \" << this->name() << std::endl;\n\n    using namespace ignition::gazebo;\n\n    // Create link components\n    m_ecm->CreateComponent(m_entity, //\n                           components::WorldPose());\n    m_ecm->CreateComponent(m_entity, components::WorldLinearVelocity());\n    m_ecm->CreateComponent(m_entity, components::WorldAngularVelocity());\n    m_ecm->CreateComponent(m_entity, components::WorldLinearAcceleration());\n    m_ecm->CreateComponent(m_entity, components::WorldAngularAcceleration());\n    m_ecm->CreateComponent(m_entity, components::LinearVelocity());\n    m_ecm->CreateComponent(m_entity, components::AngularVelocity());\n    m_ecm->CreateComponent(m_entity, components::LinearAcceleration());\n    m_ecm->CreateComponent(m_entity, components::AngularAcceleration());\n\n    if (!this->enableContactDetection(false)) {\n        sError << \"Failed to initialize contact detection\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Link::insertLinkPlugin(const std::string& libName,\n                            const std::string& className,\n                            const std::string& context)\n{\n    return utils::insertPluginToGazeboEntity(\n        *this, libName, className, context);\n}\n\nbool Link::valid() const\n{\n    return this->validEntity() && pImpl->link.Valid(*m_ecm);\n}\n\nstd::string Link::name(const bool scoped) const\n{\n    const auto& linkNameOptional = pImpl->link.Name(*m_ecm);\n\n    if (!linkNameOptional) {\n        throw exceptions::LinkError(\"Failed to get link name\");\n    }\n\n    std::string linkName = linkNameOptional.value();\n\n    if (scoped) {\n        linkName = utils::getParentModel(*this)->name() + \"::\" + linkName;\n    }\n\n    return linkName;\n}\n\ndouble Link::mass() const\n{\n    const auto& inertial = utils::getExistingComponentData< //\n        ignition::gazebo::components::Inertial>(m_ecm, m_entity);\n\n    return inertial.MassMatrix().Mass();\n}\n\nstd::array<double, 3> Link::position() const\n{\n    const ignition::math::Pose3d& linkPose = Impl::GetWorldPose(*this, *pImpl);\n    return utils::fromIgnitionPose(linkPose).position;\n}\n\nstd::array<double, 4> Link::orientation() const\n{\n    const ignition::math::Pose3d& linkPose = Impl::GetWorldPose(*this, *pImpl);\n    return utils::fromIgnitionPose(linkPose).orientation;\n}\n\nstd::array<double, 3> Link::worldLinearVelocity() const\n{\n    const auto& linkLinearVelocity = pImpl->link.WorldLinearVelocity(*m_ecm);\n\n    if (!linkLinearVelocity) {\n        throw exceptions::LinkError(\"Failed to get linear velocity\",\n                                    this->name());\n    }\n\n    return utils::fromIgnitionVector(linkLinearVelocity.value());\n}\n\nstd::array<double, 3> Link::worldAngularVelocity() const\n{\n    const auto& linkAngularVelocity = pImpl->link.WorldAngularVelocity(*m_ecm);\n\n    if (!linkAngularVelocity) {\n        throw exceptions::LinkError(\"Failed to get angular velocity\",\n                                    this->name());\n    }\n\n    return utils::fromIgnitionVector(linkAngularVelocity.value());\n}\n\nstd::array<double, 3> Link::bodyLinearVelocity() const\n{\n    const auto& linkBodyLinVel = utils::getComponentData< //\n        ignition::gazebo::components::LinearVelocity>(m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(linkBodyLinVel);\n}\n\nstd::array<double, 3> Link::bodyAngularVelocity() const\n{\n    const auto& linkBodyAngVel = utils::getComponentData< //\n        ignition::gazebo::components::AngularVelocity>(m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(linkBodyAngVel);\n}\n\nstd::array<double, 3> Link::worldLinearAcceleration() const\n{\n    const auto& linkLinearAcceleration =\n        pImpl->link.WorldLinearAcceleration(*m_ecm);\n\n    if (!linkLinearAcceleration) {\n        throw exceptions::LinkError(\"Failed to get linear acceleration\",\n                                    this->name());\n    }\n\n    return utils::fromIgnitionVector(linkLinearAcceleration.value());\n}\n\nstd::array<double, 3> Link::worldAngularAcceleration() const\n{\n    const auto& linkWorldAngAcc = utils::getComponentData<\n        ignition::gazebo::components::WorldAngularAcceleration>(m_ecm,\n                                                                m_entity);\n\n    return utils::fromIgnitionVector(linkWorldAngAcc);\n}\n\nstd::array<double, 3> Link::bodyLinearAcceleration() const\n{\n    const auto& linkBodyLinAcc = utils::getComponentData<\n        ignition::gazebo::components::LinearAcceleration>(m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(linkBodyLinAcc);\n}\n\nstd::array<double, 3> Link::bodyAngularAcceleration() const\n{\n    const auto& linkBodyAngAcc = utils::getComponentData<\n        ignition::gazebo::components::AngularAcceleration>(m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(linkBodyAngAcc);\n}\n\nbool Link::contactsEnabled() const\n{\n    const auto& collisionEntities = m_ecm->ChildrenByComponents(\n        m_entity,\n        ignition::gazebo::components::Collision(),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    // If the link has no collision elements, we return true regardless.\n    // To prevent surprises, e.g. users expecting that calling Link::inContact\n    // for such links would return true, we print a debug message.\n    if (collisionEntities.empty()) {\n        sDebug << \"The link '\" << this->name() << \"' has no collision elements \"\n               << \"and contacts cannot be detected\" << std::endl;\n        return true;\n    }\n\n    // Iterate through all link's collisions\n    for (const auto collisionEntity : collisionEntities) {\n        const bool hasContactSensorData = m_ecm->EntityHasComponentType(\n            collisionEntity,\n            ignition::gazebo::components::ContactSensorData::typeId);\n\n        // Return false if a collision does not have the contact data component\n        if (!hasContactSensorData) {\n            return false;\n        }\n    }\n\n    // We return true only if contacts are enables on all collision entities\n    return true;\n}\n\nbool Link::enableContactDetection(const bool enable)\n{\n    if (enable && !this->contactsEnabled()) {\n        // Get all the collision entities of this link\n        const auto& collisionEntities = m_ecm->ChildrenByComponents(\n            m_entity,\n            ignition::gazebo::components::Collision(),\n            ignition::gazebo::components::ParentEntity(m_entity));\n\n        // Create the contact sensor data component that enables the Physics\n        // system to extract contact information from the physics engine\n        for (const auto collisionEntity : collisionEntities) {\n            m_ecm->CreateComponent(\n                collisionEntity,\n                ignition::gazebo::components::ContactSensorData());\n        }\n\n        return true;\n    }\n\n    if (!enable && this->contactsEnabled()) {\n        // Get all the collision entities of this link\n        const auto& collisionEntities = m_ecm->ChildrenByComponents(\n            m_entity,\n            ignition::gazebo::components::Collision(),\n            ignition::gazebo::components::ParentEntity(m_entity));\n\n        // Links with no collision elements already print a sDebug in the\n        // contactsEnabled method, and not further action is needed\n        if (collisionEntities.empty()) {\n            return true;\n        }\n\n        // Delete the contact sensor data component\n        for (const auto collisionEntity : collisionEntities) {\n            m_ecm->RemoveComponent<\n                ignition::gazebo::components::ContactSensorData>(\n                collisionEntity);\n        }\n\n        if (this->contactsEnabled()) {\n            sError << \"Failed to disable contact detection\" << std::endl;\n            return false;\n        }\n\n        return true;\n    }\n\n    return true;\n}\n\nbool Link::inContact() const\n{\n    return this->contacts().empty() ? false : true;\n}\n\nstd::vector<scenario::core::Contact> Link::contacts() const\n{\n    // Get the collisions of this link\n    const auto& collisionEntities = m_ecm->EntitiesByComponents(\n        ignition::gazebo::components::ParentEntity(m_entity),\n        ignition::gazebo::components::Collision());\n\n    // Return early if the link has no collision elements\n    if (collisionEntities.empty()) {\n        return {};\n    }\n\n    using BodyNameA = std::string;\n    using BodyNameB = std::string;\n    using CollisionsInContact = std::pair<BodyNameA, BodyNameB>;\n    auto contactsMap = std::map<CollisionsInContact, core::Contact>();\n\n    for (const auto collisionEntity : collisionEntities) {\n\n        // Skip collisions entities without contact sensor\n        if (!m_ecm->EntityHasComponentType(\n                collisionEntity,\n                ignition::gazebo::components::ContactSensorData::typeId)) {\n            continue;\n        }\n\n        // Get the contact data for the selected collision entity\n        const ignition::msgs::Contacts& contactSensorData =\n            utils::getExistingComponentData<\n                ignition::gazebo::components::ContactSensorData>(\n                m_ecm, collisionEntity);\n\n        // Convert the ignition msg\n        const std::vector<core::Contact>& collisionContacts =\n            utils::fromIgnitionContactsMsgs(m_ecm, contactSensorData);\n\n        for (const auto& contact : collisionContacts) {\n            assert(!contact.bodyA.empty());\n            assert(!contact.bodyB.empty());\n\n            // Create the key that collects the entry containing the\n            // Contact object of the pair of bodies\n            const auto key = std::make_pair(contact.bodyA, contact.bodyB);\n\n            if (contactsMap.find(key) != contactsMap.end()) {\n                // Get the existing contact object\n                auto& thisContact = contactsMap.at(key);\n\n                // Insert the new points\n                thisContact.points.insert(thisContact.points.end(),\n                                          contact.points.begin(),\n                                          contact.points.end());\n            }\n            else {\n                // Create a new Contact\n                contactsMap[key] = contact;\n            }\n        }\n    }\n\n    // Copy data from the map to the output vector\n    // TODO: any trick to move values from the map to the vector?\n    std::vector<core::Contact> allContacts;\n    allContacts.reserve(contactsMap.size());\n\n    for (const auto& [_, contact] : contactsMap) {\n        allContacts.push_back(contact);\n    }\n\n    return allContacts;\n}\n\nstd::array<double, 6> Link::contactWrench() const\n{\n    auto totalForce = ignition::math::Vector3d::Zero;\n    auto totalTorque = ignition::math::Vector3d::Zero;\n\n    const auto& contacts = this->contacts();\n\n    for (const auto& contact : contacts) {\n        // Each contact wrench is expressed with respect to the contact point\n        // and with the orientation of the world frame. We need to translate it\n        // to the link frame.\n\n        for (const auto& contactPoint : contact.points) {\n            // The contact points extracted from the physics do not have torque\n            constexpr std::array<double, 3> zero = {0, 0, 0};\n            assert(contactPoint.torque == zero);\n\n            // Link position\n            const auto& o_L = utils::toIgnitionVector3(this->position());\n\n            // Contact position\n            const auto& o_P = utils::toIgnitionVector3(contactPoint.position);\n\n            // Relative position\n            const auto L_o_P = o_P - o_L;\n\n            // The contact force and the total link force are both expressed\n            // with the orientation of the world frame. This simplifies the\n            // conversion since we have to take into account only the\n            // displacement.\n            const auto& force = utils::toIgnitionVector3(contactPoint.force);\n\n            // The force does not have to be changed\n            totalForce += force;\n\n            // There is however a torque that balances out the resulting moment\n            totalTorque += L_o_P.Cross(force);\n        }\n    }\n\n    return {totalForce[0],\n            totalForce[1],\n            totalForce[2],\n            totalTorque[0],\n            totalTorque[1],\n            totalTorque[2]};\n}\n\nbool Link::applyWorldForce(const std::array<double, 3>& force,\n                           const double duration)\n{\n    return this->applyWorldWrench(force, {0, 0, 0}, duration);\n}\n\nbool Link::applyWorldTorque(const std::array<double, 3>& torque,\n                            const double duration)\n{\n    return this->applyWorldWrench({0, 0, 0}, torque, duration);\n}\n\nbool Link::applyWorldWrench(const std::array<double, 3>& force,\n                            const std::array<double, 3>& torque,\n                            const double duration)\n{\n    // Adapted from ignition::gazebo::Link::AddWorld{Force,Wrench}\n\n    // Initialize the force and the torque with the input data\n    const auto& forceIgnitionMath = utils::toIgnitionVector3(force);\n    const auto& torqueIgnitionMath = utils::toIgnitionVector3(torque);\n\n    const auto entityWithSimTime = utils::getFirstParentEntityWithComponent<\n        ignition::gazebo::components::SimulatedTime>(m_ecm, m_entity);\n    assert(entityWithSimTime != ignition::gazebo::kNullEntity);\n\n    // Get the current simulated time\n    const auto& now = utils::getExistingComponentData<\n        ignition::gazebo::components::SimulatedTime>(m_ecm, entityWithSimTime);\n\n    // Create a new wrench with duration\n    const utils::WrenchWithDuration wrench(\n        forceIgnitionMath,\n        torqueIgnitionMath,\n        utils::doubleToSteadyClockDuration(duration),\n        now);\n\n    utils::LinkWrenchCmd& linkWrenchCmd = utils::getComponentData<\n        ignition::gazebo::components::ExternalWorldWrenchCmdWithDuration>(\n        m_ecm, m_entity);\n\n    linkWrenchCmd.addWorldWrench(wrench);\n    return true;\n}\n\nbool Link::applyWorldWrenchToCoM(const std::array<double, 3>& force,\n                                 const std::array<double, 3>& torque,\n                                 const double duration)\n{\n    const ignition::math::Pose3d& worldPose = Impl::GetWorldPose(*this, *pImpl);\n\n    // Get the data of the inertial frame\n    auto inertial = utils::getExistingComponentData< //\n        ignition::gazebo::components::Inertial>(m_ecm, m_entity);\n\n    // We want the force to be applied at the center of mass, but\n    // ExternalWorldWrenchCmd applies the force at the link origin so we need to\n    // compute the resulting force and torque on the link origin.\n\n    // Compute W_o_I = W_R_L * L_o_I\n    auto linkCOMInWorldCoordinates =\n        worldPose.Rot().RotateVector(inertial.Pose().Pos());\n\n    // Initialize the force and the torque with the input data\n    const auto forceIgnitionMath = utils::toIgnitionVector3(force);\n    auto torqueIgnitionMath = utils::toIgnitionVector3(torque);\n\n    // Sum the component given by the projection of the force to the link origin\n    torqueIgnitionMath += linkCOMInWorldCoordinates.Cross(forceIgnitionMath);\n\n    return this->applyWorldWrench(utils::fromIgnitionVector(forceIgnitionMath),\n                                  utils::fromIgnitionVector(torqueIgnitionMath),\n                                  duration);\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/Model.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/Joint.h\"\n#include \"scenario/gazebo/Link.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/components/BasePoseTarget.h\"\n#include \"scenario/gazebo/components/BaseWorldAccelerationTarget.h\"\n#include \"scenario/gazebo/components/BaseWorldVelocityTarget.h\"\n#include \"scenario/gazebo/components/JointControllerPeriod.h\"\n#include \"scenario/gazebo/components/Timestamp.h\"\n#include \"scenario/gazebo/exceptions.h\"\n#include \"scenario/gazebo/helpers.h\"\n#include \"scenario/gazebo/utils.h\"\n\n#include <ignition/common/Event.hh>\n#include <ignition/gazebo/Events.hh>\n#include <ignition/gazebo/Model.hh>\n#include <ignition/gazebo/components/AngularVelocityCmd.hh>\n#include <ignition/gazebo/components/CanonicalLink.hh>\n#include <ignition/gazebo/components/Joint.hh>\n#include <ignition/gazebo/components/LinearVelocityCmd.hh>\n#include <ignition/gazebo/components/Link.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/ParentEntity.hh>\n#include <ignition/gazebo/components/Pose.hh>\n#include <ignition/gazebo/components/PoseCmd.hh>\n#include <ignition/gazebo/components/SelfCollide.hh>\n#include <ignition/math/Pose3.hh>\n#include <ignition/math/Vector3.hh>\n#include <sdf/Element.hh>\n#include <sdf/Root.hh>\n\n#include <algorithm>\n#include <cassert>\n#include <chrono>\n#include <functional>\n#include <tuple>\n#include <unordered_map>\n\nusing namespace scenario::gazebo;\n\nclass Model::Impl\n{\npublic:\n    ignition::gazebo::Model model;\n\n    using LinkName = std::string;\n    using JointName = std::string;\n\n    std::unordered_map<LinkName, core::LinkPtr> links;\n    std::unordered_map<JointName, core::JointPtr> joints;\n\n    struct\n    {\n        std::vector<std::string> linksInContact;\n        std::optional<std::vector<std::string>> linkNames;\n        std::optional<std::vector<std::string>> scopedLinkNames;\n        std::optional<std::vector<std::string>> jointNames;\n        std::optional<std::vector<std::string>> scopedJointNames;\n    } buffers;\n\n    static std::vector<double> getJointDataSerialized(\n        const Model* model,\n        const std::vector<std::string>& jointNames,\n        std::function<double(core::JointPtr, const size_t)> getJointData);\n\n    static bool setJointDataSerialized(\n        Model* model,\n        const std::vector<double>& data,\n        const std::vector<std::string>& jointNames,\n        std::function<bool(core::JointPtr, const double, const size_t)>\n            setDataToDOF);\n};\n\nModel::Model()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nModel::~Model() = default;\n\nuint64_t Model::id() const\n{\n    // Get the parent world\n    const core::WorldPtr parentWorld = utils::getParentWorld(*this);\n    assert(parentWorld);\n\n    // Build a unique string identifier of this model\n    const std::string scopedModelName =\n        parentWorld->name() + \"::\" + this->name();\n\n    // Return the hashed string\n    return std::hash<std::string>{}(scopedModelName);\n}\n\nbool Model::initialize(const ignition::gazebo::Entity modelEntity,\n                       ignition::gazebo::EntityComponentManager* ecm,\n                       ignition::gazebo::EventManager* eventManager)\n{\n    if (modelEntity == ignition::gazebo::kNullEntity || !ecm || !eventManager) {\n        return false;\n    }\n\n    m_ecm = ecm;\n    m_entity = modelEntity;\n    m_eventManager = eventManager;\n\n    // Create the model\n    pImpl->model = ignition::gazebo::Model(modelEntity);\n\n    // Check that the model is valid\n    if (!pImpl->model.Valid(*ecm)) {\n        sError << \"The model entity is not valid\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Model::createECMResources()\n{\n    sMessage << \"Model: [\" << m_entity << \"] \" << this->name() << std::endl;\n\n    // When the model is inserted, store the time of creation\n    if (!m_ecm->EntityHasComponentType(\n            m_entity, ignition::gazebo::components::Timestamp::typeId)) {\n        const auto& parentWorld = utils::getParentWorld(*this);\n        utils::setComponentData<ignition::gazebo::components::Timestamp>(\n            m_ecm,\n            m_entity,\n            utils::doubleToSteadyClockDuration(parentWorld->time()));\n    }\n\n    // Create required link resources\n    sMessage << \"Links:\" << std::endl;\n    for (const auto& link : this->links()) {\n        if (!std::static_pointer_cast<Link>(link)->createECMResources()) {\n            sError << \"Failed to initialize ECM link resources\" << std::endl;\n            return false;\n        }\n    }\n\n    // Create required model resources\n    sMessage << \"Joints:\" << std::endl;\n    for (const auto& joint : this->joints()) {\n        if (!std::static_pointer_cast<Joint>(joint)->createECMResources()) {\n            sError << \"Failed to initialize ECM joint resources\" << std::endl;\n            return false;\n        }\n    }\n\n    if (!this->enableSelfCollisions(false)) {\n        sError << \"Failed to initialize disabled self collisions\" << std::endl;\n        return false;\n    }\n\n    // Initialize the Joint Controller period as maximum duration.\n    // In this way controllers are never updated unless a new period is\n    // configured.\n    m_ecm->CreateComponent(m_entity,\n                           ignition::gazebo::components::JointControllerPeriod(\n                               std::chrono::steady_clock::duration().max()));\n\n    return true;\n}\n\nbool Model::insertModelPlugin(const std::string& libName,\n                              const std::string& className,\n                              const std::string& context)\n{\n    return utils::insertPluginToGazeboEntity(\n        *this, libName, className, context);\n}\n\nbool Model::resetJointPositions(const std::vector<double>& positions,\n                                const std::vector<std::string>& jointNames)\n{\n    auto lambda = [](core::JointPtr joint,\n                     const double position,\n                     const size_t dof) -> bool {\n        return std::static_pointer_cast<Joint>(joint)->resetPosition(position,\n                                                                     dof);\n    };\n\n    return Impl::setJointDataSerialized(this, positions, jointNames, lambda);\n}\n\nbool Model::resetJointVelocities(const std::vector<double>& velocities,\n                                 const std::vector<std::string>& jointNames)\n{\n    auto lambda = [](core::JointPtr joint,\n                     const double velocity,\n                     const size_t dof) -> bool {\n        return std::static_pointer_cast<Joint>(joint)->resetVelocity(velocity,\n                                                                     dof);\n    };\n\n    return Impl::setJointDataSerialized(this, velocities, jointNames, lambda);\n}\n\nbool Model::resetBasePose(const std::array<double, 3>& position,\n                          const std::array<double, 4>& orientation)\n{\n    // Construct the desired transform between world and base\n    const core::Pose pose(position, orientation);\n    ignition::math::Pose3d world_H_base = utils::toIgnitionPose(pose);\n\n    // Get the entity of the canonical link\n    const auto canonicalLinkEntity = m_ecm->EntityByComponents(\n        ignition::gazebo::components::Link(),\n        ignition::gazebo::components::CanonicalLink(),\n        ignition::gazebo::components::Name(this->baseFrame()),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    if (canonicalLinkEntity == ignition::gazebo::kNullEntity) {\n        sError << \"Failed to get entity of canonical link\" << std::endl;\n        return false;\n    }\n\n    // Get the Pose component of the canonical link.\n    // This is the fixed transformation between the model and the base.\n    auto& model_H_base = utils::getExistingComponentData< //\n        ignition::gazebo::components::Pose>(m_ecm, canonicalLinkEntity);\n\n    // Compute the robot pose that corresponds to the desired base pose\n    const ignition::math::Pose3d& world_H_model =\n        world_H_base * model_H_base.Inverse();\n\n    // Store the new pose\n    utils::setComponentData<ignition::gazebo::components::WorldPoseCmd>(\n        m_ecm, m_entity, world_H_model);\n\n    return true;\n}\n\nbool Model::resetBasePosition(const std::array<double, 3>& position)\n{\n    return this->resetBasePose(position, this->baseOrientation());\n}\n\nbool Model::resetBaseOrientation(const std::array<double, 4>& orientation)\n{\n    return this->resetBasePose(this->basePosition(), orientation);\n}\n\nbool Model::resetBaseWorldLinearVelocity(const std::array<double, 3>& linear)\n{\n    // Note: there could be a rigid transformation between the base frame and\n    //       the canonical frame. The Physics system processes velocity commands\n    //       in the canonical frame, but this method receives velocity commands\n    //       of in the base frame (all expressed in world coordinates).\n    //       Therefore, we need to compute the base linear velocity from the\n    //       base frame to the canonical frame.\n\n    // Get the entity of the canonical (base) link\n    const auto canonicalLinkEntity = m_ecm->EntityByComponents(\n        ignition::gazebo::components::Link(),\n        ignition::gazebo::components::CanonicalLink(),\n        ignition::gazebo::components::Name(this->baseFrame()),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    // Get the Pose component of the canonical link.\n    // This is the fixed transformation between the model and the base.\n    const auto& M_H_B = utils::getExistingComponentData< //\n        ignition::gazebo::components::Pose>(m_ecm, canonicalLinkEntity);\n\n    // Get the rotation between base link and world\n    const auto& W_R_B = utils::toIgnitionQuaternion(\n        this->getLink(this->baseFrame())->orientation());\n\n    // Compute the linear part of the base link mixed velocity\n    const ignition::math::Vector3d baseLinearWorldVelocity =\n        utils::fromModelToBaseLinearVelocity(\n            utils::toIgnitionVector3(linear),\n            utils::toIgnitionVector3(this->baseWorldAngularVelocity()),\n            M_H_B,\n            W_R_B);\n\n    // Store the new velocity\n    utils::setComponentData<ignition::gazebo::components::LinearVelocityCmd>(\n        m_ecm, m_entity, baseLinearWorldVelocity);\n\n    return true;\n}\n\nbool Model::resetBaseWorldAngularVelocity(const std::array<double, 3>& angular)\n{\n    // Note: the angular part of the velocity does not change between the base\n    //       link and the canonical link (as the linear part).\n    //       In fact, the angular velocity is invariant if there's a rigid\n    //       transformation between the two frames, like in this case.\n    utils::setComponentData<ignition::gazebo::components::AngularVelocityCmd>(\n        m_ecm, m_entity, utils::toIgnitionVector3(angular));\n\n    return true;\n}\n\nbool Model::resetBaseWorldVelocity(const std::array<double, 3>& linear,\n                                   const std::array<double, 3>& angular)\n{\n    return this->resetBaseWorldLinearVelocity(linear)\n           && this->resetBaseWorldAngularVelocity(angular);\n}\n\nbool Model::valid() const\n{\n    return this->validEntity() && pImpl->model.Valid(*m_ecm);\n}\n\nsize_t Model::dofs(const std::vector<std::string>& jointNames) const\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    size_t dofs = 0;\n\n    for (const auto& jointName : jointSerialization) {\n        dofs += this->getJoint(jointName)->dofs();\n    }\n\n    return dofs;\n}\n\nstd::string Model::name() const\n{\n    return pImpl->model.Name(*m_ecm);\n}\n\nsize_t Model::nrOfLinks() const\n{\n    return this->linkNames().size();\n}\n\nsize_t Model::nrOfJoints() const\n{\n    return this->jointNames().size();\n}\n\ndouble Model::totalMass(const std::vector<std::string>& linkNames) const\n{\n    const std::vector<std::string>& linkSerialization =\n        linkNames.empty() ? this->linkNames() : linkNames;\n\n    double mass = 0.0;\n\n    for (const auto& link : this->links(linkSerialization)) {\n        mass += link->mass();\n    }\n\n    return mass;\n}\n\nscenario::core::LinkPtr Model::getLink(const std::string& linkName) const\n{\n    if (pImpl->links.find(linkName) != pImpl->links.end()) {\n        assert(pImpl->links.at(linkName));\n        return pImpl->links.at(linkName);\n    }\n\n    const auto linkEntity = pImpl->model.LinkByName(*m_ecm, linkName);\n\n    if (linkEntity == ignition::gazebo::kNullEntity) {\n        throw exceptions::LinkNotFound(linkName);\n    }\n\n    // Create the link\n    auto link = std::make_shared<scenario::gazebo::Link>();\n\n    if (!link->initialize(linkEntity, m_ecm, m_eventManager)) {\n        throw exceptions::LinkError(\"Failed to initialize link\", linkName);\n    }\n\n    // Cache the link instance\n    pImpl->links[linkName] = link;\n\n    return link;\n}\n\nscenario::core::JointPtr Model::getJoint(const std::string& jointName) const\n{\n    if (pImpl->joints.find(jointName) != pImpl->joints.end()) {\n        assert(pImpl->joints.at(jointName));\n        return pImpl->joints.at(jointName);\n    }\n\n    const auto jointEntity = pImpl->model.JointByName(*m_ecm, jointName);\n\n    if (jointEntity == ignition::gazebo::kNullEntity) {\n        throw exceptions::JointNotFound(jointName);\n    }\n\n    // Create the joint\n    auto joint = std::make_shared<scenario::gazebo::Joint>();\n\n    if (!joint->initialize(jointEntity, m_ecm, m_eventManager)) {\n        throw exceptions::JointError(\"Failed to initialize joint\", jointName);\n    }\n\n    // Cache the joint instance\n    pImpl->joints[jointName] = joint;\n\n    return joint;\n}\n\nstd::vector<std::string> Model::linkNames(const bool scoped) const\n{\n    if (!scoped && pImpl->buffers.linkNames.has_value()) {\n        return pImpl->buffers.linkNames.value();\n    }\n\n    if (scoped && pImpl->buffers.scopedLinkNames.has_value()) {\n        return pImpl->buffers.scopedLinkNames.value();\n    }\n\n    std::vector<std::string> linkNames;\n\n    m_ecm->Each<ignition::gazebo::components::Name,\n                ignition::gazebo::components::Link,\n                ignition::gazebo::components::ParentEntity>(\n        [&](const ignition::gazebo::Entity& /*entity*/,\n            ignition::gazebo::components::Name* nameComponent,\n            ignition::gazebo::components::Link* /*linkComponent*/,\n            ignition::gazebo::components::ParentEntity* parentEntityComponent)\n            -> bool {\n            assert(nameComponent);\n            assert(parentEntityComponent);\n\n            // Discard links not belonging to this model\n            if (parentEntityComponent->Data() != m_entity) {\n                return true;\n            }\n\n            std::string prefix = \"\";\n            if (scoped) {\n                prefix = this->name() + \"::\";\n            }\n\n            // Append the link name\n            linkNames.push_back(prefix + nameComponent->Data());\n            return true;\n        });\n\n    if (!scoped) {\n        pImpl->buffers.linkNames = std::move(linkNames);\n        return pImpl->buffers.linkNames.value();\n    }\n    else {\n        pImpl->buffers.scopedLinkNames = std::move(linkNames);\n        return pImpl->buffers.scopedLinkNames.value();\n    }\n}\n\nstd::vector<std::string> Model::jointNames(const bool scoped) const\n{\n    if (!scoped && pImpl->buffers.jointNames.has_value()) {\n        return pImpl->buffers.jointNames.value();\n    }\n\n    if (scoped && pImpl->buffers.scopedLinkNames.has_value()) {\n        return pImpl->buffers.scopedLinkNames.value();\n    }\n\n    std::vector<std::string> jointNames;\n\n    m_ecm->Each<ignition::gazebo::components::Name,\n                ignition::gazebo::components::Joint,\n                ignition::gazebo::components::ParentEntity>(\n        [&](const ignition::gazebo::Entity& /*jointEntity*/,\n            ignition::gazebo::components::Name* nameComponent,\n            ignition::gazebo::components::Joint* /*jointComponent*/,\n            ignition::gazebo::components::ParentEntity* parentEntityComponent)\n            -> bool {\n            assert(nameComponent);\n            assert(parentEntityComponent);\n\n            // Discard joints not belonging to this model\n            if (parentEntityComponent->Data() != m_entity) {\n                return true;\n            }\n\n            // Discard joints with no DoFs\n            auto joint = this->getJoint(nameComponent->Data());\n            if (joint->dofs() == 0) {\n                return true;\n            }\n\n            std::string prefix = \"\";\n            if (scoped) {\n                prefix = this->name() + \"::\";\n            }\n\n            // Append the joint name\n            jointNames.push_back(prefix + nameComponent->Data());\n            return true;\n        });\n\n    if (!scoped) {\n        pImpl->buffers.jointNames = std::move(jointNames);\n        return pImpl->buffers.jointNames.value();\n    }\n    else {\n        pImpl->buffers.scopedJointNames = std::move(jointNames);\n        return pImpl->buffers.scopedJointNames.value();\n    }\n}\n\ndouble Model::controllerPeriod() const\n{\n    const auto& duration = utils::getExistingComponentData< //\n        ignition::gazebo::components::JointControllerPeriod>(m_ecm, m_entity);\n\n    return utils::steadyClockDurationToDouble(duration);\n}\n\nbool Model::setControllerPeriod(const double period)\n{\n    if (period <= 0) {\n        sError << \"The controller period must be greater than zero\"\n               << std::endl;\n        return false;\n    }\n\n    // Store the new period in the ECM\n    utils::setExistingComponentData<\n        ignition::gazebo::components::JointControllerPeriod>(\n        m_ecm, m_entity, utils::doubleToSteadyClockDuration(period));\n    return true;\n}\n\nbool Model::enableHistoryOfAppliedJointForces(\n    const bool enable,\n    const size_t maxHistorySizePerJoint,\n    const std::vector<std::string>& jointNames)\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    bool ok = true;\n\n    for (const auto& joint : this->joints(jointSerialization)) {\n        ok = ok\n             && joint->enableHistoryOfAppliedJointForces(\n                 enable, maxHistorySizePerJoint);\n    }\n\n    return ok;\n}\n\nbool Model::historyOfAppliedJointForcesEnabled(\n    const std::vector<std::string>& jointNames) const\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    bool enabled = true;\n\n    for (const auto& joint : this->joints(jointSerialization)) {\n        enabled = enabled && joint->historyOfAppliedJointForcesEnabled();\n    }\n\n    return enabled;\n}\n\nstd::vector<double> Model::historyOfAppliedJointForces(\n    const std::vector<std::string>& jointNames) const\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    std::vector<double> history;\n    std::vector<double> allAppliedJointForces;\n\n    for (const auto& joint : this->joints(jointSerialization)) {\n        history = joint->historyOfAppliedJointForces();\n        std::move(history.begin(),\n                  history.end(),\n                  std::back_inserter(allAppliedJointForces));\n\n        if (joint->name() == jointSerialization.front()) {\n            history.reserve(jointSerialization.size() * history.size());\n        }\n    }\n\n    // Given:\n    // * <j_1>: vector 1xH of torques of joint 1\n    // * <tau_t>: vector 1xn of torques of the considered joints at a given t\n    //\n    // We want to convert the allAppliedJointForces:\n    // * From: <j_1><j_2>...<j_n>\n    // * To:   <tau_t-H>...<tau_t-2><tau_t-1><tau_t>\n    //\n    // In other words, we want that the torques applied at the last step are\n    // piled up in the end of the returned vector.\n    utils::rowMajorToColumnMajor(\n        allAppliedJointForces, jointSerialization.size(), history.size());\n\n    return allAppliedJointForces;\n}\n\nbool Model::contactsEnabled() const\n{\n    for (auto& link : this->links()) {\n        // Note: links with no collision elements return true even though no\n        //       contacts can be detected.\n        if (!link->contactsEnabled()) {\n            return false;\n        }\n    }\n\n    // Return true only if all links have enabled contact detection\n    return true;\n}\n\nbool Model::enableContacts(const bool enable)\n{\n    bool ok = true;\n\n    for (auto& link : this->links()) {\n        // Note: links with no collision elements return true even though no\n        //       contacts can be detected.\n        ok = ok && link->enableContactDetection(enable);\n    }\n\n    return ok;\n}\n\nbool Model::selfCollisionsEnabled() const\n{\n    const bool selfCollisionsEnabled = utils::getExistingComponentData<\n        ignition::gazebo::components::SelfCollide>(m_ecm, m_entity);\n\n    return selfCollisionsEnabled;\n}\n\nbool Model::enableSelfCollisions(const bool enable)\n{\n    if (!utils::parentModelJustCreated(*this)) {\n        sError << \"The model has been already processed and its \"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    // Enable contact detection first\n    if (enable && !this->enableContacts(true)) {\n        sError << \"Failed to enable contact detection\" << std::endl;\n        return false;\n    }\n\n    utils::setExistingComponentData<ignition::gazebo::components::SelfCollide>(\n        m_ecm, m_entity, enable);\n\n    return true;\n}\n\nstd::vector<std::string> Model::linksInContact() const\n{\n    pImpl->buffers.linksInContact.clear();\n\n    for (const auto& link : this->links()) {\n        if (link->inContact()) {\n            pImpl->buffers.linksInContact.push_back(link->name());\n        }\n    }\n\n    return pImpl->buffers.linksInContact;\n}\n\nstd::vector<scenario::core::Contact>\nModel::contacts(const std::vector<std::string>& linkNames) const\n{\n    const std::vector<std::string>& linkSerialization =\n        linkNames.empty() ? this->linkNames() : linkNames;\n\n    std::vector<scenario::core::Contact> allContacts;\n\n    for (const auto& linkName : linkSerialization) {\n        const auto& contacts = this->getLink(linkName)->contacts();\n        std::move(contacts.begin(), //\n                  contacts.end(),\n                  std::back_inserter(allContacts));\n    }\n\n    return allContacts;\n}\n\nstd::vector<double>\nModel::jointPositions(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->position(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double>\nModel::jointVelocities(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->velocity(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double>\nModel::jointAccelerations(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->acceleration(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double>\nModel::jointGeneralizedForces(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->generalizedForce(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nscenario::core::JointLimit\nModel::jointLimits(const std::vector<std::string>& jointNames) const\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    std::vector<double> low;\n    std::vector<double> high;\n\n    low.reserve(jointSerialization.size());\n    high.reserve(jointSerialization.size());\n\n    for (const auto& joint : this->joints(jointSerialization)) {\n        auto limit = joint->jointPositionLimit();\n        std::move(limit.min.begin(), limit.min.end(), std::back_inserter(low));\n        std::move(limit.max.begin(), limit.max.end(), std::back_inserter(high));\n    }\n\n    return core::JointLimit(low, high);\n}\n\nbool Model::setJointControlMode(const scenario::core::JointControlMode mode,\n                                const std::vector<std::string>& jointNames)\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    bool ok = true;\n\n    for (auto& joint : this->joints(jointSerialization)) {\n        ok = ok && joint->setControlMode(mode);\n    }\n\n    return ok;\n}\n\nstd::vector<scenario::core::LinkPtr>\nModel::links(const std::vector<std::string>& linkNames) const\n{\n    const std::vector<std::string>& linkSerialization =\n        linkNames.empty() ? this->linkNames() : linkNames;\n\n    std::vector<core::LinkPtr> links;\n\n    for (const auto& linkName : linkSerialization) {\n        links.push_back(this->getLink(linkName));\n    }\n\n    return links;\n}\n\nstd::vector<scenario::core::JointPtr>\nModel::joints(const std::vector<std::string>& jointNames) const\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? this->jointNames() : jointNames;\n\n    std::vector<core::JointPtr> joints;\n\n    for (const auto& jointName : jointSerialization) {\n        joints.push_back(this->getJoint(jointName));\n    }\n\n    return joints;\n}\n\nbool Model::setJointPositionTargets(const std::vector<double>& positions,\n                                    const std::vector<std::string>& jointNames)\n{\n    auto lambda = [](core::JointPtr joint,\n                     const double position,\n                     const size_t dof) -> bool {\n        return joint->setPositionTarget(position, dof);\n    };\n\n    return Impl::setJointDataSerialized(this, positions, jointNames, lambda);\n}\n\nbool Model::setJointVelocityTargets(const std::vector<double>& velocities,\n                                    const std::vector<std::string>& jointNames)\n{\n    auto lambda = [](core::JointPtr joint,\n                     const double velocity,\n                     const size_t dof) -> bool {\n        return joint->setVelocityTarget(velocity, dof);\n    };\n\n    return Impl::setJointDataSerialized(this, velocities, jointNames, lambda);\n}\n\nbool Model::setJointAccelerationTargets(\n    const std::vector<double>& accelerations,\n    const std::vector<std::string>& jointNames)\n{\n    auto lambda = [](core::JointPtr joint,\n                     const double acceleration,\n                     const size_t dof) -> bool {\n        return joint->setAccelerationTarget(acceleration, dof);\n    };\n\n    return Impl::setJointDataSerialized(\n        this, accelerations, jointNames, lambda);\n}\n\nbool Model::setJointGeneralizedForceTargets(\n    const std::vector<double>& forces,\n    const std::vector<std::string>& jointNames)\n{\n    auto lambda =\n        [](core::JointPtr joint, const double force, const size_t dof) -> bool {\n        return joint->setGeneralizedForceTarget(force, dof);\n    };\n\n    return Impl::setJointDataSerialized(this, forces, jointNames, lambda);\n}\n\nstd::vector<double>\nModel::jointPositionTargets(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->positionTarget(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double>\nModel::jointVelocityTargets(const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->velocityTarget(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double> Model::jointAccelerationTargets(\n    const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->accelerationTarget(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::vector<double> Model::jointGeneralizedForceTargets(\n    const std::vector<std::string>& jointNames) const\n{\n    auto lambda = [](core::JointPtr joint, const size_t dof) -> double {\n        return joint->generalizedForceTarget(dof);\n    };\n\n    return Impl::getJointDataSerialized(this, jointNames, lambda);\n}\n\nstd::string Model::baseFrame() const\n{\n    // Get all the canonical links of the model\n    auto candidateBaseLinks = m_ecm->EntitiesByComponents(\n        ignition::gazebo::components::CanonicalLink(),\n        ignition::gazebo::components::ParentEntity(pImpl->model.Entity()));\n\n    if (candidateBaseLinks.size() == 0) {\n        throw exceptions::ModelError(\"Failed to find the canonical link\",\n                                     this->name());\n    }\n\n    if (candidateBaseLinks.size() > 1) {\n        throw exceptions::ModelError(\"Found multiple canonical link\",\n                                     this->name());\n    }\n\n    // Get the name of the base link\n    std::string baseLinkName = utils::getExistingComponentData< //\n        ignition::gazebo::components::Name>(m_ecm, candidateBaseLinks.front());\n\n    return baseLinkName;\n}\n\nstd::array<double, 3> Model::basePosition() const\n{\n    // Get the model pose\n    const ignition::math::Pose3d& world_H_model =\n        utils::getExistingComponentData<ignition::gazebo::components::Pose>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionPose(world_H_model).position;\n}\n\nstd::array<double, 4> Model::baseOrientation() const\n{\n    // Get the model pose\n    const ignition::math::Pose3d& world_H_model =\n        utils::getExistingComponentData<ignition::gazebo::components::Pose>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionPose(world_H_model).orientation;\n}\n\nstd::array<double, 3> Model::baseBodyLinearVelocity() const\n{\n    const auto& baseWorldLinearVelocity =\n        utils::toIgnitionVector3(this->baseWorldLinearVelocity());\n\n    // Get the model pose\n    const ignition::math::Pose3d& world_H_model =\n        utils::getExistingComponentData<ignition::gazebo::components::Pose>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector( //\n        world_H_model.Inverse().Rot() * baseWorldLinearVelocity);\n}\n\nstd::array<double, 3> Model::baseBodyAngularVelocity() const\n{\n    const auto& baseWorldAngularVelocity =\n        utils::toIgnitionVector3(this->baseWorldAngularVelocity());\n\n    // Get the model pose\n    const ignition::math::Pose3d& world_H_model =\n        utils::getExistingComponentData<ignition::gazebo::components::Pose>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector( //\n        world_H_model.Inverse().Rot() * baseWorldAngularVelocity);\n}\n\nstd::array<double, 3> Model::baseWorldLinearVelocity() const\n{\n    // Get the entity of the canonical link\n    const auto canonicalLinkEntity = m_ecm->EntityByComponents(\n        ignition::gazebo::components::Link(),\n        ignition::gazebo::components::CanonicalLink(),\n        ignition::gazebo::components::Name(this->baseFrame()),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    // Get the Pose component of the canonical link.\n    // This is the fixed transformation between the model and the base.\n    const auto& M_H_B = utils::getExistingComponentData< //\n        ignition::gazebo::components::Pose>(m_ecm, canonicalLinkEntity);\n\n    // Get the rotation between base link and world\n    const auto& W_R_B = utils::toIgnitionQuaternion(\n        this->getLink(this->baseFrame())->orientation());\n\n    // Get the linear velocity of the canonical link\n    const ignition::math::Vector3d& canonicalLinkLinearVelocity =\n        utils::toIgnitionVector3(\n            this->getLink(this->baseFrame())->worldLinearVelocity());\n\n    // Get the angular velocity of the canonical link\n    const ignition::math::Vector3d& canonicalLinkAngularVelocity =\n        utils::toIgnitionVector3(\n            this->getLink(this->baseFrame())->worldAngularVelocity());\n\n    // Convert the base velocity to the model mixed velocity\n    const auto& modelLinearVelocity = utils::fromBaseToModelLinearVelocity( //\n        canonicalLinkLinearVelocity,\n        canonicalLinkAngularVelocity,\n        M_H_B,\n        W_R_B);\n\n    // Return the linear part\n    return utils::fromIgnitionVector(modelLinearVelocity);\n}\n\nstd::array<double, 3> Model::baseWorldAngularVelocity() const\n{\n    // We could use the helper to convert the base link velocity to the model\n    // mixed velocity. However, since there's only a rigid transformation\n    // between base and model frame, and the velocity is computed in the world\n    // frame, we do not need to perform any conversion.\n\n    // Get the name of the base link\n    const std::string& baseLink = this->baseFrame();\n\n    // Return the angular velocity of the base link\n    return this->getLink(baseLink)->worldAngularVelocity();\n}\n\nbool Model::setBasePoseTarget(const std::array<double, 3>& position,\n                              const std::array<double, 4>& orientation)\n{\n    const ignition::math::Pose3d& basePoseTarget =\n        utils::toIgnitionPose(core::Pose{position, orientation});\n\n    utils::setComponentData<ignition::gazebo::components::BasePoseTarget>(\n        m_ecm, m_entity, basePoseTarget);\n\n    return true;\n}\n\nbool Model::setBasePositionTarget(const std::array<double, 3>& position)\n{\n    const auto& basePoseTargetComponent = utils::getComponent< //\n        ignition::gazebo::components::BasePoseTarget>(\n        m_ecm, m_entity, ignition::math::Pose3d::Zero);\n\n    const auto basePoseTarget =\n        ignition::math::Pose3d(utils::toIgnitionVector3(position),\n                               basePoseTargetComponent->Data().Rot());\n\n    utils::setExistingComponentData<\n        ignition::gazebo::components::BasePoseTarget>(\n        m_ecm, m_entity, basePoseTarget);\n\n    return true;\n}\n\nbool Model::setBaseOrientationTarget(const std::array<double, 4>& orientation)\n{\n    const auto& basePoseTargetComponent = utils::getComponent< //\n        ignition::gazebo::components::BasePoseTarget,\n        ignition::math::Pose3d>(m_ecm, m_entity);\n\n    const auto basePoseTarget =\n        ignition::math::Pose3d(basePoseTargetComponent->Data().Pos(),\n                               utils::toIgnitionQuaternion(orientation));\n\n    utils::setComponentData<ignition::gazebo::components::BasePoseTarget>(\n        m_ecm, m_entity, basePoseTarget);\n\n    return true;\n}\n\nbool Model::setBaseWorldVelocityTarget(const std::array<double, 3>& linear,\n                                       const std::array<double, 3>& angular)\n{\n    // TODO: the velocity target is not used by Gazebo.\n    //       Should we compute the base velocity from the inputs?\n    return this->setBaseWorldLinearVelocityTarget(linear)\n           && this->setBaseWorldAngularVelocityTarget(angular);\n}\n\nbool Model::setBaseWorldLinearVelocityTarget(\n    const std::array<double, 3>& linear)\n{\n    const ignition::math::Vector3d& baseWorldLinearVelocity =\n        utils::toIgnitionVector3(linear);\n\n    utils::setComponentData<\n        ignition::gazebo::components::BaseWorldLinearVelocityTarget>(\n        m_ecm, m_entity, baseWorldLinearVelocity);\n\n    return true;\n}\n\nbool Model::setBaseWorldAngularVelocityTarget(\n    const std::array<double, 3>& angular)\n{\n    const ignition::math::Vector3d& baseWorldAngularVelocity =\n        utils::toIgnitionVector3(angular);\n\n    utils::setComponentData<\n        ignition::gazebo::components::BaseWorldAngularVelocityTarget>(\n        m_ecm, m_entity, baseWorldAngularVelocity);\n\n    return true;\n}\n\nbool Model::setBaseWorldLinearAccelerationTarget(\n    const std::array<double, 3>& linear)\n{\n    const ignition::math::Vector3d& baseWorldLinearAcceleration =\n        utils::toIgnitionVector3(linear);\n\n    // TODO: do we need to convert the model acceleration to base link\n    //       acceleration? Contrarily to the velocity, this component\n    //       is not used in gazebo but from custom controllers.\n\n    utils::setComponentData<\n        ignition::gazebo::components::BaseWorldLinearAccelerationTarget>(\n        m_ecm, m_entity, baseWorldLinearAcceleration);\n\n    return true;\n}\n\nbool Model::setBaseWorldAngularAccelerationTarget(\n    const std::array<double, 3>& angular)\n{\n    const ignition::math::Vector3d& baseWorldAngularAcceleration =\n        utils::toIgnitionVector3(angular);\n\n    utils::setComponentData<\n        ignition::gazebo::components::BaseWorldAngularAccelerationTarget>(\n        m_ecm, m_entity, baseWorldAngularAcceleration);\n\n    return true;\n}\n\nstd::array<double, 3> Model::basePositionTarget() const\n{\n    const ignition::math::Pose3d& basePoseTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BasePoseTarget>(m_ecm, m_entity);\n\n    return utils::fromIgnitionPose(basePoseTarget).position;\n}\n\nstd::array<double, 4> Model::baseOrientationTarget() const\n{\n    const ignition::math::Pose3d& basePoseTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BasePoseTarget>(m_ecm, m_entity);\n\n    return utils::fromIgnitionPose(basePoseTarget).orientation;\n}\n\nstd::array<double, 3> Model::baseWorldLinearVelocityTarget() const\n{\n    const ignition::math::Vector3d& baseLinTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BaseWorldLinearVelocityTarget>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(baseLinTarget);\n}\n\nstd::array<double, 3> Model::baseWorldAngularVelocityTarget() const\n{\n    const ignition::math::Vector3d& baseAngTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BaseWorldAngularVelocityTarget>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(baseAngTarget);\n}\n\nstd::array<double, 3> Model::baseWorldLinearAccelerationTarget() const\n{\n    const ignition::math::Vector3d& baseLinTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BaseWorldLinearAccelerationTarget>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(baseLinTarget);\n}\n\nstd::array<double, 3> Model::baseWorldAngularAccelerationTarget() const\n{\n    const ignition::math::Vector3d& baseAngTarget =\n        utils::getExistingComponentData<\n            ignition::gazebo::components::BaseWorldAngularAccelerationTarget>(\n            m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(baseAngTarget);\n}\n\n// ======================\n// Implementation Methods\n// ======================\n\nstd::vector<double> Model::Impl::getJointDataSerialized(\n    const Model* model,\n    const std::vector<std::string>& jointNames,\n    std::function<double(core::JointPtr, const size_t)> getJointData)\n{\n    const std::vector<std::string>& jointSerialization =\n        jointNames.empty() ? model->jointNames() : jointNames;\n\n    std::vector<double> data;\n    data.reserve(model->dofs());\n\n    for (auto& joint : model->joints(jointSerialization)) {\n        for (size_t dof = 0; dof < joint->dofs(); ++dof) {\n            data.push_back(getJointData(joint, dof));\n        }\n    }\n\n    return data;\n}\n\nbool Model::Impl::setJointDataSerialized(\n    Model* model,\n    const std::vector<double>& data,\n    const std::vector<std::string>& jointNames,\n    std::function<bool(core::JointPtr, const double, const size_t)>\n        setJointData)\n{\n    std::vector<std::string> jointSerialization;\n\n    size_t expectedDOFs = 0;\n\n    if (!jointNames.empty()) {\n        jointSerialization = jointNames;\n\n        for (auto& joint : model->joints(jointSerialization)) {\n            expectedDOFs += joint->dofs();\n        }\n    }\n    else {\n        expectedDOFs = model->dofs();\n        jointSerialization = model->jointNames();\n    }\n\n    if (data.size() != expectedDOFs) {\n        sError << \"The size of the forces does not match the considered \"\n                  \"joint's DOFs\"\n               << std::endl;\n        return false;\n    }\n\n    auto it = data.begin();\n\n    for (auto& joint : model->joints(jointNames)) {\n        for (size_t dof = 0; dof < joint->dofs(); ++dof) {\n            if (!setJointData(joint, *it++, dof)) {\n                sError << \"Failed to set force of joint '\" << joint->name()\n                       << \"'\" << std::endl;\n                return false;\n            }\n        }\n    }\n    assert(it == data.end());\n    return true;\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/World.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/World.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/components/SimulatedTime.h\"\n#include \"scenario/gazebo/components/Timestamp.h\"\n#include \"scenario/gazebo/exceptions.h\"\n#include \"scenario/gazebo/helpers.h\"\n#include \"scenario/gazebo/utils.h\"\n\n#include <ignition/common/Event.hh>\n#include <ignition/gazebo/Events.hh>\n#include <ignition/gazebo/SdfEntityCreator.hh>\n#include <ignition/gazebo/components/Gravity.hh>\n#include <ignition/gazebo/components/Model.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/ParentEntity.hh>\n#include <ignition/gazebo/components/Physics.hh>\n#include <ignition/gazebo/components/PhysicsEnginePlugin.hh>\n#include <ignition/gazebo/components/Pose.hh>\n#include <ignition/math/Pose3.hh>\n#include <ignition/math/Vector3.hh>\n#include <ignition/physics/config.hh>\n#include <sdf/Element.hh>\n#include <sdf/Model.hh>\n#include <sdf/Root.hh>\n\n#include <algorithm>\n#include <cassert>\n#include <functional>\n#include <unordered_map>\n\nusing namespace scenario::gazebo;\n\nclass World::Impl\n{\npublic:\n    std::shared_ptr<ignition::gazebo::SdfEntityCreator> sdfEntityCreator;\n\n    using ModelName = std::string;\n    std::unordered_map<ModelName, core::ModelPtr> models;\n\n    struct\n    {\n        std::vector<std::string> modelNames;\n    } buffers;\n\npublic:\n    bool insertModel(const std::shared_ptr<sdf::Root>& modelSdfRoot,\n                     const core::Pose& pose,\n                     const std::string& overrideModelName,\n                     World& world)\n    {\n        // NOTE: sdf::Root objects could only contain one sdf::Model starting\n        //       from sdformat11.\n\n        // Name of the model to insert (allowing renaming from SDF)\n        std::string finalModelEntityName;\n\n        // Get the final name of the model\n        if (overrideModelName.empty()) {\n            assert(modelSdfRoot->Model());\n            finalModelEntityName = modelSdfRoot->Model()->Name();\n        }\n        else {\n            finalModelEntityName = overrideModelName;\n        }\n\n        // Check for model name clash\n        const std::vector<std::string>& modelNames = world.modelNames();\n        if (std::find(\n                modelNames.begin(), modelNames.end(), finalModelEntityName)\n            != modelNames.end()) {\n            sError << \"Failed to insert model '\" << finalModelEntityName\n                   << \"'. Another entity with the same name already exists.\"\n                   << std::endl;\n            return false;\n        }\n\n        // Rename the model.\n        // NOTE: The following is not enough because the name is not serialized\n        //       to string. We need also to operate directly on the raw element.\n        const_cast<sdf::Model*>(modelSdfRoot->Model())\n            ->SetName(finalModelEntityName);\n\n        // Update the name in the sdf model. This is necessary because model\n        // plugins are loaded right before the creation of the model entity and,\n        // instead of receiving the model entity name, they receive the model\n        // sdf name.\n        if (!utils::renameSDFModel(*modelSdfRoot, finalModelEntityName)) {\n            sError << \"Failed to rename SDF model\" << std::endl;\n            return false;\n        }\n\n        if (utils::verboseFromEnvironment()) {\n            sDebug << \"Inserting a model from the following SDF:\" << std::endl;\n            std::cout << modelSdfRoot->Element()->ToString(\"\") << std::endl;\n        }\n\n        // Create the model entity\n        const ignition::gazebo::Entity modelEntity =\n            this->sdfEntityCreator->CreateEntities(modelSdfRoot->Model());\n\n        // Attach the model entity to the world entity\n        this->sdfEntityCreator->SetParent(modelEntity, world.m_entity);\n\n        {\n            // Check that the model name is correct\n            std::string modelNameSDF = modelSdfRoot->Model()->Name();\n            std::string modelNameEntity = utils::getExistingComponentData< //\n                ignition::gazebo::components::Name>(world.m_ecm, modelEntity);\n            assert(modelNameSDF == modelNameEntity);\n        }\n\n        // Create the model\n        auto model = std::make_shared<scenario::gazebo::Model>();\n\n        // Initialize the model\n        if (!model->initialize(\n                modelEntity, world.m_ecm, world.m_eventManager)) {\n            sError << \"Failed to initialize the model\" << std::endl;\n            if (!world.removeModel(finalModelEntityName)) {\n                sError << \"Failed to remove temporary model after failure\"\n                       << std::endl;\n            }\n            return false;\n        }\n\n        // Create required model resources. This call prepares all the necessary\n        // components in the ECM to make our bindings work.\n        if (!model->createECMResources()) {\n            sError << \"Failed to initialize ECM model resources\" << std::endl;\n            return false;\n        }\n\n        // Set the initial model pose.\n        // We directly override the Pose component instead of using\n        // Model::resetBasePose because it would just store a pose command that\n        // needs to be processed by the Physics system. Overriding the\n        // component, instead, has instantaneous effect.\n        if (pose != core::Pose::Identity()) {\n            utils::setComponentData<ignition::gazebo::components::Pose>(\n                world.m_ecm, modelEntity, utils::toIgnitionPose(pose));\n        }\n\n        return true;\n    }\n};\n\nWorld::World()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nWorld::~World() = default;\n\nuint64_t World::id() const\n{\n    return std::hash<std::string>{}(this->name());\n}\n\nbool World::initialize(const ignition::gazebo::Entity worldEntity,\n                       ignition::gazebo::EntityComponentManager* ecm,\n                       ignition::gazebo::EventManager* eventManager)\n{\n    if (worldEntity == ignition::gazebo::kNullEntity || !ecm || !eventManager) {\n        return false;\n    }\n\n    // Store the GazeboEntity resources\n    m_ecm = ecm;\n    m_entity = worldEntity;\n    m_eventManager = eventManager;\n\n    // Create the SdfEntityCreator\n    pImpl->sdfEntityCreator = std::make_unique< //\n        ignition::gazebo::SdfEntityCreator>(*ecm, *eventManager);\n\n    return true;\n}\n\nbool World::createECMResources()\n{\n    // Store the time of creation (big bang)\n    if (!m_ecm->EntityHasComponentType(\n            m_entity, ignition::gazebo::components::Timestamp::typeId)) {\n        utils::setComponentData<ignition::gazebo::components::Timestamp>(\n            m_ecm, m_entity, std::chrono::steady_clock::duration::zero());\n    }\n\n    // Initialize the simulated time at 0.0 (Physics will then update it)\n    if (!m_ecm->EntityHasComponentType(\n            m_entity, ignition::gazebo::components::SimulatedTime::typeId)) {\n        utils::setComponentData<ignition::gazebo::components::SimulatedTime>(\n            m_ecm, m_entity, std::chrono::steady_clock::duration::zero());\n    }\n\n    // Print the active physics profile\n    const auto& physics = utils::getExistingComponentData< //\n        ignition::gazebo::components::Physics>(m_ecm, m_entity);\n    sDebug << \"Initializing world '\" << this->name()\n           << \"' with physics parameters:\" << std::endl\n           << \"rtf=\" << physics.RealTimeFactor() << std::endl\n           << \"step=\" << physics.MaxStepSize() << std::endl\n           << \"type=\" << physics.EngineType() << std::endl;\n\n    // Create required model resources\n    sMessage << \"Models:\" << std::endl;\n    for (const auto& model : this->models()) {\n        if (!std::static_pointer_cast<Model>(model)->createECMResources()) {\n            sError << \"Failed to initialize ECM model resources\" << std::endl;\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool World::insertWorldPlugin(const std::string& libName,\n                              const std::string& className,\n                              const std::string& context)\n{\n    return utils::insertPluginToGazeboEntity(\n        *this, libName, className, context);\n}\n\nbool World::setPhysicsEngine(const PhysicsEngine engine)\n{\n    // Get the name of the physics plugin\n    const std::string pluginLib = [&engine]() -> std::string {\n        switch (engine) {\n            case PhysicsEngine::Dart:\n                return \"ignition-physics\"\n                       + std::to_string(IGNITION_PHYSICS_MAJOR_VERSION)\n                       + \"-dartsim-plugin\";\n        }\n        return \"\";\n    }();\n\n    if (pluginLib.empty()) {\n        sError << \"Failed to retrieve the name of physics plugin library\";\n        return false;\n    }\n\n    // This component is read by the Physics system during its configuration\n    utils::setComponentData<ignition::gazebo::components::PhysicsEnginePlugin>(\n        m_ecm, m_entity, pluginLib);\n\n    // Vendored Physics system\n    const std::string libName = \"PhysicsSystem\";\n    const std::string className = \"scenario::plugins::gazebo::Physics\";\n\n    // Load the Physics system\n    if (!this->insertWorldPlugin(libName, className)) {\n        sError << \"Failed to insert the physics plugin\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nstd::array<double, 3> World::gravity() const\n{\n    const auto& gravity = utils::getExistingComponentData< //\n        ignition::gazebo::components::Gravity>(m_ecm, m_entity);\n\n    return utils::fromIgnitionVector(gravity);\n}\n\nbool World::setGravity(const std::array<double, 3>& gravity)\n{\n    const auto& simTimeAtWorldCreation = utils::getExistingComponentData<\n        ignition::gazebo::components::Timestamp>(m_ecm, m_entity);\n\n    const double simTimeAtWorldCreationInSeconds =\n        utils::steadyClockDurationToDouble(simTimeAtWorldCreation);\n\n    if (this->time() > simTimeAtWorldCreationInSeconds) {\n        sError << \"Physics already processed the world and its\"\n               << \"parameters cannot be modified\" << std::endl;\n        return false;\n    }\n\n    utils::setExistingComponentData<ignition::gazebo::components::Gravity>(\n        m_ecm, m_entity, utils::toIgnitionVector3(gravity));\n\n    return true;\n}\n\nbool World::valid() const\n{\n    return this->validEntity();\n}\n\ndouble World::time() const\n{\n    const auto& simTime = utils::getExistingComponentData<\n        ignition::gazebo::components::SimulatedTime>(m_ecm, m_entity);\n\n    return utils::steadyClockDurationToDouble(simTime);\n}\n\nstd::string World::name() const\n{\n    const std::string& worldName = utils::getExistingComponentData< //\n        ignition::gazebo::components::Name>(m_ecm, m_entity);\n\n    return worldName;\n}\n\nstd::vector<std::string> World::modelNames() const\n{\n    pImpl->buffers.modelNames.clear();\n\n    m_ecm->Each<ignition::gazebo::components::Name,\n                ignition::gazebo::components::Model,\n                ignition::gazebo::components::ParentEntity>(\n        [&](const ignition::gazebo::Entity& /*entity*/,\n            ignition::gazebo::components::Name* nameComponent,\n            ignition::gazebo::components::Model* /*modelComponent*/,\n            ignition::gazebo::components::ParentEntity* parentEntityComponent)\n            -> bool {\n            assert(nameComponent);\n            assert(parentEntityComponent);\n\n            // Discard models not belonging to this world\n            if (parentEntityComponent->Data() != m_entity) {\n                return true;\n            }\n\n            pImpl->buffers.modelNames.push_back(nameComponent->Data());\n            return true;\n        });\n\n    return pImpl->buffers.modelNames;\n}\n\nscenario::core::ModelPtr World::getModel(const std::string& modelName) const\n{\n    if (pImpl->models.find(modelName) != pImpl->models.end()) {\n        assert(pImpl->models.at(modelName));\n        return pImpl->models.at(modelName);\n    }\n\n    // Find the model entity\n    const auto modelEntity = m_ecm->EntityByComponents(\n        ignition::gazebo::components::Name(modelName),\n        ignition::gazebo::components::Model(),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    if (modelEntity == ignition::gazebo::kNullEntity) {\n        throw exceptions::ModelNotFound(modelName);\n    }\n\n    // Create and initialize the model\n    auto model = std::make_shared<scenario::gazebo::Model>();\n    model->initialize(modelEntity, m_ecm, m_eventManager);\n\n    pImpl->models[modelName] = model;\n    return pImpl->models[modelName];\n}\n\nstd::vector<scenario::core::ModelPtr>\nWorld::models(const std::vector<std::string>& modelNames) const\n{\n    const std::vector<std::string>& modelSerialization =\n        modelNames.empty() ? this->modelNames() : modelNames;\n\n    std::vector<core::ModelPtr> models;\n\n    for (const auto& modelName : modelSerialization) {\n        models.push_back(this->getModel(modelName));\n    }\n\n    return models;\n}\n\nbool World::insertModel(const std::string& modelFile,\n                        const core::Pose& pose,\n                        const std::string& overrideModelName)\n{\n    return this->insertModelFromFile(modelFile, pose, overrideModelName);\n}\n\nbool World::insertModelFromFile(const std::string& path,\n                                const core::Pose& pose,\n                                const std::string& overrideModelName)\n{\n    std::shared_ptr<sdf::Root> modelSdfRoot;\n    modelSdfRoot = utils::getSdfRootFromFile(path);\n\n    if (!modelSdfRoot) {\n        return false;\n    }\n\n    return pImpl->insertModel(modelSdfRoot, pose, overrideModelName, *this);\n}\n\nbool World::insertModelFromString(const std::string& sdfString,\n                                  const core::Pose& pose,\n                                  const std::string& overrideModelName)\n{\n    std::shared_ptr<sdf::Root> modelSdfRoot;\n    modelSdfRoot = utils::getSdfRootFromString(sdfString);\n\n    if (!modelSdfRoot) {\n        return false;\n    }\n\n    return pImpl.get()->insertModel(\n        modelSdfRoot, pose, overrideModelName, *this);\n}\n\nbool World::removeModel(const std::string& modelName)\n{\n    const auto modelEntity = m_ecm->EntityByComponents(\n        ignition::gazebo::components::Name(modelName),\n        ignition::gazebo::components::Model(),\n        ignition::gazebo::components::ParentEntity(m_entity));\n\n    if (modelEntity == ignition::gazebo::kNullEntity) {\n        sError << \"Model '\" << modelName << \"' not found in the world\"\n               << std::endl;\n        return false;\n    }\n\n    // Request the removal of the model\n    sDebug << \"Requesting removal of entity [\" << modelEntity << \"]\"\n           << std::endl;\n    pImpl->sdfEntityCreator->RequestRemoveEntity(modelEntity);\n\n    // Remove the cached model\n    pImpl->models.erase(modelName);\n\n    return true;\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/helpers.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/helpers.h\"\n#include \"ignition/common/Util.hh\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/components/Timestamp.h\"\n\n#include <Eigen/Dense>\n#include <ignition/gazebo/components/Component.hh>\n#include <ignition/gazebo/components/Model.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/World.hh>\n#include <ignition/msgs/contact.pb.h>\n#include <sdf/Error.hh>\n#include <sdf/Model.hh>\n#include <sdf/Physics.hh>\n#include <sdf/World.hh>\n\n#include <cassert>\n#include <sstream>\n\nusing namespace scenario::gazebo;\n\nstd::shared_ptr<sdf::Root>\nutils::getSdfRootFromFile(const std::string& sdfFileName)\n{\n    // NOTE: there's a double free error if we use std::optional\n    // auto root = std::make_optional<sdf::Root>();\n\n    auto root = std::make_shared<sdf::Root>();\n    auto errors = root->Load(sdfFileName);\n\n    if (!errors.empty()) {\n        sError << \"Failed to load sdf file \" << sdfFileName << std::endl;\n\n        for (const auto& error : errors) {\n            sError << error << std::endl;\n        }\n        return {};\n    }\n\n    return root;\n}\n\nstd::shared_ptr<sdf::Root>\nutils::getSdfRootFromString(const std::string& sdfString)\n{\n    // NOTE: there's a double free error if we use std::optional\n    // auto root = std::make_optional<sdf::Root>();\n\n    auto root = std::make_shared<sdf::Root>();\n    auto errors = root->LoadSdfString(sdfString);\n\n    if (!errors.empty()) {\n        sError << \"Failed to load sdf string\" << std::endl;\n\n        for (const auto& error : errors) {\n            sError << error << std::endl;\n        }\n        return {};\n    }\n\n    return root;\n}\n\nbool utils::verboseFromEnvironment()\n{\n    std::string envVarContent;\n    ignition::common::env(ScenarioVerboseEnvVar, envVarContent);\n\n    return envVarContent == \"1\";\n}\n\nstd::chrono::steady_clock::duration\nutils::doubleToSteadyClockDuration(const double durationInSeconds)\n{\n    using namespace std::chrono;\n\n    // Create a floating-point duration\n    const auto durationInSecondsChrono = duration<double>(durationInSeconds);\n\n    // Cast to integral duration\n    return round<steady_clock::duration>(durationInSecondsChrono);\n}\n\ndouble utils::steadyClockDurationToDouble(\n    const std::chrono::steady_clock::duration duration)\n{\n    // This is the value in seconds\n    return std::chrono::duration<double>(duration).count();\n}\n\nvoid utils::rowMajorToColumnMajor(std::vector<double>& input,\n                                  const long rows,\n                                  const long cols)\n{\n    using namespace Eigen;\n    using RowMajorMat = Matrix<double, Dynamic, Dynamic, RowMajor>;\n    using ColMajorMat = Matrix<double, Dynamic, Dynamic, ColMajor>;\n\n    Map<RowMajorMat> rowMajorView(input.data(), rows, cols);\n    Map<ColMajorMat> colMajorView(input.data(), rows, cols);\n\n    colMajorView = rowMajorView.eval();\n}\n\nbool utils::parentModelJustCreated(const GazeboEntity& gazeboEntity)\n{\n    // Get the parent world\n    const auto& world = utils::getParentWorld(gazeboEntity);\n\n    // Get the entity of the parent model\n    const auto parentModelEntity = [&]() -> ignition::gazebo::Entity {\n        return gazeboEntity.ecm()->EntityHasComponentType(\n                   gazeboEntity.entity(),\n                   ignition::gazebo::components::Model::typeId)\n                   ? gazeboEntity.entity()\n                   : utils::getParentModel(gazeboEntity)->entity();\n    }();\n\n    assert(world);\n    assert(parentModelEntity != ignition::gazebo::kNullEntity);\n\n    // Get the time the model was inserted\n    const auto& simTimeAtModelCreation = utils::getExistingComponentData<\n        ignition::gazebo::components::Timestamp>(gazeboEntity.ecm(),\n                                                 parentModelEntity);\n\n    const double simTimeAtModelCreationInSeconds =\n        utils::steadyClockDurationToDouble(simTimeAtModelCreation);\n\n    return world->time() == simTimeAtModelCreationInSeconds;\n}\n\nscenario::core::Pose\nutils::fromIgnitionPose(const ignition::math::Pose3d& ignitionPose)\n{\n    core::Pose pose;\n\n    pose.position[0] = ignitionPose.Pos().X();\n    pose.position[1] = ignitionPose.Pos().Y();\n    pose.position[2] = ignitionPose.Pos().Z();\n\n    pose.orientation[0] = ignitionPose.Rot().W();\n    pose.orientation[1] = ignitionPose.Rot().X();\n    pose.orientation[2] = ignitionPose.Rot().Y();\n    pose.orientation[3] = ignitionPose.Rot().Z();\n\n    return pose;\n}\n\nignition::math::Pose3d utils::toIgnitionPose(const scenario::core::Pose& pose)\n{\n    ignition::math::Pose3d ignitionPose;\n\n    ignitionPose.Pos() = ignition::math::Vector3d(\n        pose.position[0], pose.position[1], pose.position[2]);\n\n    ignitionPose.Rot() = ignition::math::Quaterniond(pose.orientation[0],\n                                                     pose.orientation[1],\n                                                     pose.orientation[2],\n                                                     pose.orientation[3]);\n\n    return ignitionPose;\n}\n\nscenario::core::Contact\nutils::fromIgnitionContactMsgs(ignition::gazebo::EntityComponentManager* ecm,\n                               const ignition::msgs::Contact& contactMsg)\n{\n    auto getEntityName =\n        [&](const ignition::gazebo::Entity entity) -> std::string {\n        return utils::getExistingComponentData<\n            ignition::gazebo::components::Name>(ecm, entity);\n    };\n\n    // Get the names of the links in contact following:\n    // collision entity -> collision link -> link name\n    const auto collisionEntityA = contactMsg.collision1().id();\n    const auto collisionEntityB = contactMsg.collision2().id();\n\n    const auto linkEntityA = ecm->ParentEntity(collisionEntityA);\n    const auto linkEntityB = ecm->ParentEntity(collisionEntityB);\n    const std::string linkNameA = getEntityName(linkEntityA);\n    const std::string linkNameB = getEntityName(linkEntityB);\n\n    // Return the link names scoped with the model name\n    const auto modelEntityA = ecm->ParentEntity(linkEntityA);\n    const auto modelEntityB = ecm->ParentEntity(linkEntityB);\n    const std::string modelNameA = getEntityName(modelEntityA);\n    const std::string modelNameB = getEntityName(modelEntityB);\n\n    const std::string scopedBodyA = modelNameA + \"::\" + linkNameA;\n    const std::string scopedBodyB = modelNameB + \"::\" + linkNameB;\n\n    // Returned data structure\n    scenario::core::Contact contact;\n    contact.bodyA = scopedBodyA;\n    contact.bodyB = scopedBodyB;\n\n    // Dimensions of contact points data must match\n    const auto numOfDepths = contactMsg.depth_size();\n    const auto numOfNormals = contactMsg.normal_size();\n    const auto numOfWrenches = contactMsg.wrench_size();\n    const auto numOfPositions = contactMsg.position_size();\n\n    int numOfPoints = numOfDepths;\n    assert(numOfPoints == numOfNormals);\n    assert(numOfPoints == numOfWrenches);\n    assert(numOfPoints == numOfPositions);\n\n    auto fromIgnMsg =\n        [](const ignition::msgs::Vector3d& vec) -> std::array<double, 3> {\n        return {vec.x(), vec.y(), vec.z()};\n    };\n\n    // Get all the contact points data\n    for (int pointIdx = 0; pointIdx < numOfPoints; ++pointIdx) {\n        // Create a contact point\n        scenario::core::ContactPoint contactPoint;\n        contactPoint.depth = contactMsg.depth(pointIdx);\n        contactPoint.normal = fromIgnMsg(contactMsg.normal(pointIdx));\n        contactPoint.position = fromIgnMsg(contactMsg.position(pointIdx));\n\n        // Get the wrench acting on bodyA\n        const ignition::msgs::JointWrench wrench = contactMsg.wrench(pointIdx);\n        const auto& wrench1 = wrench.body_1_wrench();\n        contactPoint.force = fromIgnMsg(wrench1.force());\n        contactPoint.torque = fromIgnMsg(wrench1.torque());\n\n        // Store the contact point\n        contact.points.push_back(contactPoint);\n    }\n\n    return contact;\n}\n\nstd::vector<scenario::core::Contact>\nutils::fromIgnitionContactsMsgs(ignition::gazebo::EntityComponentManager* ecm,\n                                const ignition::msgs::Contacts& contactsMsg)\n{\n    std::vector<core::Contact> contacts;\n\n    for (int contactIdx = 0; contactIdx < contactsMsg.contact_size();\n         ++contactIdx) {\n        contacts.push_back(\n            fromIgnitionContactMsgs(ecm, contactsMsg.contact(contactIdx)));\n    }\n\n    return contacts;\n}\n\nsdf::World utils::renameSDFWorld(const sdf::World& world,\n                                 const std::string& newWorldName)\n{\n    const size_t initialNrOfModels = world.ModelCount();\n\n    // Create a new world with the scoped name\n    auto renamedWorldElement = std::make_shared<sdf::Element>();\n    renamedWorldElement->SetName(\"world\");\n    renamedWorldElement->AddAttribute(\"name\", \"string\", newWorldName, true);\n\n    // Get the element of the world\n    sdf::ElementPtr child = world.Element()->GetFirstElement();\n\n    // Add all the children\n    while (child) {\n        renamedWorldElement->InsertElement(child);\n        child = child->GetNextElement();\n    }\n\n    // Create a new world\n    sdf::World renamedWorld;\n\n    auto errors = renamedWorld.Load(renamedWorldElement);\n\n    if (!errors.empty()) {\n        sError << \"Failed to create the World from the element\" << std::endl;\n\n        for (const auto& error : errors) {\n            sError << error << std::endl;\n        }\n        return {};\n    }\n\n    if (renamedWorld.Name() != newWorldName) {\n        sError << \"Failed to rename the world\" << std::endl;\n        return {};\n    }\n\n    if (renamedWorld.ModelCount() != initialNrOfModels) {\n        sError << \"Failed to copy all models to the new world\" << std::endl;\n        return {};\n    }\n\n    return renamedWorld;\n}\n\nbool utils::renameSDFModel(sdf::Root& sdfRoot, const std::string& newModelName)\n{\n    // Create a new model with the scoped name\n    auto renamedModel = std::make_shared<sdf::Element>();\n    renamedModel->SetName(\"model\");\n    renamedModel->AddAttribute(\"name\", \"string\", newModelName, true);\n\n    if (!sdfRoot.Model()) {\n        sError << \"The sdf Root does not contain any model\" << std::endl;\n        return false;\n    }\n\n    // Get the first child of the original model element\n    sdf::ElementPtr child = sdfRoot.Model()->Element()->GetFirstElement();\n\n    // Add all the children to the renamed model element\n    while (child) {\n        renamedModel->InsertElement(child);\n        child->SetParent(renamedModel);\n        child = child->GetNextElement();\n    }\n\n    // Remove the old model\n    auto originalModelElement = sdfRoot.Model()->Element();\n    originalModelElement->RemoveFromParent();\n\n    // Insert the renamed model\n    renamedModel->SetParent(sdfRoot.Element());\n    sdfRoot.Element()->InsertElement(renamedModel);\n\n    if (sdfRoot.Model()->Name() != newModelName) {\n        sError << \"Failed to insert renamed model in SDF root\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nnamespace scenario::gazebo::utils {\n    /**\n     * Convert a double to a string ignoring the current locale.\n     *\n     * Furthermore, set it with precision 25 to ensure that the\n     * string can be converted back exactly to the double that\n     * generated it.\n     */\n    std::string toExactStringNoLocale(const double in);\n} // namespace scenario::gazebo::utils\n\nstd::string utils::toExactStringNoLocale(const double in)\n{\n    std::ostringstream ss;\n    ss.imbue(std::locale::classic());\n    ss << std::setprecision(25) << in;\n    return ss.str();\n}\n\nbool utils::updateSDFPhysics(sdf::Root& sdfRoot,\n                             const double maxStepSize,\n                             const double rtf,\n                             const double realTimeUpdateRate,\n                             const size_t worldIndex)\n{\n    if (rtf <= 0) {\n        sError << \"Invalid RTF value (\" << rtf << \")\" << std::endl;\n        return false;\n    }\n\n    if (maxStepSize <= 0) {\n        sError << \"Invalid physics max step size (\" << maxStepSize << \")\"\n               << std::endl;\n        return false;\n    }\n\n    const sdf::World* world = sdfRoot.WorldByIndex(worldIndex);\n\n    if (world->PhysicsCount() != 1) {\n        sError << \"Found more than one physics profile\" << std::endl;\n        return false;\n    }\n\n    // Set the physics properties using the helper.\n    // It sets the internal value but it does not update the DOM.\n    auto* physics = const_cast<sdf::Physics*>(world->PhysicsByIndex(0));\n    physics->SetMaxStepSize(maxStepSize);\n    physics->SetRealTimeFactor(rtf);\n\n    // Update the DOM operating directly on the raw elements\n    sdf::ElementPtr worldElement = world->Element();\n\n    sdf::ElementPtr physicsElement = worldElement->GetElement(\"physics\");\n    assert(physicsElement);\n\n    sdf::ElementPtr max_step_size = physicsElement->GetElement(\"max_step_size\");\n    max_step_size->AddValue(\"double\", toExactStringNoLocale(maxStepSize), true);\n\n    sdf::ElementPtr real_time_update_rate =\n        physicsElement->GetElement(\"real_time_update_rate\");\n    real_time_update_rate->AddValue(\n        \"double\", toExactStringNoLocale(realTimeUpdateRate), true);\n\n    sdf::ElementPtr real_time_factor =\n        physicsElement->GetElement(\"real_time_factor\");\n    real_time_factor->AddValue(\"double\", toExactStringNoLocale(rtf), true);\n\n    return true;\n}\n\nsdf::ElementPtr utils::getPluginSDFElement(const std::string& libName,\n                                           const std::string& className)\n{\n    // Create the plugin SDF element\n    auto pluginElement = std::make_shared<sdf::Element>();\n\n    // Initialize the attributes\n    pluginElement->SetName(\"plugin\");\n    pluginElement->AddAttribute(\n        \"name\", \"string\", className, true, \"plugin name\");\n    pluginElement->AddAttribute(\n        \"filename\", \"string\", libName, true, \"pluginfilename\");\n\n    // Create the plugin description\n    pluginElement->AddElementDescription(pluginElement->Clone());\n\n    return pluginElement;\n}\n\nsdf::JointType utils::toSdf(const scenario::core::JointType type)\n{\n    sdf::JointType sdfType;\n\n    switch (type) {\n        case core::JointType::Fixed:\n            sdfType = sdf::JointType::FIXED;\n            break;\n        case core::JointType::Revolute:\n            sdfType = sdf::JointType::REVOLUTE;\n            break;\n        case core::JointType::Prismatic:\n            sdfType = sdf::JointType::PRISMATIC;\n            break;\n        case core::JointType::Ball:\n            sdfType = sdf::JointType::BALL;\n            break;\n        default:\n            sError << \"Joint type not recognized\" << std::endl;\n            sdfType = sdf::JointType::INVALID;\n            break;\n    }\n\n    return sdfType;\n}\n\nscenario::core::JointType utils::fromSdf(const sdf::JointType sdfType)\n{\n    core::JointType type;\n\n    switch (sdfType) {\n        case sdf::JointType::FIXED:\n            type = core::JointType::Fixed;\n            break;\n        case sdf::JointType::REVOLUTE:\n            type = core::JointType::Revolute;\n            break;\n        case sdf::JointType::PRISMATIC:\n            type = core::JointType::Prismatic;\n            break;\n        case sdf::JointType::BALL:\n            type = core::JointType::Ball;\n            break;\n        default:\n            sError << \"Joint type not recognized\" << std::endl;\n            type = core::JointType::Invalid;\n            break;\n    }\n\n    return type;\n}\n\nignition::math::Vector3d utils::fromModelToBaseLinearVelocity(\n    const ignition::math::Vector3d& linModelVelocity,\n    const ignition::math::Vector3d& angModelVelocity,\n    const ignition::math::Pose3d& M_H_B,\n    const ignition::math::Quaterniond& W_R_B)\n{\n    // Extract the rotation and the position of the model wrt to the base\n    auto B_R_M = M_H_B.Rot().Inverse();\n    auto M_o_B = M_H_B.Pos();\n    auto B_o_M = -B_R_M * M_o_B;\n\n    // Compute the base linear velocity\n    const ignition::math::Vector3d linBaseVelocity =\n        linModelVelocity - angModelVelocity.Cross(W_R_B * B_o_M);\n\n    // Return the linear part of the mixed velocity of the base\n    return linBaseVelocity;\n}\n\nignition::math::Vector3d utils::fromBaseToModelLinearVelocity(\n    const ignition::math::Vector3d& linBaseVelocity,\n    const ignition::math::Vector3d& angBaseVelocity,\n    const ignition::math::Pose3d& M_H_B,\n    const ignition::math::Quaterniond& W_R_B)\n{\n    // Extract the rotation and the position of the model wrt to the base\n    auto B_R_M = M_H_B.Rot().Inverse();\n    auto M_o_B = M_H_B.Pos();\n\n    // Compute the model linear velocity\n    const ignition::math::Vector3d linModelVelocity =\n        linBaseVelocity - angBaseVelocity.Cross(W_R_B * B_R_M * M_o_B);\n\n    // Return the linear part of the mixed velocity of the model\n    return linModelVelocity;\n}\n\nstd::shared_ptr<World> utils::getParentWorld(const GazeboEntity& gazeboEntity)\n{\n    if (!gazeboEntity.validEntity()) {\n        sError << \"The GazeboEntity is not valid\" << std::endl;\n        return nullptr;\n    }\n\n    auto worldEntity = getFirstParentEntityWithComponent< //\n        ignition::gazebo::components::World>(gazeboEntity.ecm(),\n                                             gazeboEntity.entity());\n\n    if (worldEntity == ignition::gazebo::kNullEntity) {\n        sError << \"Failed to find parent world entity\" << std::endl;\n        return nullptr;\n    }\n\n    auto world = std::make_shared<World>();\n\n    if (!world->initialize(\n            worldEntity, gazeboEntity.ecm(), gazeboEntity.eventManager())) {\n        sError << \"Failed to initialize world\" << std::endl;\n        return nullptr;\n    }\n\n    return world;\n}\n\nstd::shared_ptr<Model> utils::getParentModel(const GazeboEntity& gazeboEntity)\n{\n    if (!gazeboEntity.validEntity()) {\n        sError << \"The GazeboEntity is not valid\" << std::endl;\n        return nullptr;\n    }\n\n    auto modelEntity = getFirstParentEntityWithComponent< //\n        ignition::gazebo::components::Model>(gazeboEntity.ecm(),\n                                             gazeboEntity.entity());\n\n    if (modelEntity == ignition::gazebo::kNullEntity) {\n        sError << \"Failed to find parent model entity\" << std::endl;\n        return nullptr;\n    }\n\n    auto model = std::make_shared<Model>();\n\n    if (!model->initialize(\n            modelEntity, gazeboEntity.ecm(), gazeboEntity.eventManager())) {\n        sError << \"Failed to initialize model\" << std::endl;\n        return nullptr;\n    }\n\n    return model;\n}\n"
  },
  {
    "path": "scenario/src/gazebo/src/utils.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"scenario/gazebo/utils.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/helpers.h\"\n\n#include <Eigen/Dense>\n#include <ignition/common/Console.hh>\n#include <ignition/common/Filesystem.hh>\n#include <ignition/common/SystemPaths.hh>\n#include <ignition/common/URI.hh>\n#include <ignition/fuel_tools/ClientConfig.hh>\n#include <ignition/fuel_tools/FuelClient.hh>\n#include <ignition/fuel_tools/Interface.hh>\n#include <ignition/fuel_tools/Result.hh>\n#include <ignition/gazebo/Events.hh>\n#include <ignition/gazebo/config.hh>\n#include <sdf/Element.hh>\n#include <sdf/Model.hh>\n#include <sdf/Root.hh>\n#include <sdf/World.hh>\n\n#include <cassert>\n#include <exception>\n#include <memory>\n\nusing namespace scenario::gazebo;\n\nvoid utils::setVerbosity(const Verbosity level)\n{\n    ignition::common::Console::SetVerbosity(static_cast<int>(level));\n}\n\nstd::string utils::findSdfFile(const std::string& fileName)\n{\n    if (fileName.empty()) {\n        sError << \"The SDF file name is empty\" << std::endl;\n        return {};\n    }\n\n    ignition::common::SystemPaths systemPaths;\n    systemPaths.SetFilePathEnv(\"IGN_GAZEBO_RESOURCE_PATH\");\n    systemPaths.AddFilePaths(IGN_GAZEBO_WORLD_INSTALL_DIR);\n\n    // Find the file\n    std::string sdfFilePath = systemPaths.FindFile(fileName);\n\n    if (sdfFilePath.empty()) {\n        sError << \"Failed to find \" << fileName << std::endl;\n        sError << \"Check that it is part of IGN_GAZEBO_RESOURCE_PATH\"\n               << std::endl;\n        return {};\n    }\n\n    return sdfFilePath;\n}\n\nbool utils::sdfStringValid(const std::string& sdfString)\n{\n    return bool(getSdfRootFromString(sdfString));\n}\n\nstd::string utils::getSdfString(const std::string& fileName)\n{\n    // NOTE: We could use std::filesystem for the following, but compilers\n    //       support is still rough even with C++17 enabled :/\n    std::string sdfFileAbsPath;\n\n    if (!ignition::common::isFile(fileName)) {\n        sdfFileAbsPath = findSdfFile(fileName);\n    }\n\n    if (sdfFileAbsPath.empty()) {\n        return {};\n    }\n\n    auto root = getSdfRootFromString(sdfFileAbsPath);\n\n    if (!root) {\n        return {};\n    }\n\n    return root->Element()->ToString(\"\");\n}\n\nstd::string utils::getModelNameFromSdf(const std::string& fileName)\n{\n    std::string absFileName = findSdfFile(fileName);\n\n    if (absFileName.empty()) {\n        sError << \"Failed to find file \" << fileName << std::endl;\n        return {};\n    }\n\n    const auto root = utils::getSdfRootFromFile(absFileName);\n\n    if (!root) {\n        return {};\n    }\n\n    if (const auto model = root->Model()) {\n        return model->Name();\n    }\n\n    sError << \"No model found in file \" << fileName << std::endl;\n    return {};\n}\n\nstd::string utils::getWorldNameFromSdf(const std::string& fileName,\n                                       const size_t worldIndex)\n{\n    std::string absFileName = findSdfFile(fileName);\n\n    if (absFileName.empty()) {\n        sError << \"Failed to find file \" << fileName << std::endl;\n        return {};\n    }\n\n    auto root = utils::getSdfRootFromFile(absFileName);\n\n    if (!root) {\n        return {};\n    }\n\n    if (root->WorldCount() == 0) {\n        sError << \"Didn't find any world in file \" << fileName << std::endl;\n        return {};\n    }\n\n    if (worldIndex >= root->WorldCount()) {\n        sError << \"Model with index \" << worldIndex\n               << \" not found. The model has only \" << root->WorldCount()\n               << \" model(s)\" << std::endl;\n        return {};\n    }\n\n    return root->WorldByIndex(worldIndex)->Name();\n}\n\nstd::string utils::getEmptyWorld()\n{\n    // The empty world matches default.sdf from upstream without models\n    const std::string world = R\"\"\"\"(<?xml version=\"1.0\" ?>\n<sdf version=\"1.6\">\n    <world name=\"default\">\n        <physics default=\"true\" type=\"ignored\">\n        </physics>\n        <light type=\"directional\" name=\"sun\">\n            <cast_shadows>true</cast_shadows>\n            <pose>0 0 10 0 0 0</pose>\n            <diffuse>0.8 0.8 0.8 1</diffuse>\n            <specular>0.2 0.2 0.2 1</specular>\n            <attenuation>\n                <range>1000</range>\n                <constant>0.9</constant>\n                <linear>0.01</linear>\n                <quadratic>0.001</quadratic>\n            </attenuation>\n            <direction>-0.5 0.1 -0.9</direction>\n        </light>\n    </world>\n</sdf>)\"\"\"\";\n\n    assert(sdfStringValid(world));\n    return world;\n}\n\nstd::string utils::getModelFileFromFuel(const std::string& URI,\n                                        const bool useCache)\n{\n    std::string modelFilePath;\n    using namespace ignition;\n\n    if (!useCache) {\n        modelFilePath = fuel_tools::fetchResource(URI);\n\n        if (modelFilePath.empty()) {\n            sError << \"Failed to download Fuel model\" << std::endl;\n            return {};\n        }\n    }\n    else {\n        fuel_tools::FuelClient client(fuel_tools::ClientConfig{});\n\n        auto result = client.CachedModel(common::URI(URI), modelFilePath);\n\n        if (result.Type() != fuel_tools::ResultType::FETCH_ALREADY_EXISTS) {\n            sError << \"Fuel model not found locally\" << std::endl;\n            return {};\n        }\n    }\n\n    // NOTE: We could use std::filesystem for the following, but compilers\n    //       support is still rough even with C++17 enabled :/\n    std::string modelFile = common::joinPaths(modelFilePath, \"model.sdf\");\n\n    if (!common::isFile(modelFile)) {\n        sError << \"The model was downloaded from Fuel but it was not found \"\n               << \"in the filesystem\" << std::endl;\n        return {};\n    }\n\n    return modelFile;\n}\n\nstd::string utils::getRandomString(const size_t length)\n{\n    auto randchar = []() -> char {\n        static constexpr char charset[] = \"0123456789\"\n                                          \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n                                          \"abcdefghijklmnopqrstuvwxyz\";\n        const int max_index = (sizeof(charset) - 1);\n        return charset[rand() % max_index];\n    };\n\n    std::string str(length, 0);\n    std::generate_n(str.begin(), length, randchar);\n    return str;\n}\n\nstd::string utils::URDFFileToSDFString(const std::string& urdfFile)\n{\n    auto root = getSdfRootFromFile(urdfFile);\n\n    if (!root) {\n        return \"\";\n    }\n\n    return root->Element()->ToString(\"\");\n}\n\nstd::string utils::URDFStringToSDFString(const std::string& urdfString)\n{\n    auto root = getSdfRootFromString(urdfString);\n\n    if (!root) {\n        return \"\";\n    }\n\n    return root->Element()->ToString(\"\");\n}\n\nstd::vector<double> utils::normalize(const std::vector<double>& input,\n                                     const std::vector<double>& low,\n                                     const std::vector<double>& high)\n{\n    bool okInput = input.size() > 0;\n    bool okLow = low.size() == input.size() || low.size() == 1;\n    bool okHigh = high.size() == input.size() || high.size() == 1;\n\n    if (!okInput || !okLow || !okHigh) {\n        throw std::invalid_argument(\"Wrong input arguments\");\n    }\n\n    std::vector<double> lowBroadcasted = low;\n    std::vector<double> highBroadcasted = high;\n\n    if (low.size() == 1 && input.size() > 1) {\n        lowBroadcasted = std::vector<double>(input.size(), low[0]);\n    }\n\n    if (high.size() == 1 && input.size() > 1) {\n        highBroadcasted = std::vector<double>(input.size(), high[0]);\n    }\n\n    std::vector<double> output;\n    output.resize(input.size());\n\n    auto inputEigen = Eigen::Map<Eigen::ArrayXd>( //\n        const_cast<double*>(input.data()),\n        input.size());\n    auto outputEigen = Eigen::Map<Eigen::ArrayXd>( //\n        output.data(),\n        output.size());\n    auto lowEigen = Eigen::Map<Eigen::ArrayXd>( //\n        lowBroadcasted.data(),\n        lowBroadcasted.size());\n    auto highEigen = Eigen::Map<Eigen::ArrayXd>( //\n        highBroadcasted.data(),\n        highBroadcasted.size());\n\n    if (highEigen.isApprox(lowEigen)) {\n        return input;\n    }\n\n    outputEigen = 2.0 * (inputEigen - lowEigen) / (highEigen - lowEigen) - 1;\n\n    // Replace infinite with the input value\n    std::transform(output.begin(),\n                   output.end(),\n                   input.begin(),\n                   output.begin(),\n                   [](const double& output, const double& input) {\n                       return std::isfinite(output) ? output : input;\n                   });\n\n    return output;\n}\n\nstd::vector<double> utils::denormalize(const std::vector<double>& input,\n                                       const std::vector<double>& low,\n                                       const std::vector<double>& high)\n{\n    bool okInput = input.size() > 0;\n    bool okLow = low.size() == input.size() || low.size() == 1;\n    bool okHigh = high.size() == input.size() || high.size() == 1;\n\n    if (!okInput || !okLow || !okHigh) {\n        throw std::invalid_argument(\"Wrong input arguments\");\n    }\n\n    std::vector<double> lowBroadcasted = low;\n    std::vector<double> highBroadcasted = high;\n\n    if (low.size() == 1 && input.size() > 1) {\n        lowBroadcasted = std::vector<double>(input.size(), low[0]);\n    }\n\n    if (high.size() == 1 && input.size() > 1) {\n        highBroadcasted = std::vector<double>(input.size(), high[0]);\n    }\n\n    std::vector<double> output;\n    output.resize(input.size());\n\n    auto inputEigen = Eigen::Map<Eigen::ArrayXd>( //\n        const_cast<double*>(input.data()),\n        input.size());\n    auto outputEigen = Eigen::Map<Eigen::ArrayXd>( //\n        output.data(),\n        output.size());\n    auto lowEigen = Eigen::Map<Eigen::ArrayXd>( //\n        lowBroadcasted.data(),\n        lowBroadcasted.size());\n    auto highEigen = Eigen::Map<Eigen::ArrayXd>( //\n        highBroadcasted.data(),\n        highBroadcasted.size());\n\n    if (highEigen.isApprox(lowEigen)) {\n        return input;\n    }\n\n    outputEigen = (inputEigen + 1) * (highEigen - lowEigen) / 2.0 + lowEigen;\n\n    return output;\n}\n\nbool utils::insertPluginToGazeboEntity(const GazeboEntity& gazeboEntity,\n                                       const std::string& libName,\n                                       const std::string& className,\n                                       const std::string& context)\n{\n    if (!gazeboEntity.validEntity()) {\n        sError << \"The Gazebo Entity is not valid\" << std::endl;\n        return false;\n    }\n\n    if (libName.empty() || className.empty()) {\n        sError << \"Either the library name or the class name are empty strings\"\n               << std::endl;\n        return false;\n    }\n\n    sLog << \"Triggering plugin loading:\" << std::endl;\n    sLog << className << \" from \" << libName << \" for entity [\"\n         << gazeboEntity.entity() << \"]\" << std::endl;\n\n    // Create a new <plugin name=\"\" filename=\"\"> element without context\n    sdf::ElementPtr pluginElement =\n        utils::getPluginSDFElement(libName, className);\n\n    // Insert the context into the plugin element\n    if (!context.empty()) {\n\n        std::shared_ptr<sdf::Root> contextRoot =\n            utils::getSdfRootFromString(context);\n\n        if (!contextRoot) {\n            return false;\n        }\n\n        // Get the first element of the context\n        // (stripping out the <sdf> container)\n        auto contextNextElement = contextRoot->Element()->GetFirstElement();\n\n        // Insert the plugin context elements\n        while (contextNextElement) {\n            pluginElement->InsertElement(contextNextElement);\n            contextNextElement = contextNextElement->GetNextElement();\n        }\n    }\n\n    // The plugin element must be wrapped in another element, otherwise\n    // who receives it does not get the additional context\n    const auto wrapped = sdf::SDF::WrapInRoot(pluginElement);\n\n    // Trigger the plugin loading\n    gazeboEntity.eventManager()->Emit<ignition::gazebo::events::LoadPlugins>(\n        gazeboEntity.entity(), wrapped);\n\n    return true;\n}\n"
  },
  {
    "path": "scenario/src/plugins/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n# All rights reserved.\n#\n#  This project is dual licensed under LGPL v2.1+ or Apache License.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  This software may be modified and distributed under the terms of the\n#  GNU Lesser General Public License v2.1 or any later version.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\nadd_subdirectory(Physics)\nadd_subdirectory(JointController)\nadd_subdirectory(ControllerRunner)\n"
  },
  {
    "path": "scenario/src/plugins/ControllerRunner/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n# All rights reserved.\n#\n#  This project is dual licensed under LGPL v2.1+ or Apache License.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  This software may be modified and distributed under the terms of the\n#  GNU Lesser General Public License v2.1 or any later version.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\n# ==================\n# ControllersFactory\n# ==================\n\nadd_library(ControllersFactory STATIC\n    ControllersFactory.h\n    ControllersFactory.cpp)\n\ntarget_link_libraries(ControllersFactory\n    PUBLIC\n    ${sdformat.sdformat}\n    ScenarioCore::ScenarioABC\n    ScenarioControllers::ControllersABC\n    PRIVATE\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioControllers::ComputedTorqueFixedBase)\n\ntarget_include_directories(ControllersFactory PRIVATE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)\n\n# ================\n# ControllerRunner\n# ================\n\nadd_library(ControllerRunner SHARED\n    ControllerRunner.h\n    ControllerRunner.cpp)\n\ntarget_link_libraries(ControllerRunner\n    PUBLIC\n    ${ignition-gazebo.core}\n    PRIVATE\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioGazebo::ExtraComponents\n    ScenarioControllers::ControllersABC\n    ControllersFactory)\n\ntarget_include_directories(ControllerRunner PRIVATE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)\n\n# ===================\n# Install the targets\n# ===================\n\ninstall(\n    TARGETS ControllerRunner\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR})\n"
  },
  {
    "path": "scenario/src/plugins/ControllerRunner/ControllerRunner.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ControllerRunner.h\"\n#include \"ControllersFactory.h\"\n#include \"scenario/controllers/Controller.h\"\n#include \"scenario/controllers/References.h\"\n#include \"scenario/gazebo/Link.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/components/BasePoseTarget.h\"\n#include \"scenario/gazebo/components/BaseWorldAccelerationTarget.h\"\n#include \"scenario/gazebo/components/BaseWorldVelocityTarget.h\"\n#include \"scenario/gazebo/exceptions.h\"\n#include \"scenario/gazebo/helpers.h\"\n\n#include <ignition/math/Helpers.hh>\n#include <ignition/math/Pose3.hh>\n#include <ignition/math/Vector3.hh>\n#include <ignition/plugin/Register.hh>\n#include <sdf/Element.hh>\n\n#include <array>\n#include <cassert>\n#include <chrono>\n#include <limits>\n#include <ratio>\n#include <string>\n#include <vector>\n\nusing namespace scenario::gazebo;\nusing namespace scenario::plugins::gazebo;\n\nclass ControllerRunner::Impl\n{\npublic:\n    bool referencesHaveBeenSet = false;\n\n    std::shared_ptr<Model> model;\n    ignition::gazebo::Entity modelEntity;\n    std::chrono::steady_clock::duration prevUpdateTime{0};\n\n    std::shared_ptr<controllers::Controller> controller;\n\n    controllers::BaseReferences baseReferences;\n    controllers::JointReferences jointReferences;\n\n    struct\n    {\n        controllers::SetBaseReferences* base = nullptr;\n        controllers::UseScenarioModel* useModel = nullptr;\n        controllers::SetJointReferences* joints = nullptr;\n    } controllerInterfaces;\n\n    bool\n    updateAllSupportedReferences(ignition::gazebo::EntityComponentManager& ecm);\n\n    bool\n    updateBaseReferencesfromECM(ignition::gazebo::EntityComponentManager& ecm);\n\n    bool\n    updateJointReferencesfromECM(ignition::gazebo::EntityComponentManager& ecm);\n\n    void printControllerContext(\n        const std::shared_ptr<const sdf::Element> context) const;\n};\n\nControllerRunner::ControllerRunner()\n    : System()\n    , pImpl{std::make_unique<Impl>()}\n{}\n\n// NOTE: we should terminate the controller here, but plugins are not\n//       unloaded when the model is removed.\n//       All model plugins are deleted when the simulator is destroyed,\n//       and there's no more ECM -> we would get segfault.\nControllerRunner::~ControllerRunner() = default;\n\nvoid ControllerRunner::Configure(const ignition::gazebo::Entity& entity,\n                                 const std::shared_ptr<const sdf::Element>& sdf,\n                                 ignition::gazebo::EntityComponentManager& ecm,\n                                 ignition::gazebo::EventManager& eventMgr)\n{\n\n    // Store the model entity\n    pImpl->modelEntity = entity;\n\n    // Create a model that will be given to the controller\n    pImpl->model = std::make_shared<Model>();\n\n    if (!pImpl->model->initialize(entity, &ecm, &eventMgr)) {\n        sError << \"Failed to initialize model for controller\" << std::endl;\n        return;\n    }\n\n    if (!pImpl->model->valid()) {\n        sError << \"Failed to create a model from Entity [\" << entity << \"]\"\n               << std::endl;\n        return;\n    }\n\n    if (sdf->GetName() != \"plugin\") {\n        sError << \"Received context does not contain the <plugin> element\"\n               << std::endl;\n        return;\n    }\n\n    // This is the <plugin> element (with extra options stored in its children)\n    sdf::ElementPtr pluginElement = sdf->Clone();\n\n    // Initialize the controller context\n    sdf::ElementPtr controllerContext;\n\n    // Check if it contains extra options stored in a <controller> child\n    if (pluginElement->HasElement(\"controller\")) {\n        // Store the <controller> element\n        controllerContext = pluginElement->GetElement(\"controller\");\n\n        if (utils::verboseFromEnvironment()) {\n            pImpl->printControllerContext(pluginElement);\n        }\n    }\n\n    pImpl->controller =\n        ControllersFactory::Instance().get(controllerContext, pImpl->model);\n\n    if (!pImpl->controller) {\n        sError << \"Failed to find controller in the factory\" << std::endl;\n        return;\n    }\n\n    if (!pImpl->controller->initialize()) {\n        sError << \"Failed to initialize the controller\" << std::endl;\n        pImpl->controller = nullptr;\n        return;\n    }\n\n    pImpl->controllerInterfaces.useModel = dynamic_cast< //\n        controllers::UseScenarioModel*>(pImpl->controller.get());\n\n    pImpl->controllerInterfaces.base = dynamic_cast< //\n        controllers::SetBaseReferences*>(pImpl->controller.get());\n\n    pImpl->controllerInterfaces.joints = dynamic_cast< //\n        controllers::SetJointReferences*>(pImpl->controller.get());\n\n    // Controller classes could inherit from various interfaces that specify the\n    // accepted references. This design allows developing generic controllers.\n    // Here we check if the controller inherits from the supported interfaces.\n    if (!(pImpl->controllerInterfaces.base\n          || pImpl->controllerInterfaces.joints)) {\n        sWarning << \"Failed to find any of the supported interfaces to set \"\n                 << \"controller references\" << std::endl;\n        return;\n    }\n\n    sDebug << \"Controller successfully initialized\" << std::endl;\n}\n\nvoid ControllerRunner::PreUpdate(const ignition::gazebo::UpdateInfo& info,\n                                 ignition::gazebo::EntityComponentManager& ecm)\n{\n    if (info.paused) {\n        return;\n    }\n\n    if (!pImpl->model) {\n        return;\n    }\n\n    // This plugin keep being called also after the model was removed\n    try {\n        pImpl->model->controllerPeriod();\n    }\n    catch (exceptions::ComponentNotFound) {\n        return;\n    }\n\n    if (!pImpl->controller) {\n        sError << \"The controller was not initialized successfully\"\n               << std::endl;\n        return;\n    }\n\n    using namespace std::chrono;\n\n    // Update the controller only if enough time is passed\n    duration<double> elapsedFromLastUpdate =\n        info.simTime - pImpl->prevUpdateTime;\n    assert(elapsedFromLastUpdate.count() > 0);\n\n    // Handle first iteration\n    if (pImpl->prevUpdateTime.count() == 0) {\n        elapsedFromLastUpdate =\n            duration<double>(pImpl->model->controllerPeriod());\n    }\n\n    // If enough time has passed, store the time of this actuation step. In this\n    // case the state of the robot is read and new force references are computed\n    // and actuated. Otherwise, the same force of the last step is actuated.\n    bool computeNewForce;\n\n    // Due to numerical floating point approximations, sometimes a comparison of\n    // chrono durations has an error in the 1e-18 order\n    auto greaterThan = [](const duration<double>& a,\n                          const duration<double>& b) -> bool {\n        return a.count() >= b.count() - std::numeric_limits<double>::epsilon();\n    };\n\n    if (greaterThan(elapsedFromLastUpdate,\n                    duration<double>(pImpl->model->controllerPeriod()))) {\n        // Store the current update time\n        pImpl->prevUpdateTime = info.simTime;\n\n        // Enable using the controller to compute the new force\n        computeNewForce = true;\n    }\n    else {\n        // Disable the controller and send the same force reference as last\n        // update\n        computeNewForce = false;\n    }\n\n    // Get and set the new references\n    if (computeNewForce) {\n\n        try {\n            if (!pImpl->updateAllSupportedReferences(ecm)) {\n                sError << \"Failed to update supported references\" << std::endl;\n                return;\n            }\n        }\n        catch (const exceptions::ComponentNotFound& e) {\n            sDebug << \"Controller references not yet available\" << std::endl;\n            sDebug << e.what();\n            sWarning << \"[t=\"\n                     << utils::steadyClockDurationToDouble(info.simTime)\n                     << \"] The controller is not stepping\" << std::endl;\n            return;\n        }\n\n        if (pImpl->controllerInterfaces.useModel\n            && !pImpl->controllerInterfaces.useModel->updateStateFromModel()) {\n            sError << \"Failed to update controller state from internal model\"\n                   << std::endl;\n            return;\n        }\n\n        // The controller is stepped only when the references have been set\n        // at least once\n        pImpl->referencesHaveBeenSet = true;\n    }\n\n    // Step the controller\n    if (pImpl->referencesHaveBeenSet && !pImpl->controller->step(info.dt)) {\n        sError << \"Failed to step the controller\" << std::endl;\n        return;\n    }\n}\n\nbool ControllerRunner::Impl::updateAllSupportedReferences(\n    ignition::gazebo::EntityComponentManager& ecm)\n{\n    bool ok = true;\n\n    if (controllerInterfaces.base) {\n        if (!updateBaseReferencesfromECM(ecm)) {\n            sError << \"Failed to update base references\" << std::endl;\n            ok = false;\n        }\n        else {\n            if (!controllerInterfaces.base->setBaseReferences(baseReferences)) {\n                sError << \"Failed to set base references\" << std::endl;\n                ok = false;\n            }\n        }\n    }\n\n    if (controllerInterfaces.joints) {\n        if (!updateJointReferencesfromECM(ecm)) {\n            sError << \"Failed to update joint references\" << std::endl;\n            ok = false;\n        }\n        else {\n            if (!controllerInterfaces.joints->setJointReferences(\n                    jointReferences)) {\n                sError << \"Failed to set joint references\" << std::endl;\n                ok = false;\n            }\n        }\n    }\n\n    return ok;\n}\n\nbool ControllerRunner::Impl::updateBaseReferencesfromECM(\n    ignition::gazebo::EntityComponentManager& ecm)\n{\n    assert(controllerInterfaces.base);\n    using namespace ignition::math;\n    using namespace ignition::gazebo;\n\n    // =========\n    // Base Pose\n    // =========\n\n    Pose3d& basePoseTarget = utils::getExistingComponentData< //\n        components::BasePoseTarget>(&ecm, modelEntity);\n\n    core::Pose basePose = utils::fromIgnitionPose(basePoseTarget);\n    baseReferences.position = basePose.position;\n    baseReferences.orientation = basePose.orientation;\n\n    // =============\n    // Base Velocity\n    // =============\n\n    Vector3d baseLinearVelocityTarget = utils::getExistingComponentData< //\n        components::BaseWorldLinearVelocityTarget>(&ecm, modelEntity);\n\n    Vector3d baseAngularVelocityTarget = utils::getExistingComponentData< //\n\n        components::BaseWorldAngularVelocityTarget>(&ecm, modelEntity);\n\n    baseReferences.linearVelocity =\n        utils::fromIgnitionVector(baseLinearVelocityTarget);\n    baseReferences.angularVelocity =\n        utils::fromIgnitionVector(baseAngularVelocityTarget);\n\n    // =================\n    // Base Acceleration\n    // =================\n\n    Vector3d baseLinearAccelerationTarget = utils::getExistingComponentData< //\n        components::BaseWorldLinearAccelerationTarget>(&ecm, modelEntity);\n\n    Vector3d baseAngularAccelerationTarget = utils::getExistingComponentData< //\n        components::BaseWorldAngularAccelerationTarget>(&ecm, modelEntity);\n\n    baseReferences.linearAcceleration =\n        utils::fromIgnitionVector(baseLinearAccelerationTarget);\n    baseReferences.angularAcceleration =\n        utils::fromIgnitionVector(baseAngularAccelerationTarget);\n\n    return true;\n}\n\nbool ControllerRunner::Impl::updateJointReferencesfromECM(\n    ignition::gazebo::EntityComponentManager& /*ecm*/)\n{\n    assert(controllerInterfaces.joints);\n\n    auto& controlledJoints = controllerInterfaces.joints->controlledJoints();\n\n    jointReferences.position = model->jointPositionTargets(controlledJoints);\n    jointReferences.velocity = model->jointVelocityTargets(controlledJoints);\n    jointReferences.acceleration =\n        model->jointAccelerationTargets(controlledJoints);\n\n    return true;\n}\n\nvoid ControllerRunner::Impl::printControllerContext(\n    const std::shared_ptr<const sdf::Element> context) const\n{\n    sDebug << \"SDF elements received by the controller:\" << std::endl;\n    std::cout << context->ToString(\"\") << std::endl;\n}\n\nIGNITION_ADD_PLUGIN(\n    scenario::plugins::gazebo::ControllerRunner,\n    scenario::plugins::gazebo::ControllerRunner::System,\n    scenario::plugins::gazebo::ControllerRunner::ISystemConfigure,\n    scenario::plugins::gazebo::ControllerRunner::ISystemPreUpdate)\n"
  },
  {
    "path": "scenario/src/plugins/ControllerRunner/ControllerRunner.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_PLUGINS_GAZEBO_CONTROLLERRUNNER_H\n#define SCENARIO_PLUGINS_GAZEBO_CONTROLLERRUNNER_H\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n#include <ignition/gazebo/System.hh>\n#include <sdf/Element.hh>\n\n#include <memory>\n\nnamespace scenario::plugins::gazebo {\n    class ControllerRunner;\n} // namespace scenario::plugins::gazebo\n\nclass scenario::plugins::gazebo::ControllerRunner final\n    : public ignition::gazebo::System\n    , public ignition::gazebo::ISystemConfigure\n    , public ignition::gazebo::ISystemPreUpdate\n{\npublic:\n    ControllerRunner();\n    ~ControllerRunner() override;\n\n    void Configure(const ignition::gazebo::Entity& entity,\n                   const std::shared_ptr<const sdf::Element>& sdf,\n                   ignition::gazebo::EntityComponentManager& ecm,\n                   ignition::gazebo::EventManager& eventMgr) override;\n\n    void PreUpdate(const ignition::gazebo::UpdateInfo& info,\n                   ignition::gazebo::EntityComponentManager& ecm) override;\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl = nullptr;\n};\n\n#endif // SCENARIO_PLUGINS_GAZEBO_CONTROLLERRUNNER_H\n"
  },
  {
    "path": "scenario/src/plugins/ControllerRunner/ControllersFactory.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ControllersFactory.h\"\n#include \"scenario/controllers/ComputedTorqueFixedBase.h\"\n#include \"scenario/gazebo/Log.h\"\n\n#include <sdf/Param.hh>\n\n#include <algorithm>\n#include <array>\n#include <cassert>\n#include <istream>\n#include <locale>\n#include <string>\n#include <utility>\n#include <vector>\n\nusing namespace scenario::plugins::gazebo;\n\nclass ControllersFactory::Impl\n{\npublic:\n    static bool ContextValid(const sdf::ElementPtr context);\n\n    template <typename T>\n    static T GetElementValueAs(const std::string& elementName,\n                               const sdf::ElementPtr parentContext);\n\n    static void StringToStd(const std::string& string,\n                            std::vector<double>& out);\n\n    static void StringToStd(const std::string& string,\n                            std::vector<std::string>& out);\n\n    static void StringToStd(const std::string& string, std::string& out);\n};\n\nControllersFactory::ControllersFactory()\n    : pImpl{std::make_unique<Impl>()}\n{}\n\nControllersFactory::~ControllersFactory() = default;\n\nscenario::plugins::gazebo::ControllersFactory& ControllersFactory::Instance()\n{\n    static ControllersFactory instance;\n    return instance;\n}\n\nscenario::controllers::ControllerPtr\nControllersFactory::get(const sdf::ElementPtr context, core::ModelPtr model)\n{\n    if (!Impl::ContextValid(context)) {\n        sError << \"Controller context not valid\" << std::endl;\n        return nullptr;\n    }\n\n    std::string controllerName;\n    context->GetAttribute(\"name\")->Get<std::string>(controllerName);\n    sDebug << \"Found context for \" << controllerName << std::endl;\n\n    if (controllerName == \"ComputedTorqueFixedBase\") {\n\n        bool ok = true;\n        ok = ok && context->HasElement(\"kp\");\n        ok = ok && context->HasElement(\"kd\");\n        ok = ok && context->HasElement(\"urdf\");\n        ok = ok && context->HasElement(\"joints\");\n        ok = ok && context->HasElement(\"gravity\");\n\n        if (!ok) {\n            sError << \"Controller context has missing elements\" << std::endl;\n            return nullptr;\n        }\n\n        auto urdf = Impl::GetElementValueAs<std::string>(\"urdf\", context);\n        auto kp = Impl::GetElementValueAs<std::vector<double>>(\"kp\", context);\n        auto kd = Impl::GetElementValueAs<std::vector<double>>(\"kd\", context);\n        auto gravity = Impl::GetElementValueAs< //\n            std::vector<double>>(\"gravity\", context);\n        auto joints = Impl::GetElementValueAs< //\n            std::vector<std::string>>(\"joints\", context);\n\n        if (gravity.size() != 3) {\n            sError << \"Parsed gravity does not have three elements\";\n            return nullptr;\n        }\n\n        auto controller =\n            std::make_shared<controllers::ComputedTorqueFixedBase>(\n                urdf,\n                model,\n                kp,\n                kd,\n                joints,\n                std::array<double, 3>{gravity[0], gravity[1], gravity[2]});\n\n        return controller;\n    }\n\n    return nullptr;\n}\n\nbool ControllersFactory::Impl::ContextValid(const sdf::ElementPtr context)\n{\n    // Check that the context is a <controller> element\n    if (context->GetName() != \"controller\") {\n        sError << \"The first element of the context must be <controller>\"\n               << std::endl;\n        return false;\n    }\n\n    // Check that there is only one <controller> element\n    if (context->GetNextElement(\"controller\")) {\n        sError << \"Found multiple <controller> elements in controller context\"\n               << std::endl;\n        return false;\n    }\n\n    // Check that there is a name attribute: <controller name=\"controller_name\">\n    if (!context->HasAttribute(\"name\")) {\n        sError << \"Failed to find 'name' attribute in <controller> element\"\n               << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\ntemplate <typename T>\nT ControllersFactory::Impl::GetElementValueAs(\n    const std::string& elementName,\n    const sdf::ElementPtr parentContext)\n{\n    if (!parentContext->HasElement(elementName)) {\n        sError << \"Failed to find element <\" << elementName << \">\" << std::endl;\n        return {};\n    }\n\n    sdf::ElementPtr element = parentContext->GetElement(elementName);\n    assert(element);\n\n    sdf::ParamPtr value = element->GetValue();\n\n    if (!value) {\n        sError << \"Failed to get value of element <\" << elementName << \">\"\n               << std::endl;\n        return {};\n    }\n\n    T output;\n    std::string valueString = value->GetAsString();\n\n    Impl::StringToStd(valueString, output);\n    return output;\n}\n\nvoid ControllersFactory::Impl::StringToStd(const std::string& string,\n                                           std::vector<double>& out)\n{\n    double value;\n    std::stringstream in(string);\n\n    // Locale independent floating point conversion\n    // Note: not yet supported by GCC8\n    //\n    //    auto toDouble = [](const std::string& s) -> double {\n    //        double output;\n    //        std::from_chars(s.data(), s.data() + s.size(), output);\n    //        return output;\n    //    };\n\n    // Manually set the locale\n    in.imbue(std::locale::classic());\n\n    out.clear();\n\n    while (in >> value) {\n        out.push_back(value);\n    }\n}\n\nvoid ControllersFactory::Impl::StringToStd(const std::string& string,\n                                           std::vector<std::string>& out)\n{\n    std::string value;\n    std::stringstream in(string);\n\n    out.clear();\n\n    while (in >> value) {\n        out.push_back(value);\n    }\n}\n\nvoid ControllersFactory::Impl::StringToStd(const std::string& string,\n                                           std::string& out)\n{\n    out = string;\n}\n"
  },
  {
    "path": "scenario/src/plugins/ControllerRunner/ControllersFactory.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_PLUGINS_CONTROLLERSFACTORY_H\n#define SCENARIO_PLUGINS_CONTROLLERSFACTORY_H\n\n#include \"scenario/controllers/Controller.h\"\n#include \"scenario/core/Model.h\"\n\n#include <sdf/Element.hh>\n\n#include <memory>\n\nnamespace scenario::plugins::gazebo {\n    class ControllersFactory;\n} // namespace scenario::plugins::gazebo\n\nclass scenario::plugins::gazebo::ControllersFactory\n{\npublic:\n    ControllersFactory();\n    ~ControllersFactory();\n\n    static ControllersFactory& Instance();\n    controllers::ControllerPtr get(const sdf::ElementPtr context,\n                                   scenario::core::ModelPtr model);\n\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl;\n};\n\n#endif // SCENARIO_PLUGINS_CONTROLLERSFACTORY_H\n"
  },
  {
    "path": "scenario/src/plugins/JointController/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n# All rights reserved.\n#\n#  This project is dual licensed under LGPL v2.1+ or Apache License.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  This software may be modified and distributed under the terms of the\n#  GNU Lesser General Public License v2.1 or any later version.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\n# ===============\n# JointController\n# ===============\n\nadd_library(JointController SHARED\n    JointController.h\n    JointController.cpp)\n\ntarget_link_libraries(JointController\n    PUBLIC\n    ${ignition-gazebo.core}\n    PRIVATE\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioGazebo::ExtraComponents)\n\ntarget_include_directories(JointController PRIVATE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)\n\n# ===================\n# Install the targets\n# ===================\n\ninstall(\n    TARGETS JointController\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}/scenario/plugins)\n"
  },
  {
    "path": "scenario/src/plugins/JointController/JointController.cpp",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"JointController.h\"\n#include \"scenario/gazebo/Joint.h\"\n#include \"scenario/gazebo/Log.h\"\n#include \"scenario/gazebo/Model.h\"\n#include \"scenario/gazebo/components/JointControlMode.h\"\n#include \"scenario/gazebo/components/JointController.h\"\n#include \"scenario/gazebo/components/JointPID.h\"\n#include \"scenario/gazebo/components/JointPositionTarget.h\"\n#include \"scenario/gazebo/components/JointVelocityTarget.h\"\n#include \"scenario/gazebo/helpers.h\"\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/components/Joint.hh>\n#include <ignition/gazebo/components/JointVelocityCmd.hh>\n#include <ignition/gazebo/components/Name.hh>\n#include <ignition/gazebo/components/ParentEntity.hh>\n#include <ignition/math/PID.hh>\n#include <ignition/plugin/Register.hh>\n\n#include <cassert>\n#include <chrono>\n#include <limits>\n#include <ratio>\n#include <string>\n#include <vector>\n\nusing namespace scenario::gazebo;\nusing namespace scenario::plugins::gazebo;\n\nclass JointController::Impl\n{\npublic:\n    ignition::gazebo::Entity modelEntity;\n    std::shared_ptr<scenario::gazebo::Model> model;\n    std::chrono::steady_clock::duration prevUpdateTime{0};\n\n    static bool runPIDController(scenario::gazebo::Joint& joint,\n                                 const bool computeNewForce,\n                                 ignition::math::PID& pid,\n                                 const std::chrono::steady_clock::duration& dt,\n                                 const std::vector<double>& reference,\n                                 const std::vector<double>& current);\n};\n\nJointController::JointController()\n    : System()\n    , pImpl{std::make_unique<Impl>()}\n{}\n\nJointController::~JointController() = default;\n\nvoid JointController::Configure(\n    const ignition::gazebo::Entity& entity,\n    const std::shared_ptr<const sdf::Element>& /*sdf*/,\n    ignition::gazebo::EntityComponentManager& ecm,\n    ignition::gazebo::EventManager& eventMgr)\n{\n    // Check if the model already has a JointController plugin\n    if (ecm.EntityHasComponentType(\n            entity, ignition::gazebo::components::JointController::typeId)) {\n        sError << \"The model already has a JointController plugin\" << std::endl;\n        return;\n    }\n\n    // Store the model entity\n    pImpl->modelEntity = entity;\n\n    // Create a model that will be given to the controller\n    pImpl->model = std::make_shared<Model>();\n\n    // Create a model and check its validity\n    if (!pImpl->model->initialize(entity, &ecm, &eventMgr)) {\n        sError << \"Failed to initialize model for controller\" << std::endl;\n        return;\n    }\n\n    if (!pImpl->model->valid()) {\n        sError << \"Failed to create a model from Entity [\" << entity << \"]\"\n               << std::endl;\n        return;\n    }\n\n    // Add the JointController component to the model\n    utils::setComponentData<ignition::gazebo::components::JointController>(\n        &ecm, entity, true);\n}\n\nvoid JointController::PreUpdate(const ignition::gazebo::UpdateInfo& info,\n                                ignition::gazebo::EntityComponentManager& ecm)\n{\n    if (info.paused) {\n        return;\n    }\n\n    if (!pImpl->model) {\n        return;\n    }\n\n    // This plugin keep being called also after the model was removed\n    try {\n        pImpl->model->controllerPeriod();\n    }\n    catch (exceptions::ComponentNotFound) {\n        return;\n    }\n\n    using namespace std::chrono;\n\n    // Update the controller only if enough time is passed\n    duration<double> elapsedFromLastUpdate =\n        info.simTime - pImpl->prevUpdateTime;\n    assert(elapsedFromLastUpdate.count() > 0);\n\n    // Handle first iteration\n    if (pImpl->prevUpdateTime.count() == 0) {\n        elapsedFromLastUpdate =\n            duration<double>(pImpl->model->controllerPeriod());\n    }\n\n    // If enough time has passed, store the time of this actuation step. In this\n    // case the state of the robot is read and new force references are computed\n    // and actuated. Otherwise, the same force of the last step is actuated.\n    bool computeNewForce;\n\n    // Due to numerical floating point approximations, sometimes a comparison of\n    // chrono durations has an error in the 1e-18 order\n    auto greaterThan = [](const duration<double>& a,\n                          const duration<double>& b) -> bool {\n        return a.count() >= b.count() - std::numeric_limits<double>::epsilon();\n    };\n\n    if (greaterThan(elapsedFromLastUpdate,\n                    duration<double>(pImpl->model->controllerPeriod()))) {\n        // Store the current update time\n        pImpl->prevUpdateTime = info.simTime;\n\n        // Enable using the PID to compute the new force\n        computeNewForce = true;\n    }\n    else {\n        // Disable the PID and send the same force reference as last update\n        computeNewForce = false;\n    }\n\n    const auto positionControlledJoints = ecm.EntitiesByComponents(\n        ignition::gazebo::components::Joint(),\n        ignition::gazebo::components::ParentEntity(pImpl->modelEntity),\n        ignition::gazebo::components::JointControlMode(\n            core::JointControlMode::Position));\n\n    const auto positionInterpolatedControlledJoints = ecm.EntitiesByComponents(\n        ignition::gazebo::components::Joint(),\n        ignition::gazebo::components::ParentEntity(pImpl->modelEntity),\n        ignition::gazebo::components::JointControlMode(\n            core::JointControlMode::PositionInterpolated));\n\n    const auto velocityControlledJoints = ecm.EntitiesByComponents(\n        ignition::gazebo::components::Joint(),\n        ignition::gazebo::components::ParentEntity(pImpl->modelEntity),\n        ignition::gazebo::components::JointControlMode(\n            core::JointControlMode::Velocity));\n\n    const auto velocityFollowerDartControlledJoints = ecm.EntitiesByComponents(\n        ignition::gazebo::components::Joint(),\n        ignition::gazebo::components::ParentEntity(pImpl->modelEntity),\n        ignition::gazebo::components::JointControlMode(\n            core::JointControlMode::VelocityFollowerDart));\n\n    // Update PIDs for Revolute and Prismatic joints controlled in Position\n    for (const auto jointEntity : positionControlledJoints) {\n\n        ignition::math::PID& pid = utils::getExistingComponentData< //\n            ignition::gazebo::components::JointPID>(&ecm, jointEntity);\n\n        std::string& jointName = utils::getExistingComponentData< //\n            ignition::gazebo::components::Name>(&ecm, jointEntity);\n\n        auto joint = pImpl->model->getJoint(jointName);\n        auto jointGazebo = std::static_pointer_cast<Joint>(joint);\n\n        const std::vector<double>& position = joint->jointPosition();\n\n        const std::vector<double>& positionTarget =\n            utils::getExistingComponentData<\n                ignition::gazebo::components::JointPositionTarget>(&ecm,\n                                                                   jointEntity);\n\n        if (!Impl::runPIDController(*jointGazebo,\n                                    computeNewForce,\n                                    pid,\n                                    info.dt,\n                                    positionTarget,\n                                    position)) {\n            sError << \"Failed to run PID controller of joint \" << joint->name()\n                   << \" [\" << jointEntity << \"]\" << std::endl;\n        }\n    }\n\n    // TODO: Update PIDs for Revolute and Prismatic joints controlled in\n    //       PositionInterpolated\n\n    // Update PIDs for Revolute and Prismatic joints controlled in Velocity\n    for (const auto jointEntity : velocityControlledJoints) {\n\n        ignition::math::PID& pid = utils::getExistingComponentData<\n            ignition::gazebo::components::JointPID>(&ecm, jointEntity);\n\n        std::string& jointName =\n            utils::getExistingComponentData<ignition::gazebo::components::Name>(\n                &ecm, jointEntity);\n\n        auto joint = pImpl->model->getJoint(jointName);\n        auto jointGazebo = std::static_pointer_cast<Joint>(joint);\n\n        const std::vector<double>& velocity = joint->jointVelocity();\n\n        const std::vector<double>& velocityTarget =\n            utils::getExistingComponentData<\n                ignition::gazebo::components::JointVelocityTarget>(&ecm,\n                                                                   jointEntity);\n\n        if (!Impl::runPIDController(*jointGazebo,\n                                    computeNewForce,\n                                    pid,\n                                    info.dt,\n                                    velocityTarget,\n                                    velocity)) {\n            sError << \"Failed to run PID controller of joint \" << joint->name()\n                   << \" [\" << jointEntity << \"]\" << std::endl;\n        }\n    }\n\n    // Set the velocity command for Revolute and Prismatic joints controlled in\n    // VelocityDirect. This control mode computes and applies the right force\n    // to get the desired velocity at the next step. It can be thought as an\n    // ideal velocity PID.\n    for (const auto jointEntity : velocityFollowerDartControlledJoints) {\n\n        const std::string& jointName =\n            utils::getExistingComponentData<ignition::gazebo::components::Name>(\n                &ecm, jointEntity);\n\n        const auto joint = pImpl->model->getJoint(jointName);\n\n        const std::vector<double>& velocityTarget =\n            utils::getExistingComponentData<\n                ignition::gazebo::components::JointVelocityTarget>(&ecm,\n                                                                   jointEntity);\n\n        auto& jointVelocityCmd = utils::getComponentData< //\n            ignition::gazebo::components::JointVelocityCmd>(&ecm, jointEntity);\n\n        if (jointVelocityCmd.size() != joint->dofs()) {\n            assert(jointVelocityCmd.size() == 0);\n            jointVelocityCmd = std::vector<double>(joint->dofs(), 0.0);\n        }\n\n        // Set the target\n        jointVelocityCmd = velocityTarget;\n    }\n}\n\nbool JointController::Impl::runPIDController(\n    scenario::gazebo::Joint& joint,\n    const bool computeNewForce,\n    ignition::math::PID& pid,\n    const std::chrono::steady_clock::duration& dt,\n    const std::vector<double>& reference,\n    const std::vector<double>& current)\n{\n    switch (joint.type()) {\n\n        case core::JointType::Revolute:\n        case core::JointType::Prismatic: {\n\n            double force;\n\n            if (computeNewForce) {\n                assert(current.size() == 1);\n                assert(reference.size() == 1);\n\n                double error = current[0] - reference[0];\n                force = pid.Update(error, dt);\n            }\n            else {\n                force = pid.Cmd();\n            }\n\n            if (!joint.setGeneralizedForceTarget(force)) {\n                sError << \"Failed to set force of joint \" << joint.name()\n                       << std::endl;\n                return false;\n            }\n            return true;\n        }\n        case core::JointType::Fixed:\n        case core::JointType::Ball:\n        case core::JointType::Invalid:\n            sWarning << \"Type of joint '\" << joint.name() << \" not supported\"\n                     << std::endl;\n            return true;\n    }\n\n    return false;\n};\n\nIGNITION_ADD_PLUGIN(\n    scenario::plugins::gazebo::JointController,\n    scenario::plugins::gazebo::JointController::System,\n    scenario::plugins::gazebo::JointController::ISystemConfigure,\n    scenario::plugins::gazebo::JointController::ISystemPreUpdate)\n"
  },
  {
    "path": "scenario/src/plugins/JointController/JointController.h",
    "content": "/*\n * Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n * All rights reserved.\n *\n * This project is dual licensed under LGPL v2.1+ or Apache License.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * This software may be modified and distributed under the terms of the\n * GNU Lesser General Public License v2.1 or any later version.\n *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef SCENARIO_PLUGINS_GAZEBO_JOINTCONTROLLER_H\n#define SCENARIO_PLUGINS_GAZEBO_JOINTCONTROLLER_H\n\n#include <ignition/gazebo/Entity.hh>\n#include <ignition/gazebo/EntityComponentManager.hh>\n#include <ignition/gazebo/EventManager.hh>\n#include <ignition/gazebo/System.hh>\n#include <sdf/Element.hh>\n\n#include <memory>\n\nnamespace scenario::plugins::gazebo {\n    class JointController;\n} // namespace scenario::plugins::gazebo\n\nclass scenario::plugins::gazebo::JointController final\n    : public ignition::gazebo::System\n    , public ignition::gazebo::ISystemConfigure\n    , public ignition::gazebo::ISystemPreUpdate\n{\nprivate:\n    class Impl;\n    std::unique_ptr<Impl> pImpl = nullptr;\n\npublic:\n    JointController();\n    ~JointController() override;\n\n    void Configure(const ignition::gazebo::Entity& entity,\n                   const std::shared_ptr<const sdf::Element>& sdf,\n                   ignition::gazebo::EntityComponentManager& ecm,\n                   ignition::gazebo::EventManager& eventMgr) override;\n\n    void PreUpdate(const ignition::gazebo::UpdateInfo& info,\n                   ignition::gazebo::EntityComponentManager& ecm) override;\n};\n\n#endif // SCENARIO_PLUGINS_GAZEBO_JOINTCONTROLLER_H\n"
  },
  {
    "path": "scenario/src/plugins/Physics/CMakeLists.txt",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT)\n# All rights reserved.\n#\n#  This project is dual licensed under LGPL v2.1+ or Apache License.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  This software may be modified and distributed under the terms of the\n#  GNU Lesser General Public License v2.1 or any later version.\n#\n# -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\n# =============\n# PhysicsSystem\n# =============\n\nadd_library(PhysicsSystem SHARED\n    Physics.hh\n    EntityFeatureMap.hh\n    CanonicalLinkModelTracker.hh\n    Physics.cc)\n\ntarget_link_libraries(PhysicsSystem\n    PUBLIC\n    ${ignition-gazebo.core}\n    ${ignition-physics.ignition-physics}\n    PRIVATE\n    ScenarioGazebo::ScenarioGazebo\n    ScenarioGazebo::ExtraComponents)\n\ntarget_include_directories(PhysicsSystem PRIVATE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)\n\nif(ENABLE_PROFILER)\n    target_compile_definitions(PhysicsSystem PRIVATE \"IGN_PROFILER_ENABLE=1\")\nendif()\n\n# ===================\n# Install the targets\n# ===================\n\ninstall(\n    TARGETS PhysicsSystem\n    LIBRARY DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    ARCHIVE DESTINATION ${SCENARIO_INSTALL_LIBDIR}/scenario/plugins\n    RUNTIME DESTINATION ${SCENARIO_INSTALL_BINDIR}/scenario/plugins)\n"
  },
  {
    "path": "scenario/src/plugins/Physics/CanonicalLinkModelTracker.hh",
    "content": "/*\n * Copyright (C) 2021 Open Source Robotics Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n*/\n#ifndef IGNITION_GAZEBO_SYSTEMS_PHYSICS_CANONICAL_LINK_MODEL_TRACKER_HH_\n#define IGNITION_GAZEBO_SYSTEMS_PHYSICS_CANONICAL_LINK_MODEL_TRACKER_HH_\n\n#include <set>\n#include <unordered_map>\n\n#include \"ignition/gazebo/Entity.hh\"\n#include \"ignition/gazebo/EntityComponentManager.hh\"\n#include \"ignition/gazebo/components/CanonicalLink.hh\"\n#include \"ignition/gazebo/components/Model.hh\"\n#include \"ignition/gazebo/config.hh\"\n\nnamespace ignition::gazebo\n{\ninline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\nnamespace systems::physics_system\n{\n  /// \\brief Helper class that keeps track of which models have a particular\n  /// canonical link. This is useful in the physics system for updating model\n  /// poses - if a canonical link moved in the most recent physics step, then\n  /// all of the models that have this canonical link should be updated. It's\n  /// important to preserve topological ordering of the models in case there's\n  /// a nested model that shares the same canonical link (in a case like this,\n  /// the parent model pose needs to be updated before updating the child model\n  /// pose - see the documentation that explains how model pose updates are\n  /// calculated in PhysicsPrivate::UpdateSim to understand why nested model\n  /// poses need to be updated in topological order).\n  ///\n  /// It's possible to loop through all of the models and to update poses if the\n  /// model moved using something like EntityComponentManager::Each, but the\n  /// performance of this approach is worse than using just the moved canonical\n  /// links to determine which model poses should be updated (consider the case\n  /// where there are a lot of non-static models in a world, but only a few move\n  /// frequently - if using EntityComponentManager::Each, we still need to check\n  /// every single non-static model after a physics update to make sure that the\n  /// model did not move. If we instead use the updated canonical link\n  /// information, then we can skip iterating over/checking the models that\n  /// don't need to be updated).\n  class CanonicalLinkModelTracker\n  {\n    /// \\brief Save mappings for new models and their canonical links\n    /// \\param[in] _ecm EntityComponentManager\n    public: void AddNewModels(const EntityComponentManager &_ecm);\n\n    /// \\brief Get a topological ordering of models that have a particular\n    /// canonical link\n    /// \\param[in] _canonicalLink The canonical link\n    /// \\return The models that have this link as their canonical link, in\n    /// topological order\n    public: const std::set<Entity> &CanonicalLinkModels(\n                const Entity _canonicalLink) const;\n\n    /// \\brief Remove a link from the mapping. This method should be called when\n    /// a link is removed from simulation\n    /// \\param[in] _link The link to remove\n    public: void RemoveLink(const Entity &_link);\n\n    /// \\brief A mapping of canonical links to the models that have this\n    /// canonical link. The key is the canonical link entity, and the value is\n    /// the model entities that have this canonical link. The models in the\n    /// value are in topological order\n    private: std::unordered_map<Entity, std::set<Entity>> linkModelMap;\n\n    /// \\brief An empty set of models that is returned from the\n    /// CanonicalLinkModels method for links that map to no models\n    private: const std::set<Entity> emptyModelOrdering{};\n  };\n\n  void CanonicalLinkModelTracker::AddNewModels(\n      const EntityComponentManager &_ecm)\n  {\n    _ecm.EachNew<components::Model, components::ModelCanonicalLink>(\n        [this](const Entity &_model, const components::Model *,\n          const components::ModelCanonicalLink *_canonicalLinkComp)\n        {\n          this->linkModelMap[_canonicalLinkComp->Data()].insert(_model);\n          return true;\n        });\n  }\n\n  const std::set<Entity> &CanonicalLinkModelTracker::CanonicalLinkModels(\n      const Entity _canonicalLink) const\n  {\n    auto it = this->linkModelMap.find(_canonicalLink);\n    if (it != this->linkModelMap.end())\n      return it->second;\n\n    // if an invalid entity was given, it maps to no models\n    return this->emptyModelOrdering;\n  }\n\n  void CanonicalLinkModelTracker::RemoveLink(const Entity &_link)\n  {\n    this->linkModelMap.erase(_link);\n  }\n}\n}\n}\n\n#endif\n"
  },
  {
    "path": "scenario/src/plugins/Physics/EntityFeatureMap.hh",
    "content": "/*\n * Copyright (C) 2021 Open Source Robotics Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef IGNITION_GAZEBO_SYSTEMS_PHYSICS_ENTITY_FEATURE_MAP_HH_\n#define IGNITION_GAZEBO_SYSTEMS_PHYSICS_ENTITY_FEATURE_MAP_HH_\n\n#include <tuple>\n#include <type_traits>\n#include <unordered_map>\n\n#include <ignition/physics/Entity.hh>\n#include <ignition/physics/FindFeatures.hh>\n#include <ignition/physics/FeatureList.hh>\n#include <ignition/physics/RequestFeatures.hh>\n\n#include \"ignition/gazebo/Entity.hh\"\n\nnamespace ignition::gazebo\n{\ninline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\nnamespace systems::physics_system\n{\n  // \\brief Helper class that associates Gazebo entities with Physics entities\n  // with required and optional features. It can be used to cast a physics\n  // entity with the required features to another physics entity with one of\n  // the optional features. This class was created to keep all physics entities\n  // in one place so that when a gazebo entity is removed, all the mapped\n  // physics entitities can be removed at the same time. This ensures that\n  // reference counts are properly zeroed out in the underlying physics engines\n  // and the memory associated with the physics entities can be freed.\n  //\n  // DEV WARNING: There is an implicit conversion between physics EntityPtr and\n  // std::size_t in ign-physics. This seems also implicitly convert between\n  // EntityPtr and gazebo Entity. Therefore, any member function that takes a\n  // gazebo Entity can accidentally take an EntityPtr. To prevent this, for\n  // every function that takes a gazebo Entity, we should always have an\n  // overload that also takes an EntityPtr with required features. We can do\n  // this because there's a 1:1 mapping between the two in maps contained in\n  // this class.\n  //\n  // \\tparam PhysicsEntityT Type of entity, such as World, Model, or Link\n  // \\tparam PolicyT Policy of the physics engine (2D, 3D)\n  // \\tparam RequiredFeatureList Required features of the physics entity\n  // \\tparam OptionalFeatureLists One or more optional feature lists of the\n  // physics entity.\n  template <template <typename, typename> class PhysicsEntityT,\n            typename PolicyT, typename RequiredFeatureList,\n            typename... OptionalFeatureLists>\n  class EntityFeatureMap\n  {\n    /// \\brief Template that's preset with the class's Policy type\n    /// \\tparam T A FeatureList that is used in creating an EntityPtr\n    public: template <typename T>\n    using PhysicsEntityPtr = physics::EntityPtr<PhysicsEntityT<PolicyT, T>>;\n\n    /// \\brief A EntityPtr with made from RequiredFeatureList\n    public: using RequiredEntityPtr = PhysicsEntityPtr<RequiredFeatureList>;\n\n    /// \\brief Checks whether type T is in the OptionalFeatureLists\n    /// \\tparam T A FeatureList to search for in OptionalFeatureLists\n    public: template <typename T>\n            using HasFeatureList =\n                std::disjunction<std::is_same<T, OptionalFeatureLists>...>;\n\n    /// \\brief A tuple where the first element is an EntityPtr with made from\n    /// RequiredFeatureList and the remaining elements are made from\n    /// types in OptionalFeatureLists\n    private: using ValueType =\n                 std::tuple<RequiredEntityPtr,\n                            PhysicsEntityPtr<OptionalFeatureLists>...>;\n\n    /// \\brief Helper function to cast from an entity type with minimum features\n    /// to an entity with a different set of features. When the entity is cast\n    /// successfully, it is added to an internal cache so that subsequent casts\n    /// will use the entity from the cache.\n    /// \\tparam ToFeatureList The list of features of the resulting entity.\n    /// \\param[in] _entity Gazebo entity.\n    /// \\return Physics entity with features in ToFeatureList. nullptr if the\n    /// entity can't be found or the physics engine doesn't support the\n    /// requested feature.\n    public: template <typename ToFeatureList>\n            PhysicsEntityPtr<ToFeatureList>\n            EntityCast(gazebo::Entity _entity) const\n    {\n      // Using constexpr to limit compiler error message to the static_assert\n      // cppcheck-suppress syntaxError\n      if constexpr (!HasFeatureList<ToFeatureList>::value) // NOLINT\n      {\n        static_assert(HasFeatureList<ToFeatureList>::value,\n            \"Trying to cast to a FeatureList not included in the \"\n            \"optional FeatureLists of this map.\");\n        return nullptr;\n      }\n      else\n      {\n        using ToEntityPtr = PhysicsEntityPtr<ToFeatureList>;\n        // Has already been cast\n        auto castIt = this->castCache.find(_entity);\n        if (castIt != this->castCache.end())\n        {\n          auto castEntity = std::get<ToEntityPtr>(castIt->second);\n          if (nullptr != castEntity)\n          {\n            return castEntity;\n          }\n        }\n\n        auto reqEntity = this->Get(_entity);\n        if (nullptr == reqEntity)\n        {\n          return nullptr;\n        }\n\n        // Cast\n        auto castEntity = physics::RequestFeatures<ToFeatureList>::From(\n            this->Get(_entity));\n\n        if (castEntity)\n        {\n          std::get<ToEntityPtr>(this->castCache[_entity]) = castEntity;\n        }\n\n        return castEntity;\n      }\n    }\n\n    /// \\brief Helper function to cast from an entity type with minimum features\n    /// to an entity with a different set of features. This overload takes a\n    /// physics entity as input\n    /// \\tparam ToFeatureList The list of features of the resulting entity.\n    /// \\param[in] _physicsEntity Physics entity with required features.\n    /// \\return Physics entity with features in ToFeatureList. nullptr if the\n    /// entity can't be found or the physics engine doesn't support the\n    /// requested feature.\n    public: template <typename ToFeatureList>\n            PhysicsEntityPtr<ToFeatureList>\n            EntityCast(const RequiredEntityPtr &_physicsEntity) const\n    {\n      auto gzEntity = this->Get(_physicsEntity);\n      if (kNullEntity == gzEntity)\n      {\n        return nullptr;\n      }\n      return this->EntityCast<ToFeatureList>(gzEntity);\n    }\n\n    /// \\brief Get the physics entity with required features that corresponds to\n    /// the input Gazebo entity\n    /// \\param[in] _entity Gazebo entity.\n    /// \\return If found, returns the corresponding physics entity. Otherwise,\n    /// nullptr\n    public: RequiredEntityPtr Get(const Entity &_entity) const\n    {\n      auto it = this->entityMap.find(_entity);\n      if (it != this->entityMap.end())\n      {\n        return it->second;\n      }\n      return nullptr;\n    }\n\n    /// \\brief Get Gazebo entity that corresponds to the physics entity with\n    /// required features\n    /// \\param[in] _physEntity Physics entity with required features\n    /// \\return If found, returns the corresponding Gazebo entity. Otherwise,\n    /// kNullEntity\n    public: Entity Get(const RequiredEntityPtr &_physEntity) const\n    {\n      auto it = this->reverseMap.find(_physEntity);\n      if (it != this->reverseMap.end())\n      {\n        return it->second;\n      }\n      return kNullEntity;\n    }\n\n    /// \\brief Get the physics entity with required features that has a\n    /// particular ID\n    /// \\param[in] _id The ID of the desired physics entity\n    /// \\return If found, returns the corresponding physics entity. Otherwise,\n    /// nullptr\n    public: RequiredEntityPtr GetPhysicsEntityPtr(std::size_t _id) const\n    {\n      auto it = this->physEntityById.find(_id);\n      if (it != this->physEntityById.end())\n      {\n        return it->second;\n      }\n      return nullptr;\n    }\n\n    /// \\brief Check whether there is a physics entity associated with the given\n    /// Gazebo entity\n    /// \\param[in] _entity Gazebo entity.\n    /// \\return True if the there is a physics entity associated with the given\n    /// Gazebo entity\n    public: bool HasEntity(const Entity &_entity) const\n    {\n      return this->entityMap.find(_entity) != this->entityMap.end();\n    }\n\n    /// \\brief Check whether there is a gazebo entity associated with the given\n    /// physics entity\n    /// \\param[in] _physicsEntity physics entity with required features.\n    /// \\return True if the there is a gazebo entity associated with the given\n    /// physics entity\n    public: bool HasEntity(const RequiredEntityPtr &_physicsEntity) const\n    {\n      return this->reverseMap.find(_physicsEntity) != this->reverseMap.end();\n    }\n\n    /// \\brief Add a mapping between gazebo and physics entities\n    /// \\param[in] _entity Gazebo entity.\n    /// \\param[in] _physicsEntity Physics entity with required feature\n    public: void AddEntity(const Entity &_entity,\n                           const RequiredEntityPtr &_physicsEntity)\n    {\n      this->entityMap[_entity] = _physicsEntity;\n      this->reverseMap[_physicsEntity] = _entity;\n      this->physEntityById[_physicsEntity->EntityID()] = _physicsEntity;\n    }\n\n    /// \\brief Remove entity from all associated maps\n    /// \\param[in] _entity Gazebo entity.\n    /// \\return True if the entity was found and removed.\n    public: bool Remove(Entity _entity)\n    {\n      auto it = this->entityMap.find(_entity);\n      if (it != this->entityMap.end())\n      {\n        this->reverseMap.erase(it->second);\n        this->physEntityById.erase(it->second->EntityID());\n        this->castCache.erase(_entity);\n        this->entityMap.erase(it);\n        return true;\n      }\n      return false;\n    }\n\n    /// \\brief Remove physics entity from all associated maps\n    /// \\param[in] _physicsEntity Physics entity.\n    /// \\return True if the entity was found and removed.\n    public: bool Remove(const RequiredEntityPtr &_physicsEntity)\n    {\n      auto it = this->reverseMap.find(_physicsEntity);\n      if (it != this->reverseMap.end())\n      {\n        this->entityMap.erase(it->second);\n        this->physEntityById.erase(it->first->EntityID());\n        this->castCache.erase(it->second);\n        this->reverseMap.erase(it);\n        return true;\n      }\n      return false;\n    }\n\n    /// \\brief Get the map from Gazebo entity to physics entities with required\n    /// features\n    /// \\return Immumtable entity map\n    public: const std::unordered_map<Entity, RequiredEntityPtr> &Map() const\n    {\n      return this->entityMap;\n    }\n\n    /// \\brief Get the total number of entries in the maps. Only used for\n    /// testing.\n    /// \\return Number of entries in all the maps.\n    public: std::size_t TotalMapEntryCount() const\n    {\n      return this->entityMap.size() + this->reverseMap.size() +\n             this->castCache.size() + this->physEntityById.size();\n    }\n\n    /// \\brief Map from Gazebo entity to physics entities with required features\n    private: std::unordered_map<Entity, RequiredEntityPtr> entityMap;\n\n    /// \\brief Reverse map of entityMap\n    private: std::unordered_map<RequiredEntityPtr, Entity> reverseMap;\n\n    /// \\brief Map of physics entity IDs to the corresponding physics entity\n    /// with required features\n    private: std::unordered_map<std::size_t, RequiredEntityPtr> physEntityById;\n\n    /// \\brief Cache map from Gazebo entity to physics entities with optional\n    /// features\n    private: mutable std::unordered_map<Entity, ValueType> castCache;\n  };\n\n  /// \\brief Convenience template that presets EntityFeatureMap with\n  /// FeaturePolicy3d\n  template <template <typename, typename> class PhysicsEntityT,\n            typename RequiredFeatureList, typename... OptionalFeatureLists>\n  using EntityFeatureMap3d =\n      EntityFeatureMap<PhysicsEntityT, physics::FeaturePolicy3d,\n                       RequiredFeatureList, OptionalFeatureLists...>;\n}\n}\n}\n#endif\n"
  },
  {
    "path": "scenario/src/plugins/Physics/Physics.cc",
    "content": "/*\n * Copyright (C) 2018 Open Source Robotics Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n// clang-format off\n#include \"Physics.hh\"\n\n#include <ignition/msgs/contact.pb.h>\n#include <ignition/msgs/contacts.pb.h>\n#include <ignition/msgs/entity.pb.h>\n#include <ignition/msgs/Utility.hh>\n\n#include <algorithm>\n#include <iostream>\n#include <deque>\n#include <map>\n#include <string>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\n#include <ignition/common/HeightmapData.hh>\n#include <ignition/common/ImageHeightmap.hh>\n#include <ignition/common/MeshManager.hh>\n#include <ignition/common/Profiler.hh>\n#include <ignition/common/SystemPaths.hh>\n#include <ignition/math/AxisAlignedBox.hh>\n#include <ignition/math/eigen3/Conversions.hh>\n#include <ignition/math/Vector3.hh>\n#include <ignition/physics/config.hh>\n#include <ignition/physics/FeatureList.hh>\n#include <ignition/physics/FeaturePolicy.hh>\n#include <ignition/physics/heightmap/HeightmapShape.hh>\n#include <ignition/physics/RelativeQuantity.hh>\n#include <ignition/physics/RequestEngine.hh>\n\n#include <ignition/physics/BoxShape.hh>\n#include <ignition/physics/CylinderShape.hh>\n#include <ignition/physics/ForwardStep.hh>\n#include <ignition/physics/FrameSemantics.hh>\n#include <ignition/physics/FreeGroup.hh>\n#include <ignition/physics/FixedJoint.hh>\n#include <ignition/physics/GetContacts.hh>\n#include <ignition/physics/GetBoundingBox.hh>\n#include <ignition/physics/Joint.hh>\n#include <ignition/physics/Link.hh>\n#include <ignition/physics/RemoveEntities.hh>\n#include <ignition/physics/Shape.hh>\n#include <ignition/physics/SphereShape.hh>\n#include <ignition/physics/World.hh>\n#include <ignition/physics/mesh/MeshShape.hh>\n#include <ignition/physics/sdf/ConstructCollision.hh>\n#include <ignition/physics/sdf/ConstructJoint.hh>\n#include <ignition/physics/sdf/ConstructLink.hh>\n#include <ignition/physics/sdf/ConstructModel.hh>\n#include <ignition/physics/sdf/ConstructNestedModel.hh>\n#include <ignition/physics/sdf/ConstructWorld.hh>\n#include <ignition/plugin/Loader.hh>\n#include <ignition/plugin/PluginPtr.hh>\n#include <ignition/plugin/Register.hh>\n\n// SDF\n#include <sdf/Collision.hh>\n#include <sdf/Heightmap.hh>\n#include <sdf/Joint.hh>\n#include <sdf/Link.hh>\n#include <sdf/Mesh.hh>\n#include <sdf/Model.hh>\n#include <sdf/Surface.hh>\n#include <sdf/World.hh>\n\n#include \"ignition/gazebo/EntityComponentManager.hh\"\n#include \"ignition/gazebo/Model.hh\"\n#include \"ignition/gazebo/Util.hh\"\n\n// Components\n#include \"ignition/gazebo/components/AngularAcceleration.hh\"\n#include \"ignition/gazebo/components/AngularVelocity.hh\"\n#include \"ignition/gazebo/components/AngularVelocityCmd.hh\"\n#include \"ignition/gazebo/components/AxisAlignedBox.hh\"\n#include \"ignition/gazebo/components/BatterySoC.hh\"\n#include \"ignition/gazebo/components/CanonicalLink.hh\"\n#include \"ignition/gazebo/components/ChildLinkName.hh\"\n#include \"ignition/gazebo/components/Collision.hh\"\n#include \"ignition/gazebo/components/ContactSensorData.hh\"\n#include \"ignition/gazebo/components/Geometry.hh\"\n#include \"ignition/gazebo/components/Gravity.hh\"\n#include \"ignition/gazebo/components/Inertial.hh\"\n#include \"ignition/gazebo/components/DetachableJoint.hh\"\n#include \"ignition/gazebo/components/Joint.hh\"\n#include \"ignition/gazebo/components/JointAxis.hh\"\n#include \"ignition/gazebo/components/JointPosition.hh\"\n#include \"ignition/gazebo/components/JointPositionReset.hh\"\n#include \"ignition/gazebo/components/JointType.hh\"\n#include \"ignition/gazebo/components/JointVelocity.hh\"\n#include \"ignition/gazebo/components/JointVelocityCmd.hh\"\n#include \"ignition/gazebo/components/JointVelocityReset.hh\"\n#include \"ignition/gazebo/components/LinearAcceleration.hh\"\n#include \"ignition/gazebo/components/LinearVelocity.hh\"\n#include \"ignition/gazebo/components/LinearVelocityCmd.hh\"\n#include \"ignition/gazebo/components/Link.hh\"\n#include \"ignition/gazebo/components/Model.hh\"\n#include \"ignition/gazebo/components/Name.hh\"\n#include \"ignition/gazebo/components/ParentEntity.hh\"\n#include \"ignition/gazebo/components/ParentLinkName.hh\"\n#include \"ignition/gazebo/components/ExternalWorldWrenchCmd.hh\"\n#include \"ignition/gazebo/components/JointTransmittedWrench.hh\"\n#include \"ignition/gazebo/components/JointForceCmd.hh\"\n#include \"ignition/gazebo/components/Physics.hh\"\n#include \"ignition/gazebo/components/PhysicsEnginePlugin.hh\"\n#include \"ignition/gazebo/components/Pose.hh\"\n#include \"ignition/gazebo/components/PoseCmd.hh\"\n#include \"ignition/gazebo/components/SelfCollide.hh\"\n#include \"ignition/gazebo/components/SlipComplianceCmd.hh\"\n#include \"ignition/gazebo/components/Static.hh\"\n#include \"ignition/gazebo/components/ThreadPitch.hh\"\n#include \"ignition/gazebo/components/World.hh\"\n#include \"ignition/gazebo/components/HaltMotion.hh\"\n\n#include \"CanonicalLinkModelTracker.hh\"\n#include \"EntityFeatureMap.hh\"\n\n// Extra components\n#include \"scenario/gazebo/components/ExternalWorldWrenchCmdWithDuration.h\"\n#include \"scenario/gazebo/components/HistoryOfAppliedJointForces.h\"\n#include \"scenario/gazebo/components/JointAcceleration.h\"\n#include <ignition/gazebo/components/JointForce.hh>\n#include \"scenario/gazebo/components/SimulatedTime.h\"\n\nusing namespace ignition;\nusing namespace ignition::gazebo;\nusing namespace ignition::gazebo::systems;\nusing namespace ignition::gazebo::systems::physics_system;\nnamespace components = ignition::gazebo::components;\n\n\n// Private data class.\nclass ignition::gazebo::systems::PhysicsPrivate\n{\n  /// \\brief This is the minimum set of features that any physics engine must\n  /// implement to be supported by this system.\n  /// New features can't be added to this list in minor / patch releases, in\n  /// order to maintain backwards compatibility with downstream physics plugins.\n  public: struct MinimumFeatureList : ignition::physics::FeatureList<\n          ignition::physics::FindFreeGroupFeature,\n          ignition::physics::SetFreeGroupWorldPose,\n          ignition::physics::FreeGroupFrameSemantics,\n          ignition::physics::LinkFrameSemantics,\n          ignition::physics::ForwardStep,\n          ignition::physics::RemoveModelFromWorld,\n          ignition::physics::sdf::ConstructSdfLink,\n          ignition::physics::sdf::ConstructSdfModel,\n          ignition::physics::sdf::ConstructSdfWorld\n          >{};\n\n  /// \\brief Engine type with just the minimum features.\n  public: using EnginePtrType = ignition::physics::EnginePtr<\n            ignition::physics::FeaturePolicy3d, MinimumFeatureList>;\n\n  /// \\brief World type with just the minimum features.\n  public: using WorldPtrType = ignition::physics::WorldPtr<\n            ignition::physics::FeaturePolicy3d, MinimumFeatureList>;\n\n  /// \\brief Model type with just the minimum features.\n  public: using ModelPtrType = ignition::physics::ModelPtr<\n            ignition::physics::FeaturePolicy3d, MinimumFeatureList>;\n\n  /// \\brief Link type with just the minimum features.\n  public: using LinkPtrType = ignition::physics::LinkPtr<\n            ignition::physics::FeaturePolicy3d, MinimumFeatureList>;\n\n  /// \\brief Free group type with just the minimum features.\n  public: using FreeGroupPtrType = ignition::physics::FreeGroupPtr<\n            ignition::physics::FeaturePolicy3d, MinimumFeatureList>;\n\n  /// \\brief Create physics entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreatePhysicsEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create world entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateWorldEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create model entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateModelEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create link entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateLinkEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create collision entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateCollisionEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create joint entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateJointEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Create Battery entities\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void CreateBatteryEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Remove physics entities if they are removed from the ECM\n  /// \\param[in] _ecm Constant reference to ECM.\n  public: void RemovePhysicsEntities(const EntityComponentManager &_ecm);\n\n  /// \\brief Update physics from components\n  /// \\param[in] _ecm Mutable reference to ECM.\n  public: void UpdatePhysics(EntityComponentManager &_ecm,\n                             const ignition::gazebo::UpdateInfo& _info);\n\n  /// \\brief Step the simulation for each world\n  /// \\param[in] _dt Duration\n  /// \\returns Output data from the physics engine (this currently contains\n  /// data for links that experienced a pose change in the physics step)\n  public: ignition::physics::ForwardStep::Output Step(\n              const std::chrono::steady_clock::duration &_dt);\n\n  /// \\brief Get data of links that were updated in the latest physics step.\n  /// \\param[in] _ecm Mutable reference to ECM.\n  /// \\param[in] _updatedLinks Updated link poses from the latest physics step\n  /// that were written to by the physics engine (some physics engines may\n  /// not write this data to ForwardStep::Output. If not, _ecm is used to get\n  /// this updated link pose data).\n  /// \\return A map of gazebo link entities to their updated pose data.\n  /// std::map is used because canonical links must be in topological order\n  /// to ensure that nested models with multiple canonical links are updated\n  /// properly (models must be updated in topological order).\n  public: std::map<Entity, physics::FrameData3d> ChangedLinks(\n              EntityComponentManager &_ecm,\n              const ignition::physics::ForwardStep::Output &_updatedLinks);\n\n  /// \\brief Helper function to update the pose of a model.\n  /// \\param[in] _model The model to update.\n  /// \\param[in] _canonicalLink The canonical link of _model.\n  /// \\param[in] _ecm The entity component manager.\n  /// \\param[in, out] _linkFrameData Links that experienced a pose change in the\n  /// most recent physics step. The key is the entity of the link, and the\n  /// value is the updated frame data corresponding to that entity. The\n  /// canonical links of _model's nested models are added to _linkFrameData to\n  /// ensure that all of _model's nested models are marked as models to be\n  /// updated (if a parent model's pose changes, all nested model poses must be\n  /// updated since nested model poses are saved w.r.t. the parent model).\n  public: void UpdateModelPose(const Entity _model,\n              const Entity _canonicalLink, EntityComponentManager &_ecm,\n              std::map<Entity, physics::FrameData3d> &_linkFrameData);\n\n  /// \\brief Get an entity's frame data relative to world from physics.\n  /// \\param[in] _entity The entity.\n  /// \\param[in, out] _data The frame data to populate.\n  /// \\return True if _data was populated with frame data for _entity, false\n  /// otherwise.\n  public: bool GetFrameDataRelativeToWorld(const Entity _entity,\n              physics::FrameData3d &_data);\n\n  /// \\brief Update components from physics simulation\n  /// \\param[in] _ecm Mutable reference to ECM.\n  /// \\param[in, out] _linkFrameData Links that experienced a pose change in the\n  /// most recent physics step. The key is the entity of the link, and the\n  /// value is the updated frame data corresponding to that entity.\n  public: void UpdateSim(EntityComponentManager &_ecm,\n              std::map<Entity, physics::FrameData3d> &_linkFrameData,\n              const ignition::gazebo::UpdateInfo &_info);\n\n  /// \\brief Update collision components from physics simulation\n  /// \\param[in] _ecm Mutable reference to ECM.\n  public: void UpdateCollisions(EntityComponentManager &_ecm);\n\n  /// \\brief FrameData relative to world at a given offset pose\n  /// \\param[in] _link ign-physics link\n  /// \\param[in] _pose Offset pose in which to compute the frame data\n  /// \\returns FrameData at the given offset pose\n  public: physics::FrameData3d LinkFrameDataAtOffset(\n      const LinkPtrType &_link, const math::Pose3d &_pose) const;\n\n  /// \\brief Get transform from one ancestor entity to a descendant entity\n  /// that are in the same model.\n  /// \\param[in] _from An ancestor of the _to entity.\n  /// \\param[in] _to A descendant of the _from entity.\n  /// \\return Pose transform between the two entities\n  public: ignition::math::Pose3d RelativePose(const Entity &_from,\n      const Entity &_to, const EntityComponentManager &_ecm) const;\n\n  /// \\brief Cache the top-level model for each entity.\n  /// The key is an entity and the value is its top level model.\n  public: std::unordered_map<Entity, Entity> topLevelModelMap;\n\n  /// \\brief Keep track of what entities are static (models and links).\n  public: std::unordered_set<Entity> staticEntities;\n\n  /// \\brief Keep track of poses for links attached to non-static models.\n  /// This allows for skipping pose updates if a link's pose didn't change\n  /// after a physics step.\n  public: std::unordered_map<Entity, ignition::math::Pose3d> linkWorldPoses;\n\n  /// \\brief Keep a mapping of canonical links to models that have this\n  /// canonical link. Useful for updating model poses efficiently after a\n  /// physics step\n  public: CanonicalLinkModelTracker canonicalLinkModelTracker;\n\n  /// \\brief Keep track of non-static model world poses. Since non-static\n  /// models may not move on a given iteration, we want to keep track of the\n  /// most recent model world pose change that took place.\n  public: std::unordered_map<Entity, math::Pose3d> modelWorldPoses;\n\n  /// \\brief A map between model entity ids in the ECM to whether its battery\n  /// has drained.\n  public: std::unordered_map<Entity, bool> entityOffMap;\n\n  /// \\brief Entities whose pose commands have been processed and should be\n  /// deleted the following iteration.\n  public: std::unordered_set<Entity> worldPoseCmdsToRemove;\n\n  /// \\brief used to store whether physics objects have been created.\n  public: bool initialized = false;\n\n  /// \\brief Pointer to the underlying ign-physics Engine entity.\n  public: EnginePtrType engine = nullptr;\n\n  /// \\brief Vector3d equality comparison function.\n  public: std::function<bool(const math::Vector3d &, const math::Vector3d &)>\n          vec3Eql { [](const math::Vector3d &_a, const math::Vector3d &_b)\n                    {\n                      return _a.Equal(_b, 1e-6);\n                    }};\n\n  /// \\brief Pose3d equality comparison function.\n  public: std::function<bool(const math::Pose3d &, const math::Pose3d &)>\n          pose3Eql { [](const math::Pose3d &_a, const math::Pose3d &_b)\n                     {\n                       return _a.Pos().Equal(_b.Pos(), 1e-6) &&\n                         _a.Rot().Equal(_b.Rot(), 1e-6);\n                     }};\n\n  /// \\brief AxisAlignedBox equality comparison function.\n  public: std::function<bool(const math::AxisAlignedBox &,\n          const math::AxisAlignedBox&)>\n          axisAlignedBoxEql { [](const math::AxisAlignedBox &_a,\n                                 const math::AxisAlignedBox &_b)\n                     {\n                       return _a == _b;\n                     }};\n\n  /// \\brief msgs::Contacts equality comparison function.\n  public: std::function<bool(const msgs::Contacts &,\n          const msgs::Contacts &)>\n          contactsEql { [](const msgs::Contacts &_a,\n                          const msgs::Contacts &_b)\n                    {\n                      if (_a.contact_size() != _b.contact_size())\n                      {\n                        return false;\n                      }\n\n                      for (int i = 0; i < _a.contact_size(); ++i)\n                      {\n                        if (_a.contact(i).position_size() !=\n                            _b.contact(i).position_size())\n                        {\n                          return false;\n                        }\n\n                        for (int j = 0; j < _a.contact(i).position_size();\n                          ++j)\n                        {\n                          auto pos1 = _a.contact(i).position(j);\n                          auto pos2 = _b.contact(i).position(j);\n\n                          if (!math::equal(pos1.x(), pos2.x(), 1e-6) ||\n                              !math::equal(pos1.y(), pos2.y(), 1e-6) ||\n                              !math::equal(pos1.z(), pos2.z(), 1e-6))\n                          {\n                            return false;\n                          }\n                        }\n                      }\n                      return true;\n                    }};\n  /// \\brief msgs::Contacts equality comparison function.\n  public: std::function<bool(const msgs::Wrench &, const msgs::Wrench &)>\n          wrenchEql{\n          [](const msgs::Wrench &_a, const msgs::Wrench &_b)\n          {\n            return math::equal(_a.torque().x(), _b.torque().x(), 1e-6) &&\n                   math::equal(_a.torque().y(), _b.torque().y(), 1e-6) &&\n                   math::equal(_a.torque().z(), _b.torque().z(), 1e-6) &&\n\n                   math::equal(_a.force().x(), _b.force().x(), 1e-6) &&\n                   math::equal(_a.force().y(), _b.force().y(), 1e-6) &&\n                   math::equal(_a.force().z(), _b.force().z(), 1e-6);\n          }};\n\n  /// \\brief Environment variable which holds paths to look for engine plugins\n  public: std::string pluginPathEnv = \"IGN_GAZEBO_PHYSICS_ENGINE_PATH\";\n\n  //////////////////////////////////////////////////\n  ////////////// Optional Features /////////////////\n  //////////////////////////////////////////////////\n\n  //////////////////////////////////////////////////\n  // Slip Compliance\n\n  /// \\brief Feature list to process `FrictionPyramidSlipCompliance` components.\n  public: struct FrictionPyramidSlipComplianceFeatureList\n      : physics::FeatureList<\n            MinimumFeatureList,\n            ignition::physics::GetShapeFrictionPyramidSlipCompliance,\n            ignition::physics::SetShapeFrictionPyramidSlipCompliance>{};\n  //////////////////////////////////////////////////\n  // Joints\n\n  /// \\brief Feature list to handle joints.\n  public: struct JointFeatureList : ignition::physics::FeatureList<\n            MinimumFeatureList,\n            ignition::physics::GetBasicJointProperties,\n            ignition::physics::GetBasicJointState,\n            ignition::physics::SetBasicJointState,\n            ignition::physics::sdf::ConstructSdfJoint>{};\n\n\n  //////////////////////////////////////////////////\n  // Detachable joints\n\n  /// \\brief Feature list to process `DetachableJoint` components.\n  public: struct DetachableJointFeatureList : physics::FeatureList<\n            JointFeatureList,\n            physics::AttachFixedJointFeature,\n            physics::DetachJointFeature,\n            physics::SetJointTransformFromParentFeature>{};\n\n  //////////////////////////////////////////////////\n  // Joint transmitted wrench\n  /// \\brief Feature list for getting joint transmitted wrenches.\n  public: struct JointGetTransmittedWrenchFeatureList : physics::FeatureList<\n            physics::GetJointTransmittedWrench>{};\n\n  //////////////////////////////////////////////////\n  // Collisions\n\n  /// \\brief Feature list to handle collisions.\n  public: struct CollisionFeatureList : ignition::physics::FeatureList<\n            MinimumFeatureList,\n            ignition::physics::GetContactsFromLastStepFeature,\n            ignition::physics::sdf::ConstructSdfCollision>{};\n\n  /// \\brief Collision type with collision features.\n  public: using ShapePtrType = ignition::physics::ShapePtr<\n            ignition::physics::FeaturePolicy3d, CollisionFeatureList>;\n\n  /// \\brief World type with just the minimum features. Non-pointer.\n  public: using WorldShapeType = ignition::physics::World<\n            ignition::physics::FeaturePolicy3d, CollisionFeatureList>;\n\n  //////////////////////////////////////////////////\n  // Collision filtering with bitmasks\n\n  /// \\brief Feature list to filter collisions with bitmasks.\n  public: struct CollisionMaskFeatureList : ignition::physics::FeatureList<\n          CollisionFeatureList,\n          ignition::physics::CollisionFilterMaskFeature>{};\n\n  //////////////////////////////////////////////////\n  // Link force\n  /// \\brief Feature list for applying forces to links.\n  public: struct LinkForceFeatureList : ignition::physics::FeatureList<\n            ignition::physics::AddLinkExternalForceTorque>{};\n\n\n  //////////////////////////////////////////////////\n  // Bounding box\n  /// \\brief Feature list for model bounding box.\n  public: struct BoundingBoxFeatureList : ignition::physics::FeatureList<\n            MinimumFeatureList,\n            ignition::physics::GetModelBoundingBox>{};\n\n\n  //////////////////////////////////////////////////\n  // Joint velocity command\n  /// \\brief Feature list for set joint velocity command.\n  public: struct JointVelocityCommandFeatureList : physics::FeatureList<\n            physics::SetJointVelocityCommandFeature>{};\n\n  //////////////////////////////////////////////////\n  // World velocity command\n  public: struct WorldVelocityCommandFeatureList :\n            ignition::physics::FeatureList<\n              ignition::physics::SetFreeGroupWorldVelocity>{};\n\n\n  //////////////////////////////////////////////////\n  // Meshes\n\n  /// \\brief Feature list for meshes.\n  /// Include MinimumFeatureList so created collision can be automatically\n  /// up-cast.\n  public: struct MeshFeatureList : physics::FeatureList<\n            CollisionFeatureList,\n            physics::mesh::AttachMeshShapeFeature>{};\n\n  //////////////////////////////////////////////////\n  // Heightmap\n\n  /// \\brief Feature list for heightmaps.\n  /// Include MinimumFeatureList so created collision can be automatically\n  /// up-cast.\n  public: struct HeightmapFeatureList : ignition::physics::FeatureList<\n            CollisionFeatureList,\n            physics::heightmap::AttachHeightmapShapeFeature>{};\n\n  //////////////////////////////////////////////////\n  // Collision detector\n  /// \\brief Feature list for setting and getting the collision detector\n  public: struct CollisionDetectorFeatureList : ignition::physics::FeatureList<\n            ignition::physics::CollisionDetector>{};\n\n  //////////////////////////////////////////////////\n  // Solver\n  /// \\brief Feature list for setting and getting the solver\n  public: struct SolverFeatureList : ignition::physics::FeatureList<\n            ignition::physics::Solver>{};\n\n  //////////////////////////////////////////////////\n  // Nested Models\n\n  /// \\brief Feature list to construct nested models\n  public: struct NestedModelFeatureList : ignition::physics::FeatureList<\n            MinimumFeatureList,\n            ignition::physics::sdf::ConstructSdfNestedModel>{};\n\n  //////////////////////////////////////////////////\n  /// \\brief World EntityFeatureMap\n  public: using WorldEntityMap = EntityFeatureMap3d<\n          physics::World,\n          MinimumFeatureList,\n          CollisionFeatureList,\n          NestedModelFeatureList,\n          CollisionDetectorFeatureList,\n          SolverFeatureList>;\n\n  /// \\brief A map between world entity ids in the ECM to World Entities in\n  /// ign-physics.\n  public: WorldEntityMap entityWorldMap;\n\n  /// \\brief Model EntityFeatureMap\n  public: using ModelEntityMap = EntityFeatureMap3d<\n            physics::Model,\n            MinimumFeatureList,\n            JointFeatureList,\n            BoundingBoxFeatureList,\n            NestedModelFeatureList>;\n\n  /// \\brief A map between model entity ids in the ECM to Model Entities in\n  /// ign-physics.\n  public: ModelEntityMap entityModelMap;\n\n  /// \\brief Link EntityFeatureMap\n  public: using EntityLinkMap = EntityFeatureMap3d<\n            physics::Link,\n            MinimumFeatureList,\n            DetachableJointFeatureList,\n            CollisionFeatureList,\n            HeightmapFeatureList,\n            LinkForceFeatureList,\n            MeshFeatureList>;\n\n  /// \\brief A map between link entity ids in the ECM to Link Entities in\n  /// ign-physics.\n  public: EntityLinkMap entityLinkMap;\n\n  /// \\brief Joint EntityFeatureMap\n  public: using EntityJointMap = EntityFeatureMap3d<\n            physics::Joint,\n            JointFeatureList,\n            DetachableJointFeatureList,\n            JointVelocityCommandFeatureList,\n            JointGetTransmittedWrenchFeatureList\n            >;\n\n  /// \\brief A map between joint entity ids in the ECM to Joint Entities in\n  /// ign-physics\n  public: EntityJointMap entityJointMap;\n\n  /// \\brief Collision EntityFeatureMap\n  public: using EntityCollisionMap = EntityFeatureMap3d<\n            physics::Shape,\n            CollisionFeatureList,\n            CollisionMaskFeatureList,\n            FrictionPyramidSlipComplianceFeatureList\n            >;\n\n  /// \\brief A map between collision entity ids in the ECM to Shape Entities in\n  /// ign-physics.\n  public: EntityCollisionMap entityCollisionMap;\n\n  /// \\brief FreeGroup EntityFeatureMap\n  public: using EntityFreeGroupMap = EntityFeatureMap3d<\n            physics::FreeGroup,\n            MinimumFeatureList,\n            WorldVelocityCommandFeatureList\n            >;\n\n  /// \\brief A map between collision entity ids in the ECM to FreeGroup Entities\n  /// in ign-physics.\n  public: EntityFreeGroupMap entityFreeGroupMap;\n\n  /// \\brief Boolean value that is true only the first call of Configure and\n  /// PreUpdate.\n  bool firstRun = true;\n};\n\n//////////////////////////////////////////////////\nPhysics::Physics() : System(), dataPtr(std::make_unique<PhysicsPrivate>())\n{\n}\n\n//////////////////////////////////////////////////\nvoid Physics::Configure(const Entity &_entity,\n    const std::shared_ptr<const sdf::Element> &_sdf,\n    EntityComponentManager &_ecm,\n    EventManager &/*_eventMgr*/)\n{\n  std::string pluginLib;\n\n  // 1. Engine from component (from command line / ServerConfig)\n  auto engineComp = _ecm.Component<components::PhysicsEnginePlugin>(_entity);\n  if (engineComp && !engineComp->Data().empty())\n  {\n    pluginLib = engineComp->Data();\n  }\n  // 2. Engine from SDF\n  else if (_sdf->HasElement(\"engine\"))\n  {\n    auto sdfClone = _sdf->Clone();\n    auto engineElem = sdfClone->GetElement(\"engine\");\n    pluginLib = engineElem->Get<std::string>(\"filename\", pluginLib).first;\n  }\n\n  // 3. Use DART by default\n  if (pluginLib.empty())\n  {\n    pluginLib = \"libignition-physics-dartsim-plugin.so\";\n  }\n\n  // Update component\n  if (!engineComp)\n  {\n    _ecm.CreateComponent(_entity, components::PhysicsEnginePlugin(pluginLib));\n  }\n  else\n  {\n    engineComp->SetData(pluginLib,\n        [](const std::string &_a, const std::string &_b){return _a == _b;});\n  }\n\n  // Find engine shared library\n  // Look in:\n  // * Paths from environment variable\n  // * Engines installed with ign-physics\n  common::SystemPaths systemPaths;\n  systemPaths.SetPluginPathEnv(this->dataPtr->pluginPathEnv);\n  systemPaths.AddPluginPaths({IGNITION_PHYSICS_ENGINE_INSTALL_DIR});\n\n  auto pathToLib = systemPaths.FindSharedLibrary(pluginLib);\n  if (pathToLib.empty())\n  {\n    ignerr << \"Failed to find plugin [\" << pluginLib\n           << \"]. Have you checked the \" << this->dataPtr->pluginPathEnv\n           << \" environment variable?\" << std::endl;\n    return;\n  }\n\n  // Load engine plugin\n  ignition::plugin::Loader pluginLoader;\n  auto plugins = pluginLoader.LoadLib(pathToLib);\n  if (plugins.empty())\n  {\n    ignerr << \"Unable to load the [\" << pathToLib << \"] library.\\n\";\n    return;\n  }\n\n  auto classNames = pluginLoader.PluginsImplementing<\n      physics::ForwardStep::Implementation<\n      physics::FeaturePolicy3d>>();\n  if (classNames.empty())\n  {\n    ignerr << \"No physics plugins found in library [\" << pathToLib << \"].\"\n           << std::endl;\n    return;\n  }\n\n  // Get the first plugin that works\n  for (auto className : classNames)\n  {\n    auto plugin = pluginLoader.Instantiate(className);\n\n    if (!plugin)\n    {\n      ignwarn << \"Failed to instantiate [\" << className << \"] from [\"\n              << pathToLib << \"]\" << std::endl;\n      continue;\n    }\n\n    this->dataPtr->engine = ignition::physics::RequestEngine<\n      ignition::physics::FeaturePolicy3d,\n      PhysicsPrivate::MinimumFeatureList>::From(plugin);\n\n    if (nullptr != this->dataPtr->engine)\n    {\n      igndbg << \"Loaded [\" << className << \"] from library [\"\n             << pathToLib << \"]\" << std::endl;\n      break;\n    }\n\n    auto missingFeatures = ignition::physics::RequestEngine<\n        ignition::physics::FeaturePolicy3d,\n        PhysicsPrivate::MinimumFeatureList>::MissingFeatureNames(plugin);\n\n    std::stringstream msg;\n    msg << \"Plugin [\" << className << \"] misses required features:\"\n        << std::endl;\n    for (auto feature : missingFeatures)\n    {\n      msg << \"- \" << feature << std::endl;\n    }\n    ignwarn << msg.str();\n  }\n\n  if (nullptr == this->dataPtr->engine)\n  {\n    ignerr << \"Failed to load a valid physics engine from [\" << pathToLib\n           << \"].\"\n           << std::endl;\n  }\n}\n\n//////////////////////////////////////////////////\nPhysics::~Physics() = default;\n\n//////////////////////////////////////////////////\nvoid Physics::Update(const UpdateInfo &_info, EntityComponentManager &_ecm)\n{\n  IGN_PROFILE(\"Physics::Update\");\n\n  // \\TODO(anyone) Support rewind\n  if (_info.dt < std::chrono::steady_clock::duration::zero())\n  {\n    ignwarn << \"Detected jump back in time [\"\n        << std::chrono::duration_cast<std::chrono::seconds>(_info.dt).count()\n        << \"s]. System may not work properly.\" << std::endl;\n  }\n\n  // Update the component with the time in seconds that the simulation\n  // will have after the step\n  _ecm.Each<components::World, components::SimulatedTime>(\n              [&](const Entity& worldEntity,\n              const components::World*,\n              components::SimulatedTime*) {\n\n      scenario::gazebo::utils::setExistingComponentData<\n              components::SimulatedTime>(&_ecm, worldEntity, _info.simTime);\n      return true;\n  });\n\n  if (this->dataPtr->engine)\n  {\n    this->dataPtr->CreatePhysicsEntities(_ecm);\n    this->dataPtr->UpdatePhysics(_ecm, _info);\n    ignition::physics::ForwardStep::Output stepOutput;\n    // Only step if not paused.\n    if (!_info.paused)\n    {\n      stepOutput = this->dataPtr->Step(_info.dt);\n    }\n    auto changedLinks = this->dataPtr->ChangedLinks(_ecm, stepOutput);\n    this->dataPtr->UpdateSim(_ecm, changedLinks, _info);\n\n    // Entities scheduled to be removed should be removed from physics after the\n    // simulation step. Otherwise, since the to-be-removed entity still shows up\n    // in the ECM::Each the UpdatePhysics and UpdateSim calls will have an error\n    this->dataPtr->RemovePhysicsEntities(_ecm);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreatePhysicsEntities(const EntityComponentManager &_ecm)\n{\n  this->CreateWorldEntities(_ecm);\n  this->CreateModelEntities(_ecm);\n  this->CreateLinkEntities(_ecm);\n  // We don't need to add visuals to the physics engine.\n  this->CreateCollisionEntities(_ecm);\n  this->CreateJointEntities(_ecm);\n  this->CreateBatteryEntities(_ecm);\n\n  // Make sure that entities are processed by the plugin\n  // in the first iteration. This is necessary because\n  // the physics plugin can be loaded programmatically\n  // after the simulation has started and stepped.\n  if (this->firstRun)\n    this->firstRun = false;\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateWorldEntities(const EntityComponentManager &_ecm)\n{\n  // Get all the new worlds\n  auto processEntities =\n      [&](const Entity &_entity,\n        const components::World * /* _world */,\n        const components::Name *_name,\n        const components::Gravity *_gravity)->bool\n      {\n        // Check if world already exists\n        if (this->entityWorldMap.HasEntity(_entity))\n        {\n          ignwarn << \"World entity [\" << _entity\n                  << \"] marked as new, but it's already on the map.\"\n                  << std::endl;\n          return true;\n        }\n\n        sdf::World world;\n        world.SetName(_name->Data());\n        world.SetGravity(_gravity->Data());\n        auto worldPtrPhys = this->engine->ConstructWorld(world);\n        this->entityWorldMap.AddEntity(_entity, worldPtrPhys);\n\n        // Optional world features\n        auto collisionDetectorComp =\n            _ecm.Component<components::PhysicsCollisionDetector>(_entity);\n        if (collisionDetectorComp)\n        {\n          auto collisionDetectorFeature =\n              this->entityWorldMap.EntityCast<CollisionDetectorFeatureList>(\n              _entity);\n          if (!collisionDetectorFeature)\n          {\n            static bool informed{false};\n            if (!informed)\n            {\n              igndbg << \"Attempting to set physics options, but the \"\n                     << \"phyiscs engine doesn't support feature \"\n                     << \"[CollisionDetectorFeature]. Options will be ignored.\"\n                     << std::endl;\n              informed = true;\n            }\n          }\n          else\n          {\n            collisionDetectorFeature->SetCollisionDetector(\n                collisionDetectorComp->Data());\n          }\n        }\n\n        auto solverComp =\n            _ecm.Component<components::PhysicsSolver>(_entity);\n        if (solverComp)\n        {\n          auto solverFeature =\n              this->entityWorldMap.EntityCast<SolverFeatureList>(\n              _entity);\n          if (!solverFeature)\n          {\n            static bool informed{false};\n            if (!informed)\n            {\n              igndbg << \"Attempting to set physics options, but the \"\n                     << \"phyiscs engine doesn't support feature \"\n                     << \"[SolverFeature]. Options will be ignored.\"\n                     << std::endl;\n              informed = true;\n            }\n          }\n          else\n          {\n            solverFeature->SetSolver(solverComp->Data());\n          }\n        }\n\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::World, components::Name, components::Gravity>(\n      processEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::World, components::Name, components::Gravity>(\n      processEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateModelEntities(const EntityComponentManager &_ecm)\n{\n  auto processEntities =\n      [&](const Entity &_entity,\n          const components::Model *,\n          const components::Name *_name,\n          const components::Pose *_pose,\n          const components::ParentEntity *_parent)->bool\n      {\n        // Check if model already exists\n        if (this->entityModelMap.HasEntity(_entity))\n        {\n          ignwarn << \"Model entity [\" << _entity\n                  << \"] marked as new, but it's already on the map.\"\n                  << std::endl;\n          return true;\n        }\n        // TODO(anyone) Don't load models unless they have collisions\n\n        // Check if parent world / model exists\n        sdf::Model model;\n        model.SetName(_name->Data());\n        model.SetRawPose(_pose->Data());\n        auto staticComp = _ecm.Component<components::Static>(_entity);\n        if (staticComp && staticComp->Data())\n        {\n          model.SetStatic(staticComp->Data());\n          this->staticEntities.insert(_entity);\n        }\n        auto selfCollideComp = _ecm.Component<components::SelfCollide>(_entity);\n        if (selfCollideComp && selfCollideComp ->Data())\n        {\n          model.SetSelfCollide(selfCollideComp->Data());\n        }\n\n        // check if parent is a world\n        if (auto worldPtrPhys =\n                this->entityWorldMap.Get(_parent->Data()))\n        {\n          // Use the ConstructNestedModel feature for nested models\n          if (model.ModelCount() > 0)\n          {\n            auto nestedModelFeature =\n                this->entityWorldMap.EntityCast<NestedModelFeatureList>(\n                    _parent->Data());\n            if (!nestedModelFeature)\n            {\n              static bool informed{false};\n              if (!informed)\n              {\n                igndbg << \"Attempting to construct nested models, but the \"\n                       << \"phyiscs engine doesn't support feature \"\n                       << \"[ConstructSdfNestedModelFeature]. \"\n                       << \"Nested model will be ignored.\"\n                       << std::endl;\n                informed = true;\n              }\n              return true;\n            }\n            auto modelPtrPhys = nestedModelFeature->ConstructNestedModel(model);\n            this->entityModelMap.AddEntity(_entity, modelPtrPhys);\n            this->topLevelModelMap.insert(std::make_pair(_entity,\n                topLevelModel(_entity, _ecm)));\n          }\n          else\n          {\n            auto modelPtrPhys = worldPtrPhys->ConstructModel(model);\n            this->entityModelMap.AddEntity(_entity, modelPtrPhys);\n            this->topLevelModelMap.insert(std::make_pair(_entity,\n                topLevelModel(_entity, _ecm)));\n          }\n        }\n        // check if parent is a model (nested model)\n        else\n        {\n          if (auto parentPtrPhys = this->entityModelMap.Get(_parent->Data()))\n          {\n            auto nestedModelFeature =\n                this->entityModelMap.EntityCast<NestedModelFeatureList>(\n                    _parent->Data());\n            if (!nestedModelFeature)\n            {\n              static bool informed{false};\n              if (!informed)\n              {\n                igndbg << \"Attempting to construct nested models, but the \"\n                       << \"physics engine doesn't support feature \"\n                       << \"[ConstructSdfNestedModelFeature]. \"\n                       << \"Nested model will be ignored.\"\n                       << std::endl;\n                informed = true;\n              }\n              return true;\n            }\n\n            // override static property only if parent is static.\n            auto parentStaticComp =\n              _ecm.Component<components::Static>(_parent->Data());\n            if (parentStaticComp && parentStaticComp->Data())\n            {\n              model.SetStatic(true);\n              this->staticEntities.insert(_entity);\n            }\n\n            auto modelPtrPhys = nestedModelFeature->ConstructNestedModel(model);\n            if (modelPtrPhys)\n            {\n              this->entityModelMap.AddEntity(_entity, modelPtrPhys);\n              this->topLevelModelMap.insert(std::make_pair(_entity,\n                  topLevelModel(_entity, _ecm)));\n            }\n            else\n            {\n              ignerr << \"Model: '\" << _name->Data() << \"' not loaded. \"\n                     << \"Failed to create nested model.\"\n                     << std::endl;\n            }\n          }\n          else\n          {\n            ignwarn << \"Model's parent entity [\" << _parent->Data()\n                    << \"] not found on world / model map.\" << std::endl;\n            return true;\n          }\n        }\n\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::Model,\n              components::Name,\n              components::Pose,\n              components::ParentEntity>(processEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::Model,\n                 components::Name,\n                 components::Pose,\n                 components::ParentEntity>(processEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateLinkEntities(const EntityComponentManager &_ecm)\n{\n  auto processEntities =\n      [&](const Entity &_entity,\n        const components::Link * /* _link */,\n        const components::Name *_name,\n        const components::Pose *_pose,\n        const components::ParentEntity *_parent)->bool\n      {\n        // Check if link already exists\n        if (this->entityLinkMap.HasEntity(_entity))\n        {\n          ignwarn << \"Link entity [\" << _entity\n                  << \"] marked as new, but it's already on the map.\"\n                  << std::endl;\n          return true;\n        }\n\n        // TODO(anyone) Don't load links unless they have collisions\n\n        // Check if parent model exists\n        if (!this->entityModelMap.HasEntity(_parent->Data()))\n        {\n          ignwarn << \"Link's parent entity [\" << _parent->Data()\n                  << \"] not found on model map.\" << std::endl;\n          return true;\n        }\n        auto modelPtrPhys =\n            this->entityModelMap.Get(_parent->Data());\n\n        sdf::Link link;\n        link.SetName(_name->Data());\n        link.SetRawPose(_pose->Data());\n\n        if (this->staticEntities.find(_parent->Data()) !=\n            this->staticEntities.end())\n        {\n          this->staticEntities.insert(_entity);\n        }\n\n        // get link inertial\n        auto inertial = _ecm.Component<components::Inertial>(_entity);\n        if (inertial)\n        {\n          link.SetInertial(inertial->Data());\n        }\n\n        auto linkPtrPhys = modelPtrPhys->ConstructLink(link);\n        this->entityLinkMap.AddEntity(_entity, linkPtrPhys);\n        this->topLevelModelMap.insert(std::make_pair(_entity,\n            topLevelModel(_entity, _ecm)));\n\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::Link,\n              components::Name,\n              components::Pose,\n              components::ParentEntity>(processEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::Link,\n                 components::Name,\n                 components::Pose,\n                 components::ParentEntity>(processEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateCollisionEntities(const EntityComponentManager &_ecm)\n{\n  auto processEntities =\n      [&](const Entity &_entity,\n          const components::Collision *,\n          const components::Name *_name,\n          const components::Pose *_pose,\n          const components::Geometry *_geom,\n          const components::CollisionElement *_collElement,\n          const components::ParentEntity *_parent) -> bool\n      {\n        if (this->entityCollisionMap.HasEntity(_entity))\n        {\n           ignwarn << \"Collision entity [\" << _entity\n                   << \"] marked as new, but it's already on the map.\"\n                   << std::endl;\n          return true;\n        }\n\n        // Check if parent link exists\n        if (!this->entityLinkMap.HasEntity(_parent->Data()))\n        {\n          ignwarn << \"Collision's parent entity [\" << _parent->Data()\n                  << \"] not found on link map.\" << std::endl;\n          return true;\n        }\n        auto linkPtrPhys = this->entityLinkMap.Get(_parent->Data());\n\n        // Make a copy of the collision DOM so we can set its pose which has\n        // been resolved and is now expressed w.r.t the parent link of the\n        // collision.\n        sdf::Collision collision = _collElement->Data();\n        collision.SetRawPose(_pose->Data());\n        collision.SetPoseRelativeTo(\"\");\n        auto collideBitmask = collision.Surface()->Contact()->CollideBitmask();\n\n        ShapePtrType collisionPtrPhys;\n        if (_geom->Data().Type() == sdf::GeometryType::MESH)\n        {\n          const sdf::Mesh *meshSdf = _geom->Data().MeshShape();\n          if (nullptr == meshSdf)\n          {\n            ignwarn << \"Mesh geometry for collision [\" << _name->Data()\n                    << \"] missing mesh shape.\" << std::endl;\n            return true;\n          }\n\n          auto &meshManager = *ignition::common::MeshManager::Instance();\n          auto fullPath = asFullPath(meshSdf->Uri(), meshSdf->FilePath());\n          auto *mesh = meshManager.Load(fullPath);\n          if (nullptr == mesh)\n          {\n            ignwarn << \"Failed to load mesh from [\" << fullPath\n                    << \"].\" << std::endl;\n            return true;\n          }\n\n          auto linkMeshFeature =\n              this->entityLinkMap.EntityCast<MeshFeatureList>(_parent->Data());\n          if (!linkMeshFeature)\n          {\n            static bool informed{false};\n            if (!informed)\n            {\n              igndbg << \"Attempting to process mesh geometries, but the physics\"\n                     << \" engine doesn't support feature \"\n                     << \"[AttachMeshShapeFeature]. Meshes will be ignored.\"\n                     << std::endl;\n              informed = true;\n            }\n            return true;\n          }\n\n          collisionPtrPhys = linkMeshFeature->AttachMeshShape(_name->Data(),\n              *mesh,\n              math::eigen3::convert(_pose->Data()),\n              math::eigen3::convert(meshSdf->Scale()));\n        }\n        else if (_geom->Data().Type() == sdf::GeometryType::HEIGHTMAP)\n        {\n          auto linkHeightmapFeature =\n              this->entityLinkMap.EntityCast<HeightmapFeatureList>(\n                  _parent->Data());\n          if (!linkHeightmapFeature)\n          {\n            static bool informed{false};\n            if (!informed)\n            {\n              igndbg << \"Attempting to process heightmap geometries, but the \"\n                     << \"physics engine doesn't support feature \"\n                     << \"[AttachHeightmapShapeFeature]. Heightmaps will be \"\n                     << \"ignored.\" << std::endl;\n              informed = true;\n            }\n            return true;\n          }\n\n          auto heightmapSdf = _geom->Data().HeightmapShape();\n          if (nullptr == heightmapSdf)\n          {\n            ignwarn << \"Heightmap geometry for collision [\" << _name->Data()\n                    << \"] missing heightmap shape.\" << std::endl;\n            return true;\n          }\n\n          auto fullPath = asFullPath(heightmapSdf->Uri(),\n              heightmapSdf->FilePath());\n          if (fullPath.empty())\n          {\n            ignerr << \"Heightmap geometry missing URI\" << std::endl;\n            return true;\n          }\n\n          common::ImageHeightmap data;\n          if (data.Load(fullPath) < 0)\n          {\n            ignerr << \"Failed to load heightmap image data from [\" << fullPath\n                   << \"]\" << std::endl;\n            return true;\n          }\n\n          collisionPtrPhys = linkHeightmapFeature->AttachHeightmapShape(\n              _name->Data(),\n              data,\n              math::eigen3::convert(_pose->Data()),\n              math::eigen3::convert(heightmapSdf->Size()),\n              heightmapSdf->Sampling());\n        }\n        else\n        {\n          auto linkCollisionFeature =\n              this->entityLinkMap.EntityCast<CollisionFeatureList>(\n                  _parent->Data());\n          if (!linkCollisionFeature)\n          {\n            static bool informed{false};\n            if (!informed)\n            {\n              igndbg << \"Attempting to process collisions, but the physics \"\n                     << \"engine doesn't support feature \"\n                     << \"[ConstructSdfCollision]. Collisions will be ignored.\"\n                     << std::endl;\n              informed = true;\n            }\n            return true;\n          }\n\n          collisionPtrPhys =\n              linkCollisionFeature->ConstructCollision(collision);\n        }\n\n        if (nullptr == collisionPtrPhys)\n        {\n          igndbg << \"Failed to create collision [\" << _name->Data()\n                 << \"]. Does the physics engine support geometries of type [\"\n                 << static_cast<int>(_geom->Data().Type()) << \"]?\" << std::endl;\n          return true;\n        }\n\n        this->entityCollisionMap.AddEntity(_entity, collisionPtrPhys);\n\n        // Check that the physics engine has a filter mask feature\n        // Set the collide_bitmask if it does\n        auto filterMaskFeature =\n            this->entityCollisionMap.EntityCast<CollisionMaskFeatureList>(\n                _entity);\n        if (filterMaskFeature)\n        {\n          filterMaskFeature->SetCollisionFilterMask(collideBitmask);\n        }\n        else\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to set collision bitmasks, but the physics \"\n                   << \"engine doesn't support feature [CollisionFilterMask]. \"\n                   << \"Collision bitmasks will be ignored.\" << std::endl;\n            informed = true;\n          }\n        }\n\n        this->topLevelModelMap.insert(std::make_pair(_entity,\n            topLevelModel(_entity, _ecm)));\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::Collision,\n              components::Name,\n              components::Pose,\n              components::Geometry,\n              components::CollisionElement,\n              components::ParentEntity>(processEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::Collision,\n                 components::Name,\n                 components::Pose,\n                 components::Geometry,\n                 components::CollisionElement,\n                 components::ParentEntity>(processEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateJointEntities(const EntityComponentManager &_ecm)\n{\n  auto processJointEntities =\n      [&](const Entity &_entity,\n          const components::Joint * /* _joint */,\n          const components::Name *_name,\n          const components::JointType *_jointType,\n          const components::Pose *_pose,\n          const components::ThreadPitch *_threadPitch,\n          const components::ParentEntity *_parentModel,\n          const components::ParentLinkName *_parentLinkName,\n          const components::ChildLinkName *_childLinkName) -> bool\n      {\n        // Check if joint already exists\n        if (this->entityJointMap.HasEntity(_entity))\n        {\n          ignwarn << \"Joint entity [\" << _entity\n                  << \"] marked as new, but it's already on the map.\"\n                  << std::endl;\n          return true;\n        }\n\n        // Check if parent model exists\n        if (!this->entityModelMap.HasEntity(_parentModel->Data()))\n        {\n          ignwarn << \"Joint's parent entity [\" << _parentModel->Data()\n                  << \"] not found on model map.\" << std::endl;\n          return true;\n        }\n        auto modelPtrPhys = this->entityModelMap.Get(_parentModel->Data());\n\n        auto modelJointFeature =\n            this->entityModelMap.EntityCast<JointFeatureList>(\n                _parentModel->Data());\n        if (!modelJointFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to process joints, but the physics \"\n                   << \"engine doesn't support joint features. \"\n                   << \"Joints will be ignored.\" << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no joints can be processed\n          return false;\n        }\n\n        sdf::Joint joint;\n        joint.SetName(_name->Data());\n        joint.SetType(_jointType->Data());\n        joint.SetRawPose(_pose->Data());\n        joint.SetThreadPitch(_threadPitch->Data());\n\n        joint.SetParentLinkName(_parentLinkName->Data());\n        joint.SetChildLinkName(_childLinkName->Data());\n\n        auto jointAxis = _ecm.Component<components::JointAxis>(_entity);\n        auto jointAxis2 = _ecm.Component<components::JointAxis2>(_entity);\n\n        // Since we're making copies of the joint axes that were created using\n        // `Model::Load`, frame semantics should work for resolving their xyz\n        // axis\n        if (jointAxis)\n          joint.SetAxis(0, jointAxis->Data());\n        if (jointAxis2)\n          joint.SetAxis(1, jointAxis2->Data());\n\n        // Use the parent link's parent model as the model of this joint\n        auto jointPtrPhys = modelJointFeature->ConstructJoint(joint);\n\n        if (jointPtrPhys.Valid())\n        {\n          // Some joints may not be supported, so only add them to the map if\n          // the physics entity is valid\n          this->entityJointMap.AddEntity(_entity, jointPtrPhys);\n          this->topLevelModelMap.insert(std::make_pair(_entity,\n              topLevelModel(_entity, _ecm)));\n        }\n        return true;\n      };\n\n  // Detachable joints\n  auto processDetachableJointEntities =\n      [&](const Entity &_entity,\n          const components::DetachableJoint *_jointInfo) -> bool\n      {\n        if (_jointInfo->Data().jointType != \"fixed\")\n        {\n          ignerr << \"Detachable joint type [\" << _jointInfo->Data().jointType\n                 << \"] is currently not supported\" << std::endl;\n          return true;\n        }\n        // Check if joint already exists\n        if (this->entityJointMap.HasEntity(_entity))\n        {\n          ignwarn << \"Joint entity [\" << _entity\n                  << \"] marked as new, but it's already on the map.\"\n                  << std::endl;\n          return true;\n        }\n\n        // Check if the link entities exist in the physics engine\n        auto parentLinkPhys =\n            this->entityLinkMap.Get(_jointInfo->Data().parentLink);\n        if (!parentLinkPhys)\n        {\n          ignwarn << \"DetachableJoint's parent link entity [\"\n                  << _jointInfo->Data().parentLink << \"] not found in link map.\"\n                  << std::endl;\n          return true;\n        }\n\n        auto childLinkEntity = _jointInfo->Data().childLink;\n\n        // Get child link\n        auto childLinkPhys = this->entityLinkMap.Get(childLinkEntity);\n        if (!childLinkPhys)\n        {\n          ignwarn << \"Failed to find joint's child link [\" << childLinkEntity\n                  << \"].\" << std::endl;\n          return true;\n        }\n\n        auto childLinkDetachableJointFeature =\n            this->entityLinkMap.EntityCast<DetachableJointFeatureList>(\n                childLinkEntity);\n        if (!childLinkDetachableJointFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to create a detachable joint, but the physics\"\n                   << \" engine doesn't support feature \"\n                   << \"[AttachFixedJointFeature]. Detachable joints will be \"\n                   << \"ignored.\" << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no DetachableJoints can be processed\n          return false;\n        }\n\n        const auto poseParent =\n            parentLinkPhys->FrameDataRelativeToWorld().pose;\n        const auto poseChild =\n            childLinkDetachableJointFeature->FrameDataRelativeToWorld().pose;\n\n        // Pose of child relative to parent\n        auto poseParentChild = poseParent.inverse() * poseChild;\n        auto jointPtrPhys =\n            childLinkDetachableJointFeature->AttachFixedJoint(parentLinkPhys);\n        if (jointPtrPhys.Valid())\n        {\n          // We let the joint be at the origin of the child link.\n          jointPtrPhys->SetTransformFromParent(poseParentChild);\n\n          igndbg << \"Creating detachable joint [\" << _entity << \"]\"\n                 << std::endl;\n          this->entityJointMap.AddEntity(_entity, jointPtrPhys);\n          this->topLevelModelMap.insert(std::make_pair(_entity,\n              topLevelModel(_entity, _ecm)));\n        }\n        else\n        {\n          ignwarn << \"DetachableJoint could not be created.\" << std::endl;\n        }\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::Joint,\n              components::Name,\n              components::JointType,\n              components::Pose,\n              components::ThreadPitch,\n              components::ParentEntity,\n              components::ParentLinkName,\n              components::ChildLinkName>(processJointEntities);\n    _ecm.Each<components::DetachableJoint>(processDetachableJointEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::Joint,\n                 components::Name,\n                 components::JointType,\n                 components::Pose,\n                 components::ThreadPitch,\n                 components::ParentEntity,\n                 components::ParentLinkName,\n                 components::ChildLinkName>(processJointEntities);\n   _ecm.EachNew<components::DetachableJoint>(processDetachableJointEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::CreateBatteryEntities(const EntityComponentManager &_ecm)\n{\n  auto processEntities =\n      [&](const Entity & _entity, const components::BatterySoC *)->bool\n      {\n        // Parent entity of battery is model entity\n        this->entityOffMap.insert(std::make_pair(\n          _ecm.ParentEntity(_entity), false));\n        return true;\n      };\n\n  if (this->firstRun)\n  {\n    _ecm.Each<components::BatterySoC>(processEntities);\n  }\n  else\n  {\n    _ecm.EachNew<components::BatterySoC>(processEntities);\n  }\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::RemovePhysicsEntities(const EntityComponentManager &_ecm)\n{\n  // Assume the world will not be erased\n  // Only removing models is supported by ign-physics right now so we only\n  // remove links, joints and collisions if they are children of the removed\n  // model.\n  // We assume the links, joints and collisions will be removed from the\n  // physics engine when the containing model gets removed so, here, we only\n  // remove the entities from the gazebo entity->physics entity map.\n  _ecm.EachRemoved<components::Model>(\n      [&](const Entity &_entity, const components::Model *\n          /* _model */) -> bool\n      {\n        // Remove model if found\n        if (auto modelPtrPhys = this->entityModelMap.Get(_entity))\n        {\n          // Remove child links, collisions and joints first\n          for (const auto &childLink :\n               _ecm.ChildrenByComponents(_entity, components::Link()))\n          {\n            for (const auto &childCollision :\n                 _ecm.ChildrenByComponents(childLink, components::Collision()))\n            {\n              this->entityCollisionMap.Remove(childCollision);\n              this->topLevelModelMap.erase(childCollision);\n            }\n            this->entityLinkMap.Remove(childLink);\n            this->topLevelModelMap.erase(childLink);\n            this->staticEntities.erase(childLink);\n            this->linkWorldPoses.erase(childLink);\n            this->canonicalLinkModelTracker.RemoveLink(childLink);\n          }\n\n          for (const auto &childJoint :\n               _ecm.ChildrenByComponents(_entity, components::Joint()))\n          {\n            this->entityJointMap.Remove(childJoint);\n            this->topLevelModelMap.erase(childJoint);\n          }\n\n          this->entityFreeGroupMap.Remove(_entity);\n          // Remove the model from the physics engine\n          modelPtrPhys->Remove();\n          this->entityModelMap.Remove(_entity);\n          this->topLevelModelMap.erase(_entity);\n          this->staticEntities.erase(_entity);\n          this->modelWorldPoses.erase(_entity);\n        }\n        return true;\n      });\n\n  _ecm.EachRemoved<components::DetachableJoint>(\n      [&](const Entity &_entity, const components::DetachableJoint *) -> bool\n      {\n        if (!this->entityJointMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find joint [\" << _entity\n                  << \"].\" << std::endl;\n          return true;\n        }\n\n        auto castEntity =\n            this->entityJointMap.EntityCast<DetachableJointFeatureList>(\n                _entity);\n        if (!castEntity)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to detach a joint, but the physics \"\n                   << \"engine doesn't support feature \"\n                   << \"[DetachJointFeature]. Joint won't be detached.\"\n                   << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no DetachableJoints can be processed\n          return false;\n        }\n\n        igndbg << \"Detaching joint [\" << _entity << \"]\" << std::endl;\n        castEntity->Detach();\n        return true;\n      });\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::UpdatePhysics(EntityComponentManager &_ecm,\n                                   const ignition::gazebo::UpdateInfo &_info)\n{\n  IGN_PROFILE(\"PhysicsPrivate::UpdatePhysics\");\n  // Battery state\n  _ecm.Each<components::BatterySoC>(\n      [&](const Entity & _entity, const components::BatterySoC *_bat)\n      {\n        if (_bat->Data() <= 0)\n          entityOffMap[_ecm.ParentEntity(_entity)] = true;\n        else\n          entityOffMap[_ecm.ParentEntity(_entity)] = false;\n        return true;\n      });\n\n  // Handle joint state\n  _ecm.Each<components::Joint, components::Name>(\n      [&](const Entity &_entity, const components::Joint *,\n          const components::Name *_name)\n      {\n        auto jointPhys = this->entityJointMap.Get(_entity);\n        if (nullptr == jointPhys)\n          return true;\n\n        auto jointVelFeature =\n          this->entityJointMap.EntityCast<JointVelocityCommandFeatureList>(\n              _entity);\n\n        auto haltMotionComp = _ecm.Component<components::HaltMotion>(\n            _ecm.ParentEntity(_entity));\n        bool haltMotion = false;\n        if (haltMotionComp)\n        {\n          haltMotion = haltMotionComp->Data();\n        }\n\n        // Model is out of battery or halt motion has been triggered.\n        if (this->entityOffMap[_ecm.ParentEntity(_entity)] || haltMotion)\n        {\n          std::size_t nDofs = jointPhys->GetDegreesOfFreedom();\n          for (std::size_t i = 0; i < nDofs; ++i)\n          {\n            jointPhys->SetForce(i, 0);\n\n            // Halt motion requires the vehicle to come to a full stop,\n            // while running out of battery can leave existing joint velocity\n            // in place.\n            if (haltMotion && jointVelFeature)\n              jointVelFeature->SetVelocityCommand(i, 0);\n          }\n          return true;\n        }\n\n        auto posReset = _ecm.Component<components::JointPositionReset>(\n            _entity);\n        auto velReset = _ecm.Component<components::JointVelocityReset>(\n            _entity);\n\n        // Reset the velocity\n        if (velReset)\n        {\n          auto& jointVelocity = velReset->Data();\n\n          if (jointVelocity.size() != jointPhys->GetDegreesOfFreedom())\n          {\n            ignwarn << \"There is a mismatch in the degrees of freedom \"\n                    << \"between Joint [\" << _name->Data() << \"(Entity=\"\n                    << _entity << \")] and its JointVelocityReset \"\n                    << \"component. The joint has \"\n                    << jointPhys->GetDegreesOfFreedom()\n                    << \" while the component has \"\n                    << jointVelocity.size() << \".\\n\";\n            }\n\n            std::size_t nDofs = std::min(\n                jointVelocity.size(), jointPhys->GetDegreesOfFreedom());\n\n            for (std::size_t i = 0; i < nDofs; ++i)\n            {\n              jointPhys->SetVelocity(i, jointVelocity[i]);\n            }\n        }\n\n        // Reset the position\n        if (posReset)\n        {\n          auto &jointPosition = posReset->Data();\n\n          if (jointPosition.size() != jointPhys->GetDegreesOfFreedom())\n          {\n            ignwarn << \"There is a mismatch in the degrees of freedom \"\n                    << \"between Joint [\" << _name->Data() << \"(Entity=\"\n                    << _entity << \")] and its JointPositionyReset \"\n                    << \"component. The joint has \"\n                    << jointPhys->GetDegreesOfFreedom()\n                    << \" while the component has \"\n                    << jointPosition.size() << \".\\n\";\n            }\n            std::size_t nDofs = std::min(\n                jointPosition.size(), jointPhys->GetDegreesOfFreedom());\n            for (std::size_t i = 0; i < nDofs; ++i)\n            {\n              jointPhys->SetPosition(i, jointPosition[i]);\n            }\n        }\n\n        auto force = _ecm.Component<components::JointForceCmd>(_entity);\n        auto velCmd = _ecm.Component<components::JointVelocityCmd>(_entity);\n\n        if (force)\n        {\n          if (force->Data().size() != jointPhys->GetDegreesOfFreedom())\n          {\n            ignwarn << \"There is a mismatch in the degrees of freedom between \"\n                    << \"Joint [\" << _name->Data() << \"(Entity=\" << _entity\n                    << \")] and its JointForceCmd component. The joint has \"\n                    << jointPhys->GetDegreesOfFreedom() << \" while the \"\n                    << \" component has \" << force->Data().size() << \".\\n\";\n          }\n          std::size_t nDofs = std::min(force->Data().size(),\n                                       jointPhys->GetDegreesOfFreedom());\n          for (std::size_t i = 0; i < nDofs; ++i)\n          {\n            jointPhys->SetForce(i, force->Data()[i]);\n          }\n        }\n        // Only set joint velocity if joint force is not set.\n        // If both the cmd and reset components are found, cmd is ignored.\n        else if (velCmd)\n        {\n          auto velocityCmd = velCmd->Data();\n\n          if (velReset)\n          {\n            ignwarn << \"Found both JointVelocityReset and \"\n                    << \"JointVelocityCmd components for Joint [\"\n                    << _name->Data() << \"(Entity=\" << _entity\n                    << \"]). Ignoring JointVelocityCmd component.\"\n                    << std::endl;\n            return true;\n          }\n\n          if (velocityCmd.size() != jointPhys->GetDegreesOfFreedom())\n          {\n            ignwarn << \"There is a mismatch in the degrees of freedom\"\n                    << \" between Joint [\" << _name->Data()\n                    << \"(Entity=\" << _entity<< \")] and its \"\n                    << \"JointVelocityCmd component. The joint has \"\n                    << jointPhys->GetDegreesOfFreedom()\n                    << \" while the component has \"\n                    << velocityCmd.size() << \".\\n\";\n          }\n\n          if (!jointVelFeature)\n          {\n            return true;\n          }\n\n          std::size_t nDofs = std::min(\n            velocityCmd.size(),\n            jointPhys->GetDegreesOfFreedom());\n\n          for (std::size_t i = 0; i < nDofs; ++i)\n          {\n            jointVelFeature->SetVelocityCommand(i, velocityCmd[i]);\n          }\n        }\n\n        return true;\n      });\n\n  // Link wrenches\n  _ecm.Each<components::ExternalWorldWrenchCmd>(\n      [&](const Entity &_entity,\n          const components::ExternalWorldWrenchCmd *_wrenchComp)\n      {\n        if (!this->entityLinkMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find link [\" << _entity\n                  << \"].\" << std::endl;\n          return true;\n        }\n\n        auto linkForceFeature =\n            this->entityLinkMap.EntityCast<LinkForceFeatureList>(_entity);\n        if (!linkForceFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to apply a wrench, but the physics \"\n                   << \"engine doesn't support feature \"\n                   << \"[AddLinkExternalForceTorque]. Wrench will be ignored.\"\n                   << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no ExternalWorldWrenchCmd's can be processed\n          return false;\n        }\n\n        math::Vector3 force = msgs::Convert(_wrenchComp->Data().force());\n        math::Vector3 torque = msgs::Convert(_wrenchComp->Data().torque());\n        linkForceFeature->AddExternalForce(math::eigen3::convert(force));\n        linkForceFeature->AddExternalTorque(math::eigen3::convert(torque));\n\n        return true;\n      });\n\n  // Link wrenches with duration\n  if (!_info.paused)\n  {\n    _ecm.Each<components::ExternalWorldWrenchCmdWithDuration>(\n        [&](const Entity& _entity,\n            components::ExternalWorldWrenchCmdWithDuration*\n                _wrenchWithDurComp)\n    {\n      if (!this->entityLinkMap.HasEntity(_entity))\n      {\n        ignwarn << \"Failed to find link [\" << _entity << \"].\"\n                << std::endl;\n        return true;\n      }\n\n      auto linkForceFeature =\n           this->entityLinkMap.EntityCast<LinkForceFeatureList>(_entity);\n      if (!linkForceFeature) {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to apply a wrench, but the physics \"\n                   << \"engine doesn't support feature \"\n                   << \"[AddLinkExternalForceTorque]. Wrench will be ignored.\"\n                   << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no ExternalWorldWrenchCmd's can be processed\n          return false;\n      }\n\n      // Skip the application if there is no wrench to apply\n      if (_wrenchWithDurComp->Data().empty())\n          return true;\n\n      // Compute the total wrench\n      const auto& totalWrench =  _wrenchWithDurComp->Data().totalWrench();\n      const math::Vector3 force = msgs::Convert(totalWrench.force());\n      const math::Vector3 torque = msgs::Convert(totalWrench.torque());\n\n      // Apply the wrench\n      linkForceFeature->AddExternalForce(math::eigen3::convert(force));\n      linkForceFeature->AddExternalTorque(math::eigen3::convert(torque));\n\n      // NOTE: Cleaning could be moved to UpdateSim, but let's\n      //       keep things all together for now\n      auto simTimeAfterStep = _info.simTime;\n      _wrenchWithDurComp->Data().cleanExpired(simTimeAfterStep);\n\n      return true;\n    });\n  }\n\n  // Update model pose\n  auto olderWorldPoseCmdsToRemove = std::move(this->worldPoseCmdsToRemove);\n  this->worldPoseCmdsToRemove.clear();\n\n  _ecm.Each<components::Model, components::WorldPoseCmd>(\n      [&](const Entity &_entity, const components::Model *,\n          const components::WorldPoseCmd *_poseCmd)\n      {\n        this->worldPoseCmdsToRemove.insert(_entity);\n\n        auto modelPtrPhys = this->entityModelMap.Get(_entity);\n        if (nullptr == modelPtrPhys)\n          return true;\n\n        // world pose cmd currently not supported for nested models\n        if (_entity != this->topLevelModelMap[_entity])\n        {\n          ignerr << \"Unable to set world pose for nested models.\"\n                 << std::endl;\n          return true;\n        }\n\n        // TODO(addisu) Store the free group instead of searching for it at\n        // every iteration\n        auto freeGroup = modelPtrPhys->FindFreeGroup();\n        if (!freeGroup)\n          return true;\n\n        // Get root link offset\n        const auto linkEntity =\n            this->entityLinkMap.Get(freeGroup->RootLink());\n        if (linkEntity == kNullEntity)\n          return true;\n\n        // set world pose of root link in freegroup\n        // root link might be in a nested model so use RelativePose to get\n        // its pose relative to this model\n        math::Pose3d linkPose =\n            this->RelativePose(_entity, linkEntity, _ecm);\n\n        freeGroup->SetWorldPose(math::eigen3::convert(_poseCmd->Data() *\n                                linkPose));\n\n        // Process pose commands for static models here, as one-time changes\n        if (this->staticEntities.find(_entity) != this->staticEntities.end())\n        {\n          auto worldPoseComp = _ecm.Component<components::Pose>(_entity);\n          if (worldPoseComp)\n          {\n            auto state = worldPoseComp->SetData(_poseCmd->Data(),\n                this->pose3Eql) ?\n                ComponentState::OneTimeChange :\n                ComponentState::NoChange;\n            _ecm.SetChanged(_entity, components::Pose::typeId, state);\n          }\n        }\n\n        return true;\n      });\n\n  // Remove world commands from previous iteration. We let them rotate one\n  // iteration so other systems have a chance to react to them too.\n  for (const Entity &entity : olderWorldPoseCmdsToRemove)\n  {\n    _ecm.RemoveComponent<components::WorldPoseCmd>(entity);\n  }\n\n  // Slip compliance on Collisions\n  _ecm.Each<components::SlipComplianceCmd>(\n      [&](const Entity &_entity,\n          const components::SlipComplianceCmd *_slipCmdComp)\n      {\n        if (!this->entityCollisionMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find shape [\" << _entity << \"].\" << std::endl;\n          return true;\n        }\n\n        auto slipComplianceShape =\n            this->entityCollisionMap\n                .EntityCast<FrictionPyramidSlipComplianceFeatureList>(_entity);\n\n        if (!slipComplianceShape)\n        {\n          ignwarn << \"Can't process Wheel Slip component, physics engine \"\n                  << \"missing SetShapeFrictionPyramidSlipCompliance\"\n                  << std::endl;\n\n          // Break Each call since no SlipCompliances can be processed\n          return false;\n        }\n\n        if (_slipCmdComp->Data().size() == 2)\n        {\n          slipComplianceShape->SetPrimarySlipCompliance(\n              _slipCmdComp->Data()[0]);\n          slipComplianceShape->SetSecondarySlipCompliance(\n              _slipCmdComp->Data()[1]);\n        }\n\n        return true;\n      });\n\n  // Update model angular velocity\n  _ecm.Each<components::Model, components::AngularVelocityCmd>(\n      [&](const Entity &_entity, const components::Model *,\n          const components::AngularVelocityCmd *_angularVelocityCmd)\n      {\n        auto modelPtrPhys = this->entityModelMap.Get(_entity);\n        if (nullptr == modelPtrPhys)\n          return true;\n\n        // angular vel cmd currently not supported for nested models\n        if (_entity != this->topLevelModelMap[_entity])\n        {\n          ignerr << \"Unable to set angular velocity for nested models.\"\n                 << std::endl;\n          return true;\n        }\n\n        auto freeGroup = modelPtrPhys->FindFreeGroup();\n        if (!freeGroup)\n          return true;\n        this->entityFreeGroupMap.AddEntity(_entity, freeGroup);\n\n        const components::Pose *poseComp =\n            _ecm.Component<components::Pose>(_entity);\n        math::Vector3d worldAngularVel = poseComp->Data().Rot() *\n            _angularVelocityCmd->Data();\n\n        auto worldAngularVelFeature =\n            this->entityFreeGroupMap\n                .EntityCast<WorldVelocityCommandFeatureList>(_entity);\n        if (!worldAngularVelFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to set model angular velocity, but the \"\n                   << \"physics engine doesn't support velocity commands. \"\n                   << \"Velocity won't be set.\"\n                   << std::endl;\n            informed = true;\n          }\n          return true;\n        }\n\n        worldAngularVelFeature->SetWorldAngularVelocity(\n            math::eigen3::convert(worldAngularVel));\n\n        return true;\n      });\n\n  // Update model linear velocity\n  _ecm.Each<components::Model, components::LinearVelocityCmd>(\n      [&](const Entity &_entity, const components::Model *,\n          const components::LinearVelocityCmd *_linearVelocityCmd)\n      {\n        auto modelPtrPhys = this->entityModelMap.Get(_entity);\n        if (nullptr == modelPtrPhys)\n          return true;\n\n        // linear vel cmd currently not supported for nested models\n        if (_entity != this->topLevelModelMap[_entity])\n        {\n          ignerr << \"Unable to set linear velocity for nested models.\"\n                 << std::endl;\n          return true;\n        }\n\n        auto freeGroup = modelPtrPhys->FindFreeGroup();\n        if (!freeGroup)\n          return true;\n\n        this->entityFreeGroupMap.AddEntity(_entity, freeGroup);\n\n        const components::Pose *poseComp =\n            _ecm.Component<components::Pose>(_entity);\n        math::Vector3d worldLinearVel = poseComp->Data().Rot() *\n            _linearVelocityCmd->Data();\n\n        auto worldLinearVelFeature =\n            this->entityFreeGroupMap\n                .EntityCast<WorldVelocityCommandFeatureList>(_entity);\n        if (!worldLinearVelFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to set model linear velocity, but the \"\n                   << \"physics engine doesn't support velocity commands. \"\n                   << \"Velocity won't be set.\"\n                   << std::endl;\n            informed = true;\n          }\n          return true;\n        }\n\n        worldLinearVelFeature->SetWorldLinearVelocity(\n            math::eigen3::convert(worldLinearVel));\n\n        return true;\n      });\n\n  // Update link angular velocity\n  _ecm.Each<components::Link, components::AngularVelocityCmd>(\n      [&](const Entity &_entity, const components::Link *,\n          const components::AngularVelocityCmd *_angularVelocityCmd)\n      {\n        if (!this->entityLinkMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find link [\" << _entity\n                  << \"].\" << std::endl;\n          return true;\n        }\n\n        auto linkPtrPhys = this->entityLinkMap.Get(_entity);\n        if (nullptr == linkPtrPhys)\n          return true;\n\n        auto freeGroup = linkPtrPhys->FindFreeGroup();\n        if (!freeGroup)\n          return true;\n        this->entityFreeGroupMap.AddEntity(_entity, freeGroup);\n\n        auto worldAngularVelFeature =\n            this->entityFreeGroupMap\n                .EntityCast<WorldVelocityCommandFeatureList>(_entity);\n\n        if (!worldAngularVelFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to set link angular velocity, but the \"\n                   << \"physics engine doesn't support velocity commands. \"\n                   << \"Velocity won't be set.\"\n                   << std::endl;\n            informed = true;\n          }\n          return true;\n        }\n        // velocity in world frame = world_to_model_tf * model_to_link_tf * vel\n        Entity modelEntity = topLevelModel(_entity, _ecm);\n        const components::Pose *modelEntityPoseComp =\n            _ecm.Component<components::Pose>(modelEntity);\n        math::Pose3d modelToLinkTransform = this->RelativePose(\n            modelEntity, _entity, _ecm);\n        math::Vector3d worldAngularVel = modelEntityPoseComp->Data().Rot()\n            * modelToLinkTransform.Rot() * _angularVelocityCmd->Data();\n        worldAngularVelFeature->SetWorldAngularVelocity(\n            math::eigen3::convert(worldAngularVel));\n\n        return true;\n      });\n\n  // Update link linear velocity\n  _ecm.Each<components::Link, components::LinearVelocityCmd>(\n      [&](const Entity &_entity, const components::Link *,\n          const components::LinearVelocityCmd *_linearVelocityCmd)\n      {\n        if (!this->entityLinkMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find link [\" << _entity\n                  << \"].\" << std::endl;\n          return true;\n        }\n\n        auto linkPtrPhys = this->entityLinkMap.Get(_entity);\n        if (nullptr == linkPtrPhys)\n          return true;\n\n        auto freeGroup = linkPtrPhys->FindFreeGroup();\n        if (!freeGroup)\n          return true;\n        this->entityFreeGroupMap.AddEntity(_entity, freeGroup);\n\n        auto worldLinearVelFeature =\n            this->entityFreeGroupMap\n                .EntityCast<WorldVelocityCommandFeatureList>(_entity);\n        if (!worldLinearVelFeature)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to set link linear velocity, but the \"\n                   << \"physics engine doesn't support velocity commands. \"\n                   << \"Velocity won't be set.\"\n                   << std::endl;\n            informed = true;\n          }\n          return true;\n        }\n\n        // velocity in world frame = world_to_model_tf * model_to_link_tf * vel\n        Entity modelEntity = topLevelModel(_entity, _ecm);\n        const components::Pose *modelEntityPoseComp =\n            _ecm.Component<components::Pose>(modelEntity);\n        math::Pose3d modelToLinkTransform = this->RelativePose(\n            modelEntity, _entity, _ecm);\n        math::Vector3d worldLinearVel = modelEntityPoseComp->Data().Rot()\n            * modelToLinkTransform.Rot() * _linearVelocityCmd->Data();\n        worldLinearVelFeature->SetWorldLinearVelocity(\n            math::eigen3::convert(worldLinearVel));\n\n        return true;\n      });\n\n\n  // Populate bounding box info\n  // Only compute bounding box if component exists to avoid unnecessary\n  // computations\n  _ecm.Each<components::Model, components::AxisAlignedBox>(\n      [&](const Entity &_entity, const components::Model *,\n          components::AxisAlignedBox *_bbox)\n      {\n        if (!this->entityModelMap.HasEntity(_entity))\n        {\n          ignwarn << \"Failed to find model [\" << _entity << \"].\" << std::endl;\n          return true;\n        }\n\n        auto bbModel =\n            this->entityModelMap.EntityCast<BoundingBoxFeatureList>(_entity);\n\n        if (!bbModel)\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg << \"Attempting to get a bounding box, but the physics \"\n                   << \"engine doesn't support feature \"\n                   << \"[GetModelBoundingBox]. Bounding box won't be populated.\"\n                   << std::endl;\n            informed = true;\n          }\n\n          // Break Each call since no AxisAlignedBox'es can be processed\n          return false;\n        }\n\n        math::AxisAlignedBox bbox =\n            math::eigen3::convert(bbModel->GetAxisAlignedBoundingBox());\n        auto state = _bbox->SetData(bbox, this->axisAlignedBoxEql) ?\n            ComponentState::PeriodicChange :\n            ComponentState::NoChange;\n        _ecm.SetChanged(_entity, components::AxisAlignedBox::typeId, state);\n\n        return true;\n      });\n}\n\n//////////////////////////////////////////////////\nignition::physics::ForwardStep::Output PhysicsPrivate::Step(\n    const std::chrono::steady_clock::duration &_dt)\n{\n  IGN_PROFILE(\"PhysicsPrivate::Step\");\n  ignition::physics::ForwardStep::Input input;\n  ignition::physics::ForwardStep::State state;\n  ignition::physics::ForwardStep::Output output;\n\n  input.Get<std::chrono::steady_clock::duration>() = _dt;\n\n  for (const auto &world : this->entityWorldMap.Map())\n  {\n    world.second->Step(output, state, input);\n  }\n\n  return output;\n}\n\n//////////////////////////////////////////////////\nignition::math::Pose3d PhysicsPrivate::RelativePose(const Entity &_from,\n  const Entity &_to, const EntityComponentManager &_ecm) const\n{\n  math::Pose3d transform;\n\n  if (_from == _to)\n    return transform;\n\n  auto currentEntity = _to;\n  auto parentComp = _ecm.Component<components::ParentEntity>(_to);\n  while (parentComp)\n  {\n    auto parentEntity = parentComp->Data();\n\n    // get the entity pose\n    auto entityPoseComp =\n      _ecm.Component<components::Pose>(currentEntity);\n\n    // update transform\n    transform = entityPoseComp->Data() * transform;\n\n    if (parentEntity == _from)\n      break;\n\n    // set current entity to parent\n    currentEntity = parentEntity;\n\n    // get entity's parent\n    parentComp = _ecm.Component<components::ParentEntity>(\n      parentEntity);\n  }\n\n  return transform;\n}\n\n//////////////////////////////////////////////////\nstd::map<Entity, physics::FrameData3d> PhysicsPrivate::ChangedLinks(\n    EntityComponentManager &_ecm,\n    const ignition::physics::ForwardStep::Output &_updatedLinks)\n{\n  IGN_PROFILE(\"Links Frame Data\");\n\n  std::map<Entity, physics::FrameData3d> linkFrameData;\n\n  // Check to see if the physics engine gave a list of changed poses. If not, we\n  // will iterate through all of the links via the ECM to see which ones changed\n  if (_updatedLinks.Has<ignition::physics::ChangedWorldPoses>())\n  {\n    for (const auto &link :\n        _updatedLinks.Query<ignition::physics::ChangedWorldPoses>()->entries)\n    {\n      // get the gazebo entity that matches the updated physics link entity\n      const auto linkPhys = this->entityLinkMap.GetPhysicsEntityPtr(link.body);\n      if (nullptr == linkPhys)\n      {\n        ignerr << \"Internal error: a physics entity ptr with an ID of [\"\n          << link.body << \"] does not exist.\" << std::endl;\n        continue;\n      }\n      auto entity = this->entityLinkMap.Get(linkPhys);\n      if (entity == kNullEntity)\n      {\n        ignerr << \"Internal error: no gazebo entity matches the physics entity \"\n          << \"with ID [\" << link.body << \"].\" << std::endl;\n        continue;\n      }\n\n      auto frameData = linkPhys->FrameDataRelativeToWorld();\n      linkFrameData[entity] = frameData;\n    }\n  }\n  else\n  {\n    _ecm.Each<components::Link>(\n      [&](const Entity &_entity, components::Link *) -> bool\n      {\n        if (this->staticEntities.find(_entity) != this->staticEntities.end())\n          return true;\n\n        auto linkPhys = this->entityLinkMap.Get(_entity);\n        if (nullptr == linkPhys)\n        {\n          ignerr << \"Internal error: link [\" << _entity\n                 << \"] not in entity map\" << std::endl;\n          return true;\n        }\n\n        auto frameData = linkPhys->FrameDataRelativeToWorld();\n\n        // update the link pose if this is the first update,\n        // or if the link pose has changed since the last update\n        // (if the link pose hasn't changed, there's no need for a pose update)\n        const auto worldPoseMath3d = ignition::math::eigen3::convert(\n            frameData.pose);\n        if ((this->linkWorldPoses.find(_entity) == this->linkWorldPoses.end())\n            || !this->pose3Eql(this->linkWorldPoses[_entity], worldPoseMath3d))\n        {\n          // cache the updated link pose to check if the link pose has changed\n          // during the next iteration\n          this->linkWorldPoses[_entity] = worldPoseMath3d;\n\n          linkFrameData[_entity] = frameData;\n        }\n\n        return true;\n      });\n  }\n\n  return linkFrameData;\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::UpdateModelPose(const Entity _model,\n    const Entity _canonicalLink, EntityComponentManager &_ecm,\n    std::map<Entity, physics::FrameData3d> &_linkFrameData)\n{\n  std::optional<math::Pose3d> parentWorldPose;\n\n  // If this model is nested, the pose of the parent model has already\n  // been updated since we iterate through the modified links in\n  // topological order. We expect to find the updated pose in\n  // this->modelWorldPoses. If not found, this must not be nested, so this\n  // model's pose component would reflect it's absolute pose.\n  auto parentModelPoseIt =\n    this->modelWorldPoses.find(\n        _ecm.Component<components::ParentEntity>(_model)->Data());\n  if (parentModelPoseIt != this->modelWorldPoses.end())\n  {\n    parentWorldPose = parentModelPoseIt->second;\n  }\n\n  // Given the following frame names:\n  // W: World/inertial frame\n  // P: Parent frame (this could be a parent model or the World frame)\n  // M: This model's frame\n  // L: The frame of this model's canonical link\n  //\n  // And the following quantities:\n  // (See http://sdformat.org/tutorials?tut=specify_pose for pose\n  // convention)\n  // parentWorldPose (X_WP): Pose of the parent frame w.r.t the world\n  // linkPoseFromModel (X_ML): Pose of the canonical link frame w.r.t the\n  // model frame\n  // linkWorldPose (X_WL): Pose of the canonical link w.r.t the world\n  // modelWorldPose (X_WM): Pose of this model w.r.t the world\n  //\n  // The Pose component of this model entity stores the pose of M w.r.t P\n  // (X_PM) and is calculated as\n  //   X_PM = (X_WP)^-1 * X_WM\n  //\n  // And X_WM is calculated from X_WL, which is obtained from physics as:\n  //   X_WM = X_WL * (X_ML)^-1\n  auto linkPoseFromModel = this->RelativePose(_model, _canonicalLink, _ecm);\n  const auto &linkWorldPose = _linkFrameData[_canonicalLink].pose;\n  const auto &modelWorldPose =\n      math::eigen3::convert(linkWorldPose) * linkPoseFromModel.Inverse();\n\n  this->modelWorldPoses[_model] = modelWorldPose;\n\n  // update model's pose\n  auto modelPose = _ecm.Component<components::Pose>(_model);\n  if (parentWorldPose)\n  {\n    *modelPose =\n        components::Pose(parentWorldPose->Inverse() * modelWorldPose);\n  }\n  else\n  {\n    // This is a non-nested model and parentWorldPose would be identity\n    // because it would be the pose of the parent (world) w.r.t the world.\n    *modelPose = components::Pose(modelWorldPose);\n  }\n\n  _ecm.SetChanged(_model, components::Pose::typeId,\n                  ComponentState::PeriodicChange);\n\n  // once the model pose has been updated, all descendant link poses of this\n  // model must be updated (whether the link actually changed pose or not)\n  // since link poses are saved w.r.t. their parent model\n  auto model = gazebo::Model(_model);\n  for (const auto &childLink : model.Links(_ecm))\n  {\n    // skip links that are already marked as a link to be updated\n    if (_linkFrameData.find(childLink) != _linkFrameData.end())\n      continue;\n\n    physics::FrameData3d childLinkFrameData;\n    if (!this->GetFrameDataRelativeToWorld(childLink, childLinkFrameData))\n      continue;\n\n    _linkFrameData[childLink] = childLinkFrameData;\n  }\n\n  // since nested model poses are saved w.r.t. the nested model's parent\n  // pose, we must also update any nested models that have a different\n  // canonical link\n  for (const auto &nestedModel : model.Models(_ecm))\n  {\n    auto nestedModelCanonicalLinkComp =\n      _ecm.Component<components::ModelCanonicalLink>(nestedModel);\n    if (!nestedModelCanonicalLinkComp)\n    {\n      auto staticComp = _ecm.Component<components::Static>(nestedModel);\n      if (!staticComp || !staticComp->Data())\n        ignerr << \"Model [\" << nestedModel << \"] has no canonical link\\n\";\n      continue;\n    }\n\n    auto nestedCanonicalLink = nestedModelCanonicalLinkComp->Data();\n\n    // skip links that are already marked as a link to be updated\n    if (nestedCanonicalLink == _canonicalLink ||\n        _linkFrameData.find(nestedCanonicalLink) != _linkFrameData.end())\n      continue;\n\n    // mark this canonical link as one that needs to be updated so that all of\n    // the models that have this canonical link are updated\n    physics::FrameData3d canonicalLinkFrameData;\n    if (!this->GetFrameDataRelativeToWorld(nestedCanonicalLink,\n          canonicalLinkFrameData))\n      continue;\n\n    _linkFrameData[nestedCanonicalLink] = canonicalLinkFrameData;\n  }\n}\n\n//////////////////////////////////////////////////\nbool PhysicsPrivate::GetFrameDataRelativeToWorld(const Entity _entity,\n    physics::FrameData3d &_data)\n{\n  auto entityPhys = this->entityLinkMap.Get(_entity);\n  if (nullptr == entityPhys)\n  {\n    ignerr << \"Internal error: entity [\" << _entity\n           << \"] not in entity map\" << std::endl;\n    return false;\n  }\n\n  _data = entityPhys->FrameDataRelativeToWorld();\n  return true;\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::UpdateSim(EntityComponentManager &_ecm,\n    std::map<Entity, physics::FrameData3d> &_linkFrameData,\n    const ignition::gazebo::UpdateInfo &_info)\n{\n  IGN_PROFILE(\"PhysicsPrivate::UpdateSim\");\n\n  // Populate world components with default values\n  _ecm.EachNew<components::World>(\n      [&](const Entity &_entity,\n        const components::World *)->bool\n      {\n        // If not provided by ECM, create component with values from physics if\n        // those features are available\n        auto collisionDetectorComp =\n            _ecm.Component<components::PhysicsCollisionDetector>(_entity);\n        if (!collisionDetectorComp)\n        {\n          auto collisionDetectorFeature =\n              this->entityWorldMap.EntityCast<CollisionDetectorFeatureList>(\n              _entity);\n          if (collisionDetectorFeature)\n          {\n            _ecm.CreateComponent(_entity, components::PhysicsCollisionDetector(\n                collisionDetectorFeature->GetCollisionDetector()));\n          }\n        }\n\n        auto solverComp = _ecm.Component<components::PhysicsSolver>(_entity);\n        if (!solverComp)\n        {\n          auto solverFeature =\n              this->entityWorldMap.EntityCast<SolverFeatureList>(_entity);\n          if (solverFeature)\n          {\n            _ecm.CreateComponent(_entity,\n                components::PhysicsSolver(solverFeature->GetSolver()));\n          }\n        }\n\n        return true;\n      });\n\n  IGN_PROFILE_BEGIN(\"Models\");\n\n  // make sure we have an up-to-date mapping of canonical links to their models\n  this->canonicalLinkModelTracker.AddNewModels(_ecm);\n\n  for (const auto &[linkEntity, frameData] : _linkFrameData)\n  {\n    // get a topological ordering of the models that have linkEntity as the\n    // model's canonical link. If linkEntity isn't a canonical link for any\n    // models, canonicalLinkModels will be empty\n    auto canonicalLinkModels =\n      this->canonicalLinkModelTracker.CanonicalLinkModels(linkEntity);\n\n    // Update poses for all of the models that have this changed canonical link\n    // (linkEntity). Since we have the models in topological order and\n    // _linkFrameData stores links in topological order thanks to the ordering\n    // of std::map (entity IDs are created in ascending order), this should\n    // properly handle pose updates for nested models that share the same\n    // canonical link.\n    //\n    // Nested models that don't share the same canonical link will also need to\n    // be updated since these nested models have their pose saved w.r.t. their\n    // parent model, which just experienced a pose update. The UpdateModelPose\n    // method also handles this case.\n    for (auto &modelEnt : canonicalLinkModels)\n      this->UpdateModelPose(modelEnt, linkEntity, _ecm, _linkFrameData);\n  }\n  IGN_PROFILE_END();\n\n  // Link poses, velocities...\n  IGN_PROFILE_BEGIN(\"Links\");\n  for (const auto &[entity, frameData] : _linkFrameData)\n  {\n    IGN_PROFILE_BEGIN(\"Local pose\");\n    auto canonicalLink =\n        _ecm.Component<components::CanonicalLink>(entity);\n\n    const auto &worldPose = frameData.pose;\n    const auto parentEntity = _ecm.ParentEntity(entity);\n\n    if (!canonicalLink)\n    {\n      // Compute the relative pose of this link from the parent model\n      auto parentModelPoseIt = this->modelWorldPoses.find(parentEntity);\n      if (parentModelPoseIt == this->modelWorldPoses.end())\n      {\n        ignerr << \"Internal error: parent model [\" << parentEntity\n              << \"] does not have a world pose available\" << std::endl;\n        continue;\n      }\n      const math::Pose3d &parentWorldPose = parentModelPoseIt->second;\n\n      // Unlike canonical links, pose of regular links can move relative.\n      // to the parent. Same for links inside nested models.\n      auto pose = _ecm.Component<components::Pose>(entity);\n      *pose = components::Pose(parentWorldPose.Inverse() *\n                                math::eigen3::convert(worldPose));\n      _ecm.SetChanged(entity, components::Pose::typeId,\n          ComponentState::PeriodicChange);\n    }\n    IGN_PROFILE_END();\n\n    // Populate world poses, velocities and accelerations of the link. For\n    // now these components are updated only if another system has created\n    // the corresponding component on the entity.\n    auto worldPoseComp = _ecm.Component<components::WorldPose>(entity);\n    if (worldPoseComp)\n    {\n      auto state =\n          worldPoseComp->SetData(math::eigen3::convert(frameData.pose),\n          this->pose3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity, components::WorldPose::typeId, state);\n    }\n\n    // Velocity in world coordinates\n    auto worldLinVelComp =\n        _ecm.Component<components::WorldLinearVelocity>(entity);\n    if (worldLinVelComp)\n    {\n      auto state = worldLinVelComp->SetData(\n            math::eigen3::convert(frameData.linearVelocity),\n            this->vec3Eql) ?\n            ComponentState::PeriodicChange :\n            ComponentState::NoChange;\n      _ecm.SetChanged(entity,\n          components::WorldLinearVelocity::typeId, state);\n    }\n\n    // Angular velocity in world frame coordinates\n    auto worldAngVelComp =\n        _ecm.Component<components::WorldAngularVelocity>(entity);\n    if (worldAngVelComp)\n    {\n      auto state = worldAngVelComp->SetData(\n          math::eigen3::convert(frameData.angularVelocity),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity,\n          components::WorldAngularVelocity::typeId, state);\n    }\n\n    // Acceleration in world frame coordinates\n    auto worldLinAccelComp =\n        _ecm.Component<components::WorldLinearAcceleration>(entity);\n    if (worldLinAccelComp)\n    {\n      auto state = worldLinAccelComp->SetData(\n          math::eigen3::convert(frameData.linearAcceleration),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity,\n          components::WorldLinearAcceleration::typeId, state);\n    }\n\n    // Angular acceleration in world frame coordinates\n    auto worldAngAccelComp =\n        _ecm.Component<components::WorldAngularAcceleration>(entity);\n\n    if (worldAngAccelComp)\n    {\n      auto state = worldAngAccelComp->SetData(\n          math::eigen3::convert(frameData.angularAcceleration),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity,\n          components::WorldAngularAcceleration::typeId, state);\n    }\n\n    const Eigen::Matrix3d R_bs = worldPose.linear().transpose(); // NOLINT\n\n    // Velocity in body-fixed frame coordinates\n    auto bodyLinVelComp =\n        _ecm.Component<components::LinearVelocity>(entity);\n    if (bodyLinVelComp)\n    {\n      Eigen::Vector3d bodyLinVel = R_bs * frameData.linearVelocity;\n      auto state =\n          bodyLinVelComp->SetData(math::eigen3::convert(bodyLinVel),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity, components::LinearVelocity::typeId, state);\n    }\n\n    // Angular velocity in body-fixed frame coordinates\n    auto bodyAngVelComp =\n        _ecm.Component<components::AngularVelocity>(entity);\n    if (bodyAngVelComp)\n    {\n      Eigen::Vector3d bodyAngVel = R_bs * frameData.angularVelocity;\n      auto state =\n          bodyAngVelComp->SetData(math::eigen3::convert(bodyAngVel),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity, components::AngularVelocity::typeId,\n          state);\n    }\n\n    // Acceleration in body-fixed frame coordinates\n    auto bodyLinAccelComp =\n        _ecm.Component<components::LinearAcceleration>(entity);\n    if (bodyLinAccelComp)\n    {\n      Eigen::Vector3d bodyLinAccel = R_bs * frameData.linearAcceleration;\n      auto state =\n          bodyLinAccelComp->SetData(math::eigen3::convert(bodyLinAccel),\n          this->vec3Eql)?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity, components::LinearAcceleration::typeId,\n          state);\n    }\n\n    // Angular acceleration in world frame coordinates\n    auto bodyAngAccelComp =\n        _ecm.Component<components::AngularAcceleration>(entity);\n    if (bodyAngAccelComp)\n    {\n      Eigen::Vector3d bodyAngAccel = R_bs * frameData.angularAcceleration;\n      auto state =\n          bodyAngAccelComp->SetData(math::eigen3::convert(bodyAngAccel),\n          this->vec3Eql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n      _ecm.SetChanged(entity, components::AngularAcceleration::typeId,\n          state);\n    }\n  }\n  IGN_PROFILE_END();\n\n  // history of applied joint forces (commands)\n  _ecm.Each<components::Joint,\n            components::JointForceCmd,\n            components::HistoryOfAppliedJointForces>(\n       [&](const Entity& /*_entity*/,\n           components::Joint* /*_joint*/,\n           components::JointForceCmd* _forceCmd,\n           components::HistoryOfAppliedJointForces* _history) -> bool\n  {\n      // Since the operation is an append, we have to perform it only when\n      // the physics step is actually performed\n      if (_info.paused)\n      {\n          return true;\n      }\n\n      // Get the history queue\n      auto& history = _history->Data();\n\n      // Get the data from the component\n      auto jointForceCmdData = _forceCmd->Data();\n\n      // Append values to the queue\n      for (const auto& jointForceCmd : jointForceCmdData)\n      {\n        history.push(jointForceCmd);\n      }\n\n      return true;\n  });\n\n  // pose/velocity/acceleration of non-link entities such as sensors /\n  // collisions. These get updated only if another system has created a\n  // components::WorldPose component for the entity.\n  // Populated components:\n  // * WorldPose\n  // * WorldLinearVelocity\n  // * AngularVelocity\n  // * LinearAcceleration\n\n  IGN_PROFILE_BEGIN(\"Sensors / collisions\");\n  // world pose\n  _ecm.Each<components::Pose, components::WorldPose,\n            components::ParentEntity>(\n      [&](const Entity &,\n          const components::Pose *_pose, components::WorldPose *_worldPose,\n          const components::ParentEntity *_parent)->bool\n      {\n        // check if parent entity is a link, e.g. entity is sensor / collision\n        if (auto linkPhys = this->entityLinkMap.Get(_parent->Data()))\n        {\n          const auto entityFrameData =\n              this->LinkFrameDataAtOffset(linkPhys, _pose->Data());\n\n          *_worldPose = components::WorldPose(\n              math::eigen3::convert(entityFrameData.pose));\n        }\n\n        return true;\n      });\n\n  // world linear velocity\n  _ecm.Each<components::Pose, components::WorldLinearVelocity,\n            components::ParentEntity>(\n      [&](const Entity &,\n          const components::Pose *_pose,\n          components::WorldLinearVelocity *_worldLinearVel,\n          const components::ParentEntity *_parent)->bool\n      {\n        // check if parent entity is a link, e.g. entity is sensor / collision\n        if (auto linkPhys = this->entityLinkMap.Get(_parent->Data()))\n        {\n          const auto entityFrameData =\n              this->LinkFrameDataAtOffset(linkPhys, _pose->Data());\n\n          // set entity world linear velocity\n          *_worldLinearVel = components::WorldLinearVelocity(\n              math::eigen3::convert(entityFrameData.linearVelocity));\n        }\n\n        return true;\n      });\n\n  // body angular velocity\n  _ecm.Each<components::Pose, components::AngularVelocity,\n            components::ParentEntity>(\n      [&](const Entity &,\n          const components::Pose *_pose,\n          components::AngularVelocity *_angularVel,\n          const components::ParentEntity *_parent)->bool\n      {\n        // check if parent entity is a link, e.g. entity is sensor / collision\n        if (auto linkPhys = this->entityLinkMap.Get(_parent->Data()))\n        {\n          const auto entityFrameData =\n              this->LinkFrameDataAtOffset(linkPhys, _pose->Data());\n\n          auto entityWorldPose = math::eigen3::convert(entityFrameData.pose);\n          ignition::math::Vector3d entityWorldAngularVel =\n              math::eigen3::convert(entityFrameData.angularVelocity);\n\n          auto entityBodyAngularVel =\n              entityWorldPose.Rot().RotateVectorReverse(entityWorldAngularVel);\n          *_angularVel = components::AngularVelocity(entityBodyAngularVel);\n        }\n\n        return true;\n      });\n\n  // body linear acceleration\n  _ecm.Each<components::Pose, components::LinearAcceleration,\n            components::ParentEntity>(\n      [&](const Entity &,\n          const components::Pose *_pose,\n          components::LinearAcceleration *_linearAcc,\n          const components::ParentEntity *_parent)->bool\n      {\n        if (auto linkPhys = this->entityLinkMap.Get(_parent->Data()))\n        {\n          const auto entityFrameData =\n              this->LinkFrameDataAtOffset(linkPhys, _pose->Data());\n\n          auto entityWorldPose = math::eigen3::convert(entityFrameData.pose);\n          ignition::math::Vector3d entityWorldLinearAcc =\n              math::eigen3::convert(entityFrameData.linearAcceleration);\n\n          auto entityBodyLinearAcc =\n              entityWorldPose.Rot().RotateVectorReverse(entityWorldLinearAcc);\n          *_linearAcc = components::LinearAcceleration(entityBodyLinearAcc);\n        }\n\n        return true;\n      });\n  IGN_PROFILE_END();\n\n  // Clear reset components\n  IGN_PROFILE_BEGIN(\"Clear / reset components\");\n  std::vector<Entity> entitiesPositionReset;\n  _ecm.Each<components::JointPositionReset>(\n      [&](const Entity &_entity, components::JointPositionReset *) -> bool\n      {\n        entitiesPositionReset.push_back(_entity);\n        return true;\n      });\n\n  for (const auto entity : entitiesPositionReset)\n  {\n    _ecm.RemoveComponent<components::JointPositionReset>(entity);\n  }\n\n  std::vector<Entity> entitiesVelocityReset;\n  _ecm.Each<components::JointVelocityReset>(\n      [&](const Entity &_entity, components::JointVelocityReset *) -> bool\n      {\n        entitiesVelocityReset.push_back(_entity);\n        return true;\n      });\n\n  for (const auto entity : entitiesVelocityReset)\n  {\n    _ecm.RemoveComponent<components::JointVelocityReset>(entity);\n  }\n\n  // Clear pending commands\n  _ecm.Each<components::JointForceCmd>(\n      [&](const Entity &, components::JointForceCmd *_force) -> bool\n      {\n        std::fill(_force->Data().begin(), _force->Data().end(), 0.0);\n        return true;\n      });\n\n  _ecm.Each<components::ExternalWorldWrenchCmd >(\n      [&](const Entity &, components::ExternalWorldWrenchCmd *_wrench) -> bool\n      {\n        _wrench->Data().Clear();\n        return true;\n      });\n\n  _ecm.Each<components::JointVelocityCmd>(\n      [&](const Entity &, components::JointVelocityCmd *_vel) -> bool\n      {\n        std::fill(_vel->Data().begin(), _vel->Data().end(), 0.0);\n        return true;\n      });\n\n  _ecm.Each<components::SlipComplianceCmd>(\n      [&](const Entity &, components::SlipComplianceCmd *_slip) -> bool\n      {\n        std::fill(_slip->Data().begin(), _slip->Data().end(), 0.0);\n        return true;\n      });\n  IGN_PROFILE_END();\n\n  _ecm.Each<components::AngularVelocityCmd>(\n      [&](const Entity &, components::AngularVelocityCmd *_vel) -> bool\n      {\n        _vel->Data() = math::Vector3d::Zero;\n        return true;\n      });\n\n  _ecm.Each<components::LinearVelocityCmd>(\n      [&](const Entity &, components::LinearVelocityCmd *_vel) -> bool\n      {\n        _vel->Data() = math::Vector3d::Zero;\n        return true;\n      });\n\n  // Update joint positions\n  IGN_PROFILE_BEGIN(\"Joints\");\n  _ecm.Each<components::Joint, components::JointPosition>(\n      [&](const Entity &_entity, components::Joint *,\n          components::JointPosition *_jointPos) -> bool\n      {\n        if (auto jointPhys = this->entityJointMap.Get(_entity))\n        {\n          _jointPos->Data().resize(jointPhys->GetDegreesOfFreedom());\n          for (std::size_t i = 0; i < jointPhys->GetDegreesOfFreedom();\n               ++i)\n          {\n            _jointPos->Data()[i] = jointPhys->GetPosition(i);\n          }\n          _ecm.SetChanged(_entity, components::JointPosition::typeId,\n              ComponentState::PeriodicChange);\n        }\n        return true;\n      });\n\n  // Update joint Velocities\n  _ecm.Each<components::Joint, components::JointVelocity>(\n      [&](const Entity &_entity, components::Joint *,\n          components::JointVelocity *_jointVel) -> bool\n      {\n        if (auto jointPhys = this->entityJointMap.Get(_entity))\n        {\n          _jointVel->Data().resize(jointPhys->GetDegreesOfFreedom());\n          for (std::size_t i = 0; i < jointPhys->GetDegreesOfFreedom();\n               ++i)\n          {\n            _jointVel->Data()[i] = jointPhys->GetVelocity(i);\n          }\n        }\n        return true;\n      });\n\n  // Update joint accelerations\n  _ecm.Each<components::Joint, components::JointAcceleration>(\n      [&](const Entity& _entity,\n          components::Joint*,\n          components::JointAcceleration* _jointAcc) -> bool\n  {\n    if (auto jointPhys = this->entityJointMap.Get(_entity))\n    {\n      _jointAcc->Data().resize(jointPhys->GetDegreesOfFreedom());\n      for (std::size_t i = 0; i < jointPhys->GetDegreesOfFreedom(); ++i)\n      {\n        _jointAcc->Data()[i] = jointPhys->GetAcceleration(i);\n      }\n    }\n    return true;\n  });\n\n  // Update joint forces\n  _ecm.Each<components::Joint, components::JointForce>(\n      [&](const Entity& _entity,\n          components::Joint*,\n          components::JointForce* _jointForce) -> bool\n  {\n    if (auto jointPhys = this->entityJointMap.Get(_entity))\n    {\n      _jointForce->Data().resize(jointPhys->GetDegreesOfFreedom());\n      for (std::size_t i = 0; i < jointPhys->GetDegreesOfFreedom(); ++i)\n      {\n          _jointForce->Data()[i] = jointPhys->GetForce(i);\n      }\n    }\n    return true;\n  });\n\n  IGN_PROFILE_END();\n\n  // Update joint transmitteds\n  _ecm.Each<components::Joint, components::JointTransmittedWrench>(\n      [&](const Entity &_entity, components::Joint *,\n          components::JointTransmittedWrench *_wrench) -> bool\n      {\n        auto jointPhys =\n            this->entityJointMap\n                .EntityCast<JointGetTransmittedWrenchFeatureList>(_entity);\n        if (jointPhys)\n        {\n          const auto &jointWrench = jointPhys->GetTransmittedWrench();\n\n          msgs::Wrench wrenchData;\n          msgs::Set(wrenchData.mutable_torque(),\n                    math::eigen3::convert(jointWrench.torque));\n          msgs::Set(wrenchData.mutable_force(),\n                    math::eigen3::convert(jointWrench.force));\n          const auto state =\n              _wrench->SetData(wrenchData, this->wrenchEql)\n                  ? ComponentState::PeriodicChange\n                  : ComponentState::NoChange;\n          _ecm.SetChanged(_entity, components::JointTransmittedWrench::typeId,\n                          state);\n        }\n        else\n        {\n          static bool informed{false};\n          if (!informed)\n          {\n            igndbg\n                << \"Attempting to get joint transmitted wrenches, but the \"\n                   \"physics engine doesn't support this feature. Values in the \"\n                   \"JointTransmittedWrench component will not be meaningful.\"\n                << std::endl;\n            informed = true;\n          }\n        }\n        return true;\n      });\n\n  // TODO(louise) Skip this if there are no collision features\n  this->UpdateCollisions(_ecm);\n}\n\n//////////////////////////////////////////////////\nvoid PhysicsPrivate::UpdateCollisions(EntityComponentManager &_ecm)\n{\n  IGN_PROFILE(\"PhysicsPrivate::UpdateCollisions\");\n  // Quit early if the ContactData component hasn't been created. This means\n  // there are no systems that need contact information\n  if (!_ecm.HasComponentType(components::ContactSensorData::typeId))\n    return;\n\n  // TODO(addisu) If systems are assumed to only have one world, we should\n  // capture the world Entity in a Configure call\n  Entity worldEntity = _ecm.EntityByComponents(components::World());\n\n  // Check if there is at least one collision that requires contact data.\n  // The previous check does not block the scenario where all the collisions\n  // start enabled and then get disabled.\n  bool hasContactSensorData = false;\n  _ecm.Each<components::ContactSensorData, components::Collision>(\n      [&](const Entity&,\n          components::ContactSensorData*,\n          components::Collision*) -> bool\n  {\n    hasContactSensorData = true;\n    return false;\n  });\n\n  // Quit early if the ContactData component was created and then removed.\n  // This means there are no systems that need contact information.\n  if (!hasContactSensorData)\n    return;\n\n  if (worldEntity == kNullEntity)\n  {\n    ignerr << \"Missing world entity.\\n\";\n    return;\n  }\n\n  if (!this->entityWorldMap.HasEntity(worldEntity))\n  {\n    ignwarn << \"Failed to find world [\" << worldEntity << \"].\" << std::endl;\n    return;\n  }\n\n  auto worldCollisionFeature =\n      this->entityWorldMap.EntityCast<CollisionFeatureList>(worldEntity);\n  if (!worldCollisionFeature)\n  {\n    static bool informed{false};\n    if (!informed)\n    {\n      igndbg << \"Attempting process contacts, but the physics \"\n             << \"engine doesn't support contact features. \"\n             << \"Contacts won't be computed.\"\n             << std::endl;\n      informed = true;\n    }\n    return;\n  }\n\n  // Struct containing pointer of contact data\n  struct AllContactData\n  {\n      const WorldShapeType::ContactPoint *point;\n      const WorldShapeType::ExtraContactData *extra;\n  };\n\n  // Each contact object we get from ign-physics contains the EntityPtrs of the\n  // two colliding entities and other data about the contact such as the\n  // position. This map groups contacts so that it is easy to query all the\n  // contacts of one entity.\n  using EntityContactMap = std::unordered_map<Entity,\n      std::deque<AllContactData>>;\n\n  // This data structure is essentially a mapping between a pair of entities and\n  // a list of pointers to their contact object. We use a map inside a map to\n  // create msgs::Contact objects conveniently later on.\n  std::unordered_map<Entity, EntityContactMap> entityContactMap;\n\n  // Note that we are temporarily storing pointers to elements in this\n  // (\"allContacts\") container. Thus, we must make sure it doesn't get destroyed\n  // until the end of this function.\n  auto allContacts = worldCollisionFeature->GetContactsFromLastStep();\n  for (const auto &contactComposite : allContacts)\n  {\n    // Get the RequireData\n    const auto &contact = contactComposite.Get<WorldShapeType::ContactPoint>();\n    auto coll1Entity =\n      this->entityCollisionMap.Get(ShapePtrType(contact.collision1));\n    auto coll2Entity =\n      this->entityCollisionMap.Get(ShapePtrType(contact.collision2));\n\n    // Check the ExpectData\n    const auto* extraContactData =\n        contactComposite.Query<WorldShapeType::ExtraContactData>();\n\n    if (coll1Entity != kNullEntity && coll2Entity != kNullEntity)\n    {\n      AllContactData allContactData;\n      allContactData.point = &contact;\n\n      if (extraContactData)\n        allContactData.extra = extraContactData;\n\n      // Note that the ExtraContactData is valid only when the first\n      // collision is the first body. Quantities like the force and\n      // the normal must be flipped in the second case.\n      entityContactMap[coll1Entity][coll2Entity].push_back(\n        allContactData);\n      entityContactMap[coll2Entity][coll1Entity].push_back(\n        allContactData);\n    }\n  }\n\n  // Go through each collision entity that has a ContactData component and\n  // set the component value to the list of contacts that correspond to\n  // the collision entity\n  _ecm.Each<components::Collision, components::ContactSensorData>(\n      [&](const Entity &_collEntity1, components::Collision *,\n          components::ContactSensorData *_contacts) -> bool\n      {\n        msgs::Contacts contactsComp;\n        if (entityContactMap.find(_collEntity1) == entityContactMap.end())\n        {\n          // Clear the last contact data\n          auto state = _contacts->SetData(contactsComp,\n            this->contactsEql) ?\n            ComponentState::PeriodicChange :\n            ComponentState::NoChange;\n          _ecm.SetChanged(\n            _collEntity1, components::ContactSensorData::typeId, state);\n          return true;\n        }\n\n        const auto &contactMap = entityContactMap[_collEntity1];\n\n        for (const auto &[collEntity2, contactData] : contactMap)\n        {\n          msgs::Contact *contactMsg = contactsComp.add_contact();\n          contactMsg->mutable_collision1()->set_id(_collEntity1);\n          contactMsg->mutable_collision2()->set_id(collEntity2);\n\n          for (const auto &contact : contactData)\n          {\n            auto *position = contactMsg->add_position();\n            position->set_x(contact.point->point.x());\n            position->set_y(contact.point->point.y());\n            position->set_z(contact.point->point.z());\n\n            if (contact.extra)\n            {\n              // Add the penetration depth\n              contactMsg->add_depth(contact.extra->depth);\n\n              // Get the name of the collisions\n              auto collisionName1 =\n                  _ecm.Component<components::Name>(_collEntity1)->Data();\n              auto collisionName2 =\n                  _ecm.Component<components::Name>(collEntity2)->Data();\n\n              // Add the wrench (only the force component)\n              auto* wrench = contactMsg->add_wrench();\n              wrench->set_body_1_name(collisionName1);\n              wrench->set_body_2_name(collisionName2);\n              auto* wrench1 = wrench->mutable_body_1_wrench();\n              auto* wrench2 = wrench->mutable_body_2_wrench();\n\n              auto* force1 = wrench1->mutable_force();\n              auto* force2 = wrench2->mutable_force();\n              auto* torque1 = wrench1->mutable_torque();\n              auto* torque2 = wrench2->mutable_torque();\n\n              // The same ContactPoint and ExtraContactData are\n              // used for the contact between collision1 and\n              // collision2. In those structures there is some\n              // data, like the force and normal, that cannot\n              // commute.\n              if (_collEntity1 == this->entityCollisionMap.Get(\n                      ShapePtrType(contact.point->collision1)))\n              {\n                assert(collEntity2 == this->entityCollisionMap.Get(\n                        ShapePtrType(contact.point->collision2)));\n                // Use the data as it is\n                *force1 = msgs::Convert(math::eigen3::convert(contact.extra->force));\n                *force2 = msgs::Convert(-math::eigen3::convert(contact.extra->force));\n                // Add the wrench normal\n                auto* normal = contactMsg->add_normal();\n                normal->set_x(contact.extra->normal.x());\n                normal->set_y(contact.extra->normal.y());\n                normal->set_z(contact.extra->normal.z());\n              }\n              else\n              {\n                assert(collEntity2 == this->entityCollisionMap.Get(\n                        ShapePtrType(contact.point->collision1)));\n                // Flip the force\n                *force1 = msgs::Convert(-math::eigen3::convert(contact.extra->force));\n                *force2 = msgs::Convert(math::eigen3::convert(contact.extra->force));\n                // Flip the normal\n                auto* normal = contactMsg->add_normal();\n                normal->set_x(-contact.extra->normal.x());\n                normal->set_y(-contact.extra->normal.y());\n                normal->set_z(-contact.extra->normal.z());\n              }\n\n              *torque1 = msgs::Convert(math::Vector3d::Zero);\n              *torque2 = msgs::Convert(math::Vector3d::Zero);\n            }\n          }\n        }\n\n        auto state = _contacts->SetData(contactsComp,\n          this->contactsEql) ?\n          ComponentState::PeriodicChange :\n          ComponentState::NoChange;\n        _ecm.SetChanged(\n          _collEntity1, components::ContactSensorData::typeId, state);\n\n        return true;\n      });\n}\n\nphysics::FrameData3d PhysicsPrivate::LinkFrameDataAtOffset(\n      const LinkPtrType &_link, const math::Pose3d &_pose) const\n{\n  physics::FrameData3d parent;\n  parent.pose = math::eigen3::convert(_pose);\n  physics::RelativeFrameData3d relFrameData(_link->GetFrameID(), parent);\n  return this->engine->Resolve(relFrameData, physics::FrameID::World());\n}\n\nIGNITION_ADD_PLUGIN(Physics,\n                    ignition::gazebo::System,\n                    Physics::ISystemConfigure,\n                    Physics::ISystemUpdate)\n\nIGNITION_ADD_PLUGIN_ALIAS(Physics, \"ignition::gazebo::systems::Physics\")\nIGNITION_ADD_PLUGIN_ALIAS(Physics, \"scenario::plugins::gazebo::Physics\")\n"
  },
  {
    "path": "scenario/src/plugins/Physics/Physics.hh",
    "content": "/*\n * Copyright (C) 2018 Open Source Robotics Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n#ifndef IGNITION_GAZEBO_SYSTEMS_PHYSICS_HH_\n#define IGNITION_GAZEBO_SYSTEMS_PHYSICS_HH_\n\n// clang-format off\n#include <memory>\n#include <unordered_map>\n#include <utility>\n#include <ignition/physics/FindFeatures.hh>\n#include <ignition/physics/RequestFeatures.hh>\n\n// Features need to be defined ahead of entityCast\n#include <ignition/physics/BoxShape.hh>\n#include <ignition/physics/CapsuleShape.hh>\n#include <ignition/physics/CylinderShape.hh>\n#include <ignition/physics/EllipsoidShape.hh>\n#include <ignition/physics/ForwardStep.hh>\n#include <ignition/physics/FrameSemantics.hh>\n#include <ignition/physics/FreeGroup.hh>\n#include <ignition/physics/FixedJoint.hh>\n#include <ignition/physics/GetContacts.hh>\n#include <ignition/physics/GetBoundingBox.hh>\n#include <ignition/physics/Joint.hh>\n#include <ignition/physics/Link.hh>\n#include <ignition/physics/RemoveEntities.hh>\n#include <ignition/physics/Shape.hh>\n#include <ignition/physics/SphereShape.hh>\n#include <ignition/physics/World.hh>\n#include <ignition/physics/mesh/MeshShape.hh>\n#include <ignition/physics/sdf/ConstructCollision.hh>\n#include <ignition/physics/sdf/ConstructJoint.hh>\n#include <ignition/physics/sdf/ConstructLink.hh>\n#include <ignition/physics/sdf/ConstructModel.hh>\n#include <ignition/physics/sdf/ConstructNestedModel.hh>\n#include <ignition/physics/sdf/ConstructWorld.hh>\n\n#include <ignition/gazebo/config.hh>\n#include <ignition/gazebo/System.hh>\n\nnamespace ignition\n{\nnamespace gazebo\n{\n// Inline bracket to help doxygen filtering.\ninline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {\nnamespace systems\n{\n  // Forward declarations.\n  class PhysicsPrivate;\n\n  /// \\class Physics Physics.hh ignition/gazebo/systems/Physics.hh\n  /// \\brief Base class for a System.\n  class Physics:\n    public System,\n    public ISystemConfigure,\n    public ISystemUpdate\n  {\n    /// \\brief Constructor\n    public: explicit Physics();\n\n    /// \\brief Destructor\n    public: ~Physics() override;\n\n    // Documentation inherited\n    public: void Configure(const Entity &_entity,\n                           const std::shared_ptr<const sdf::Element> &_sdf,\n                           EntityComponentManager &_ecm,\n                           EventManager &_eventMgr) final;\n\n    /// Documentation inherited\n    public: void Update(const UpdateInfo &_info,\n                EntityComponentManager &_ecm) final;\n\n    /// \\brief Private data pointer.\n    private: std::unique_ptr<PhysicsPrivate> dataPtr;\n  };\n}\n}\n}\n}\n#endif\n"
  },
  {
    "path": "setup.cfg",
    "content": "# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\n[metadata]\nname = gym_ignition\ndescription = A toolkit for developing OpenAI Gym environments simulated with Ignition Gazebo.\nlong_description = file: README.md\nlong_description_content_type = text/markdown\nauthor = Diego Ferigo\nauthor_email = dgferigo@gmail.com\nlicense = LGPL\nlicense_file = LICENSE\nplatforms = any\nurl = https://github.com/robotology/gym-ignition\n\nproject_urls =\n    Changelog = https://github.com/robotology/gym-ignition/releases\n    Tracker = https://github.com/robotology/gym-ignition/issues\n    Documentation = https://robotology.github.io/gym-ignition\n    Source = https://github.com/robotology/gym-ignition\n\nkeywords =\n    openai\n    gym\n    reinforcement learning\n    rl\n    environment\n    gazebo\n    robotics\n    ignition\n    humanoid\n    panda\n    icub\n    urdf\n    sdf\n\nclassifiers =\n    Development Status :: 5 - Production/Stable\n    Operating System :: POSIX :: Linux\n    Topic :: Games/Entertainment :: Simulation\n    Topic :: Scientific/Engineering :: Artificial Intelligence\n    Topic :: Scientific/Engineering :: Physics\n    Topic :: Software Development\n    Framework :: Robot Framework\n    Intended Audience :: Developers\n    Intended Audience :: Science/Research\n    Programming Language :: Python :: 3.8\n    Programming Language :: Python :: 3.9\n    Programming Language :: Python :: 3 :: Only\n    Programming Language :: Python :: Implementation :: CPython\n    License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)\n\n[options]\nzip_safe = False\npackages = find:\npackage_dir =\n    =python\npython_requires = >=3.8\ninstall_requires =\n    scenario >= 1.3.2.dev\n    gym >= 0.13.1\n    numpy\n    scipy\n    gym_ignition_models\n    lxml\n    idyntree\n\n[options.packages.find]\nwhere = python\n\n[options.extras_require]\ntesting =\n    pytest\n    pytest-xvfb\n    pytest-icdiff\nwebsite =\n    sphinx\n    sphinx-book-theme\n    sphinx-autodoc-typehints\n    sphinx_fontawesome\n    sphinx-multiversion\n    sphinx-tabs\n    breathe\nall =\n    %(testing)s\n    %(website)s\n\n[tool:pytest]\naddopts = -rsxX -v --strict-markers\ntestpaths = tests\nmarkers =\n    scenario: Select the tests in the 'tests/test_scenario/' folder.\n    gym_ignition: Select the tests in the 'tests/test_gym_ignition/' folder.\n"
  },
  {
    "path": "setup.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport setuptools\n\nsetuptools.setup()\n"
  },
  {
    "path": "tests/.python/__init__.py",
    "content": ""
  },
  {
    "path": "tests/.python/test_contacts.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport tempfile\n\nimport numpy as np\n\nfrom . import utils\n\n\ndef test_contacts():\n    # Get the simulator\n    gazebo = utils.Gazebo(physics_rate=1000, iterations=1, rtf=100)\n\n    # Create the first cube and insert it in the simulation\n    cube1 = utils.CubeGazeboRobot(\n        gazebo=gazebo.simulator, initial_position=np.array([0, 0, 1.0])\n    )\n\n    # Create the second cube and insert it in the simulation\n    cube2 = utils.CubeGazeboRobot(\n        gazebo=gazebo.simulator, initial_position=np.array([0, 0, 2.5])\n    )\n\n    # Execute the first simulation step\n    gazebo.step()\n\n    # The cubes should be falling without contacts\n    assert len(cube1.links_in_contact()) == 0\n    assert len(cube2.links_in_contact()) == 0\n\n    # Perform 500 steps.\n    for _ in range(500):\n        gazebo.step()\n\n    # Cube1 should be touching ground\n    assert len(cube1.links_in_contact()) == 1\n    assert cube1.links_in_contact()[0] == \"cube\"\n    contact_data1 = cube1.contact_data(\"cube\")\n    assert len(contact_data1) > 0\n    assert contact_data1[0].bodyA == cube1.name() + \"::cube_collision\"\n    assert contact_data1[0].bodyB == \"ground_plane::collision\"\n\n    # Cube 2 should be still floating\n    assert len(cube2.links_in_contact()) == 0\n    assert len(cube2.contact_data(\"cube\")) == 0\n\n    # Perform 500 steps.\n    for _ in range(500):\n        gazebo.step()\n\n    # Now cube2 should be in contact with cube1\n    assert len(cube2.links_in_contact()) == 1\n    assert cube2.links_in_contact()[0] == \"cube\"\n    contact_data2 = cube2.contact_data(\"cube\")\n    assert len(contact_data2) > 0\n    assert contact_data2[0].bodyA == cube2.name() + \"::cube_collision\"\n    assert contact_data2[0].bodyB == cube1.name() + \"::cube_collision\"\n\n    # And cube1 should be in contact with cube2 and ground_plane\n    assert len(cube1.links_in_contact()) == 1\n    assert cube1.links_in_contact()[0] == \"cube\"\n    contact_data1 = cube1.contact_data(\"cube\")\n    assert len(contact_data1) == 2\n\n    for contact in contact_data1:\n        assert contact.bodyA == cube1.name() + \"::cube_collision\"\n        assert (\n            contact.bodyB == cube2.name() + \"::cube_collision\"\n            or contact.bodyB == \"ground_plane::collision\"\n        )\n"
  },
  {
    "path": "tests/.python/test_environments_gazebowrapper.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport gym\nimport pytest\nfrom gym_ignition.utils import logger\n\n# Set verbosity\nlogger.set_level(gym.logger.DEBUG)\n\n\ndef template_run_environment(env_name):\n    logger.info(f\"Testing environment '{env_name}'\")\n    env = gym.make(env_name)\n    assert env, f\"Failed to create '{env_name}' environment\"\n\n    observation = env.observation_space.sample()\n    assert observation.size > 0, \"The sampled observation is empty\"\n\n    observation = env.reset()\n    assert observation.size > 0, \"The observation is empty\"\n\n    for _ in range(10):\n        action = env.action_space.sample()\n        state, reward, done, _ = env.step(action)\n        assert state.size > 0, \"The environment didn't return a valid state\"\n\n    env.close()\n\n\n@pytest.mark.parametrize(\n    \"env_name\",\n    [\n        \"CartPoleDiscrete-Gazebo-v0\",\n        \"CartPoleContinuous-Gazebo-v0\",\n        \"Pendulum-Gazebo-v0\",\n    ],\n)\ndef test_environment(env_name: str):\n    template_run_environment(env_name)\n"
  },
  {
    "path": "tests/.python/test_externalforce.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport tempfile\n\nimport numpy as np\n\nfrom . import utils\n\n\ndef test_external_force():\n    # Get the simulator\n    gazebo = utils.Gazebo(physics_rate=1000, iterations=1, rtf=100)\n\n    # Create the first cube and insert it in the simulation\n    cube = utils.CubeGazeboRobot(\n        gazebo=gazebo.simulator, initial_position=np.array([0, 0, 1.0])\n    )\n\n    # Execute the first simulation step\n    gazebo.step()\n\n    # Get the position of the cube\n    position, _ = cube.base_pose()\n    assert position[0] == 0.0\n    assert position[1] == 0.0\n\n    # Apply a force for 1 second\n    num_steps = 100\n    f_x = 50.0\n    f_y = -f_x / 10\n\n    for _ in range(num_steps):\n        ok_w = cube.apply_external_force(\n            \"cube\", np.array([f_x, f_y, 0]), np.array([0.0, 0, 0])\n        )\n        assert ok_w\n\n        # Step the simulation\n        gazebo.step()\n\n    # Get the position of the cube\n    position, _ = cube.base_pose()\n    print(position)\n    assert position[0] > 0.0\n    assert position[1] < 0.0\n    assert np.allclose(-position[0], 10 * position[1])\n"
  },
  {
    "path": "tests/.python/test_joint_force.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom gym_ignition.base.robot.robot_joints import JointControlMode\n\nfrom . import utils\n\n\ndef test_joint_force():\n    # Get the simulator\n    gazebo = utils.Gazebo(physics_rate=1000, iterations=1)\n\n    # Insert the robot\n    pendulum = utils.get_pendulum(simulator=gazebo)\n\n    # Configure the robot\n    ok_mode = pendulum.set_joint_control_mode(\"pivot\", JointControlMode.TORQUE)\n    assert ok_mode\n\n    # Step the simulator\n    gazebo.step()\n\n    # No references set\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Step the simulator\n    gazebo.step()\n\n    # Set a reference. No force reference yet applied.\n    torque = 42.42\n    pendulum.set_joint_force(\"pivot\", torque)\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Step the simulator. Now the force reference should have been actuated and after\n    # the physics step it should be returned by the method.\n    gazebo.step()\n    assert pendulum.joint_force(\"pivot\") == torque\n\n    # Step again the simulator. No force reference has been specified and the method\n    # should return zero.\n    gazebo.step()\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Close the simulator\n    gazebo.close()\n\n\ndef test_joint_force_multiple_iterations():\n    # Get the simulator\n    gazebo = utils.Gazebo(physics_rate=1000, iterations=2)\n\n    # Insert the robot\n    pendulum = utils.get_pendulum(simulator=gazebo)\n    pendulum.set_joint_control_mode(\"pivot\", JointControlMode.TORQUE)\n\n    # Step the simulator\n    gazebo.step()\n\n    # No references set\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Step the simulator\n    gazebo.step()\n\n    # Set a reference. No force reference yet applied.\n    torque = 42.42\n    pendulum.set_joint_force(\"pivot\", torque)\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Step the simulator.\n    # Note that since gazebo was configured with multiple iterations,\n    # the force is applied only in the first one and we still read zero!\n    gazebo.step()\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Step again the simulator\n    gazebo.step()\n    assert pendulum.joint_force(\"pivot\") == 0.0\n\n    # Close the simulator\n    gazebo.close()\n"
  },
  {
    "path": "tests/.python/test_pendulum_wrt_ground_truth.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport gym\nimport numpy as np\nimport pytest\nfrom gym.envs import registry\nfrom gym.envs.registration import register\nfrom gym_ignition.robots.sim import gazebo, pybullet\nfrom gym_ignition.tasks.pendulum_swingup import PendulumSwingUp\nfrom gym_ignition.utils import logger\nfrom gym_ignition.utils.typing import Observation, Reward, State\n\n# Set verbosity\nlogger.set_level(gym.logger.DEBUG)\n\n\nclass PendulumEnv(gym.Env):\n    \"\"\"\n    Environment that implements the pendulum dynamics from equations.\n    It integrates the system with Euler.\n    \"\"\"\n\n    metadata = {\"render.modes\": []}\n\n    def __init__(self):\n        super().__init__()\n\n        # Check the xacro pendulum model\n        r = 0.01\n        self.L = 0.5\n        self.m = 1\n        self.g = 9.8182\n        self.I = self.m * (4 * self.L * self.L + 3 * r * r) / 12\n\n        self.dt = None\n        # self.force = None\n        self.theta = None\n        self.theta_dot = None\n\n    def set_state_from_obs(self, observation: np.ndarray) -> None:\n        \"\"\"\n        Set the state of the environment from an observation sampled from another\n        environment.\n        \"\"\"\n\n        # Unpack the observation\n        cos_theta, sin_theta, self.theta_dot = observation.tolist()\n\n        # Calculate the initial angle\n        self.theta = np.math.atan2(sin_theta, cos_theta)\n\n    def step(self, action: np.ndarray) -> State:\n        tau_m = action[0]\n        theta_ddot = (\n            self.m * self.g * self.L / 2.0 * np.sin(self.theta) + tau_m\n        ) / self.I\n\n        # Integrate with euler.\n        # Note that in this way the ground truth used as comparison implements a very\n        # basic integration method, and the errors might be reduced implementing a\n        # better integrator.\n        self.theta_dot = self.theta_dot + theta_ddot * self.dt\n        self.theta = self.theta + self.theta_dot * self.dt\n\n        observation = np.array([np.cos(self.theta), np.sin(self.theta), self.theta_dot])\n\n        return State((Observation(observation), Reward(0.0), False, {}))\n\n    def reset(self):\n        # Use set_state_from_obs\n        pass\n\n    def render(self, mode=\"human\", **kwargs):\n        raise Exception(\"This runtime does not support rendering\")\n\n    def seed(self, seed=None):\n        raise Exception(\"This runtime should not be seeded\")\n\n\ndef theta_from_obs(observation: np.ndarray) -> float:\n    cos_theta, sin_theta, _ = observation\n    return np.math.atan2(sin_theta, cos_theta)\n\n\nif \"Pendulum-Ignition-PyTest-v0\" not in [spec.id for spec in list(registry.all())]:\n    register(\n        id=\"Pendulum-Ignition-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n        max_episode_steps=1000,\n        kwargs={\n            \"task_cls\": PendulumSwingUp,\n            \"robot_cls\": gazebo.pendulum.PendulumGazeboRobot,\n            \"model\": \"Pendulum/Pendulum.urdf\",\n            \"world\": \"DefaultEmptyWorld.world\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,\n            \"hard_reset\": False,\n        },\n    )\n\nif \"Pendulum-PyBullet-PyTest-v0\" not in [spec.id for spec in list(registry.all())]:\n    register(\n        id=\"Pendulum-PyBullet-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.pybullet_runtime:PyBulletRuntime\",\n        max_episode_steps=1000,\n        kwargs={\n            \"task_cls\": PendulumSwingUp,\n            \"robot_cls\": pybullet.pendulum.PendulumPyBulletRobot,\n            \"model\": \"Pendulum/Pendulum.urdf\",\n            \"world\": \"plane_implicit.urdf\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,  # To keep errors small, pybullet needs higher rate\n            \"hard_reset\": False,\n        },\n    )\n\n\ndef template_pendulum_wrt_ground_truth(env_name: str, max_error_in_deg: float):\n    # Create the pendulum\n    env = gym.make(env_name)\n\n    # Create the environment with the equations and initialize its time step\n    env_equation = PendulumEnv()\n    env_equation.dt = 1.0 / env.unwrapped.spec._kwargs[\"agent_rate\"]\n\n    # Render the environment\n    # env.render('human')\n    # time.sleep(5)\n\n    # Seed the environment\n    env.seed(42)\n\n    for epoch in range(10):\n        # Reset the environment\n        logger.info(\"Resetting the environment\")\n        observation = env.reset()\n        env_equation.set_state_from_obs(observation)\n\n        # Initialize intermediate variables\n        iteration = 0\n        done = False\n\n        while not done:\n            iteration += 1\n\n            # Sample a random action from the environment\n            action = env.action_space.sample()\n\n            # Step the environments\n            observation, _, done, _ = env.step(action)\n            observation_equation, _, _, _ = env_equation.step(action)\n\n            theta = np.rad2deg(theta_from_obs(observation))\n            theta_equation = np.rad2deg(theta_from_obs(observation_equation))\n\n            # Compute the error taking care of the change of sign\n            if np.sign(theta_equation) * np.sign(theta) == -1:\n                error = (180 % abs(theta)) + (180 % abs(theta_equation))\n            else:\n                error = abs(theta - theta_equation)\n\n            print(iteration, error)\n\n            if error > max_error_in_deg:\n                print(\"===================\")\n                print(f\"Environment name: {env_name}\")\n                print(f\"Iteration: #{iteration}\")\n                print(f\"Error: {error}\")\n                print(f\"Theta Equation    (deg): {theta_equation}\")\n                print(f\"Theta Environment (deg): {theta}\")\n                print(\"===================\")\n                assert False, \"Error in pendulum angle is bigger then the threshold\"\n\n    env.close()\n\n\n@pytest.mark.parametrize(\n    \"env_name, max_error_in_deg\",\n    [\n        (\"Pendulum-Ignition-PyTest-v0\", 3.0),\n        (\"Pendulum-PyBullet-PyTest-v0\", 3.0),\n    ],\n)\ndef test_pendulum_ignition(env_name: str, max_error_in_deg: float):\n    template_pendulum_wrt_ground_truth(env_name, max_error_in_deg)\n"
  },
  {
    "path": "tests/.python/test_rates.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport itertools\nimport time\nfrom typing import List, Tuple\n\nimport numpy as np\nimport pytest\nfrom gym_ignition.base.robot.robot_joints import JointControlMode\nfrom gym_ignition.utils import logger\n\nfrom . import utils\n\n\ndef almost_equal(first, second, epsilon=None) -> bool:\n    if not epsilon:\n        epsilon = first * 0.05\n\n    res = np.abs(first - second) <= epsilon\n\n    if not res:\n        print(\"----------------\")\n        print(\"ASSERTION FAILED\")\n        print(\"----------------\")\n        print(f\"#1={first}\")\n        print(f\"#2={second}\")\n        print(\"Error={}\".format(np.abs(first - second)))\n        print(f\"Tolerance={epsilon}\")\n        print(\"----------------\")\n\n    return res\n\n\ndef template_test(\n    rtf: float,\n    physics_rate: float,\n    agent_rate: float,\n) -> None:\n\n    # Get the simulator\n    iterations = int(physics_rate / agent_rate)\n    gazebo = utils.Gazebo(physics_rate=physics_rate, iterations=iterations, rtf=rtf)\n\n    # Get the cartpole robot\n    robot = utils.get_cartpole(gazebo)\n    assert robot.valid(), \"The robot object is not valid\"\n\n    # Configure the cartpole\n    ok_cm = robot.set_joint_control_mode(\"linear\", JointControlMode.POSITION)\n    assert ok_cm, \"Failed to set the control mode\"\n\n    # Set the joint controller period\n    robot.set_dt(0.001 if physics_rate < 1000 else physics_rate)\n\n    # Trajectory specifications\n    trajectory_dt = 1 / agent_rate\n    tot_simulated_seconds = 2\n\n    # Generate the cart trajectory. This is analogous of setting an action containing\n    # the cart references, hence it is related to the agent rate.\n    cart_ref = np.fromiter(\n        (\n            0.2 * np.sin(2 * np.pi * 0.5 * t)\n            for t in np.arange(0, tot_simulated_seconds, trajectory_dt)\n        ),\n        dtype=np.float,\n    )\n\n    avg_time_per_step = 0.0\n    start = time.time()\n\n    logger.debug(f\"Simulating {cart_ref.size} steps\")\n    for i, ref in enumerate(cart_ref):\n        # Set the references\n        ok_ref = robot.set_joint_position(\"linear\", ref)\n        assert ok_ref, \"Failed to set joint references\"\n\n        # Step the simulator\n        now = time.time()\n        gazebo.step()\n        this_step = time.time() - now\n        avg_time_per_step = avg_time_per_step + 0.1 * (this_step - avg_time_per_step)\n\n    stop = time.time()\n    elapsed_time = stop - start\n\n    # Compute useful quantities\n    number_of_actions = tot_simulated_seconds / trajectory_dt\n    physics_iterations_per_run = physics_rate / agent_rate\n    simulation_dt = 1 / (physics_rate * rtf)\n\n    assert number_of_actions == cart_ref.size\n\n    print()\n    print(f\"Elapsed time = {elapsed_time}\")\n    print(f\"Average step time = {avg_time_per_step}\")\n    print(\"Number of actions: = {}\".format(tot_simulated_seconds / trajectory_dt))\n    print(f\"Physics iteration per simulator step = {physics_iterations_per_run}\")\n    print()\n\n    # Check if the average time per step matches what expected\n    assert almost_equal(\n        first=avg_time_per_step,\n        second=simulation_dt * physics_iterations_per_run,\n        epsilon=avg_time_per_step * 0.5,\n    )\n\n    # Check if the total time of the simulation matched what expected\n    assert almost_equal(\n        first=elapsed_time,\n        second=number_of_actions * simulation_dt * physics_iterations_per_run,\n        epsilon=elapsed_time * 0.5,\n    )\n\n    # Terminate simulation\n    gazebo.close()\n\n\ndef create_test_matrix() -> List[Tuple[float, float, float]]:\n    rtf_list = [0.5, 1, 2, 5, 10]\n    agent_rate_list = [100, 500, 1000]\n    physics_rate_list = [100, 500, 1000]\n\n    matrix = list()\n\n    for agent_rate in agent_rate_list:\n        # Compute all the combinations of simulation rate and physics rate\n        combinations = list(itertools.product(rtf_list, physics_rate_list))\n\n        for rtf, physics_rate in combinations:\n            # Remove some combination too demanding for a single process\n            if physics_rate * rtf >= 2000:\n                continue\n\n            # This case is not allowed\n            if agent_rate > physics_rate:\n                continue\n\n            matrix.append((rtf, agent_rate, physics_rate))\n\n    print(matrix)\n    return matrix\n\n\n@pytest.mark.parametrize(\"rtf, agent_rate, physics_rate\", create_test_matrix())\ndef test_rates(rtf: float, agent_rate: float, physics_rate: float):\n\n    print(\"========\")\n    print(\"Testing:\")\n    print(\"========\")\n    print(f\"RTF = {rtf}\")\n    print(f\"Agent rate = {agent_rate}\")\n    print(f\"Physics rate = {physics_rate}\")\n\n    template_test(rtf, physics_rate, agent_rate)\n"
  },
  {
    "path": "tests/.python/test_robot_base.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport numpy as np\nimport pytest\n\nfrom . import utils\n\n\n@pytest.mark.parametrize(\"simulator_name\", [\"gazebo\", \"pybullet\"])\ndef test_robot_fixed_base(simulator_name: str):\n\n    if simulator_name == \"gazebo\":\n        simulator = utils.Gazebo(physics_rate=1000)\n    elif simulator_name == \"pybullet\":\n        simulator = utils.PyBullet(physics_rate=1000)\n    else:\n        raise ValueError(simulator_name)\n\n    # Get the pendulum robot and specify its base position\n    base_position = np.array([-3, 3, 2])\n    robot = utils.get_pendulum(simulator=simulator, base_position=base_position)\n\n    # Robot should not fall due to gravity\n    for _ in range(100):\n        simulator.step()\n\n    assert np.allclose(robot.base_pose()[0], base_position, atol=1e-3)\n    assert np.allclose(robot.base_pose()[1], np.array([1.0, 0, 0, 0]), atol=1e-3)\n\n\n# @pytest.mark.parametrize(\"simulator_name\", [\"gazebo\", \"pybullet\"])\n# def test_robot_floating_base(simulator_name: str):\n#\n#     if simulator_name == \"gazebo\":\n#         simulator = utils.Gazebo(physics_rate=1000)\n#     elif simulator_name == \"pybullet\":\n#         simulator = utils.PyBullet(physics_rate=1000)\n#     else:\n#         raise ValueError(simulator_name)\n#\n#     # Get the pendulum robot and specify its base position\n#     base_position = np.array([-3, 3, 2])\n#     robot = utils.get_pendulum(simulator=simulator, base_position=base_position)\n#\n#     assert np.allclose(robot.base_pose()[0], base_position, atol=1e-3)\n#     assert np.allclose(robot.base_pose()[1], np.array([1.0, 0, 0, 0]), atol=1e-3)\n#\n#     old_pos_z = base_position[2]\n#\n#     # Robot will fall due to gravity\n#     for _ in range(100):\n#         simulator.step()\n#         current_pos_z = robot.base_pose()[0][2]\n#         assert current_pos_z < old_pos_z\n#         old_pos_z = current_pos_z\n\n\n@pytest.mark.parametrize(\"simulator_name\", [\"pybullet\"])\ndef test_robot_floating_to_fixed(simulator_name: str):\n\n    if simulator_name == \"gazebo\":\n        simulator = utils.Gazebo(physics_rate=1000)\n    elif simulator_name == \"pybullet\":\n        simulator = utils.PyBullet(physics_rate=1000)\n    else:\n        raise ValueError(simulator_name)\n\n    # Get the pendulum robot and specify its base position\n    base_position = np.array([-3, 3, 2])\n    robot = utils.get_pendulum(simulator=simulator, base_position=base_position)\n\n    # Let's make the robot fall a little\n    for _ in range(10):\n        simulator.step()\n\n    current_base_position, current_base_orientation = robot.base_pose()\n    assert current_base_position[2] < base_position[2]\n\n    ok_fixed_base = robot.set_as_floating_base(False)\n    assert ok_fixed_base, \"Failed to set the robot as fixed base\"\n\n    ok_reset_base_pose = robot.reset_base_pose(\n        current_base_position, current_base_orientation\n    )\n    assert ok_reset_base_pose, \"Failed to reset the base pose\"\n\n    # Robot should now not fall due to gravity\n    for _ in range(100):\n        simulator.step()\n\n    assert np.allclose(robot.base_pose()[0], current_base_position, atol=1e-3)\n    assert np.allclose(robot.base_pose()[1], current_base_orientation, atol=1e-3)\n"
  },
  {
    "path": "tests/.python/test_robot_controller.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport gym\nimport numpy as np\nfrom gym_ignition import gympp_bindings as bindings\nfrom gym_ignition.utils import logger, resource_finder\n\n\ndef test_joint_controller():\n    # ==========\n    # PARAMETERS\n    # ==========\n\n    agent_rate = 100.0\n    physics_rate = 1000.0\n    controller_rate = 500.0\n\n    plugin_data = bindings.PluginData()\n    plugin_data.libName = \"RobotController\"\n    plugin_data.className = \"scenario::plugins::gazebo::RobotController\"\n\n    # Find and load the model SDF file\n    model_sdf_file = resource_finder.find_resource(\"CartPole/CartPole.urdf\")\n    with open(model_sdf_file, \"r\") as stream:\n        model_sdf_string = stream.read()\n\n    # Initialize the model data\n    model_data = bindings.ModelInitData()\n    model_data.sdfString = model_sdf_string\n\n    # Get the model name\n    model_name = bindings.GazeboSimulator.getModelNameFromSDF(model_sdf_string)\n    robot_name = model_name\n\n    # =============\n    # CONFIGURATION\n    # =============\n\n    # Create the gazebo wrapper\n    num_of_iterations = int(physics_rate / agent_rate)\n    desired_rtf = float(np.finfo(np.float32).max)\n    gazebo = bindings.GazeboSimulator(num_of_iterations, desired_rtf, physics_rate)\n    assert gazebo, \"Failed to get the gazebo wrapper\"\n\n    # Set the verbosity\n    logger.set_level(gym.logger.DEBUG)\n\n    # Initialize the world\n    world_ok = gazebo.setupGazeboWorld(\"DefaultEmptyWorld.world\")\n    assert world_ok, \"Failed to initialize the gazebo world\"\n\n    # Initialize the ignition gazebo wrapper (creates a paused simulation)\n    gazebo_initialized = gazebo.initialize()\n    assert gazebo_initialized, \"Failed to initialize ignition gazebo\"\n\n    # Insert the model\n    model_ok = gazebo.insertModel(model_data, plugin_data)\n    assert model_ok, \"Failed to insert the model in the simulation\"\n\n    assert bindings.RobotSingleton_get().exists(\n        robot_name\n    ), \"The robot interface was not registered in the singleton\"\n\n    # Extract the robot interface from the singleton\n    robot_weak_ptr = bindings.RobotSingleton_get().getRobot(robot_name)\n    assert not robot_weak_ptr.expired(), \"The Robot object has expired\"\n    assert (\n        robot_weak_ptr.lock()\n    ), \"The returned Robot object does not contain a valid interface\"\n    assert robot_weak_ptr.lock().valid(), \"The Robot object is not valid\"\n\n    # Get the pointer to the robot interface\n    robot = robot_weak_ptr.lock()\n\n    # Set the default update rate\n    robot.setdt(1 / controller_rate)\n\n    # Control the cart joint in position\n    ok_cm = robot.setJointControlMode(\"linear\", bindings.JointControlMode_Position)\n    assert ok_cm, \"Failed to control the cart joint in position\"\n\n    # Set the PID of the cart joint\n    pid = bindings.PID(10000, 1000, 1000)\n    pid_ok = robot.setJointPID(\"linear\", pid)\n    assert pid_ok, \"Failed to set the PID of the cart joint\"\n\n    # Reset the robot state\n    robot.resetJoint(\"pivot\", 0, 0)\n    robot.resetJoint(\"linear\", 0, 0)\n\n    # Generate the cart trajectory\n    cart_ref = np.fromiter(\n        (0.2 * np.sin(2 * np.pi * 0.5 * t) for t in np.arange(0, 5, 1 / agent_rate)),\n        dtype=np.float,\n    )\n\n    # Initialize the cart position buffer\n    pos_cart_buffer = np.zeros(np.shape(cart_ref))\n\n    for (i, ref) in enumerate(cart_ref):\n        # Set the references\n        ok1 = robot.setJointPositionTarget(\"linear\", ref)\n        assert ok1, \"Failed to set joint references\"\n\n        # Step the simulator\n        gazebo.run()\n\n        # Read the position\n        pos_cart_buffer[i] = robot.jointPosition(\"linear\")\n\n    # Check that the trajectory was followed correctly\n    assert (\n        np.abs(pos_cart_buffer - cart_ref).sum() / cart_ref.size < 5e-3\n    ), \"The reference trajectory was not tracked correctly\"\n"
  },
  {
    "path": "tests/.python/test_runtimes.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport gym\nimport numpy as np\nimport pytest\nfrom gym.envs import registry\nfrom gym.envs.registration import register\nfrom gym_ignition.robots.sim import gazebo, pybullet\nfrom gym_ignition.tasks.cartpole_discrete import CartPoleDiscrete\nfrom gym_ignition.tasks.pendulum_swingup import PendulumSwingUp\nfrom gym_ignition.utils import logger\n\n# Set verbosity\nlogger.set_level(gym.logger.DEBUG)\n\nif \"Pendulum-Ignition-PyTest-v0\" not in [spec.id for spec in list(registry.all())]:\n    register(\n        id=\"Pendulum-Ignition-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n        max_episode_steps=1000,\n        kwargs={\n            \"task_cls\": PendulumSwingUp,\n            \"robot_cls\": gazebo.pendulum.PendulumGazeboRobot,\n            \"model\": \"Pendulum/Pendulum.urdf\",\n            \"world\": \"DefaultEmptyWorld.world\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,\n            \"hard_reset\": False,\n        },\n    )\n\nif \"Pendulum-PyBullet-PyTest-v0\" not in [spec.id for spec in list(registry.all())]:\n    register(\n        id=\"Pendulum-PyBullet-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.pybullet_runtime:PyBulletRuntime\",\n        max_episode_steps=1000,\n        kwargs={\n            \"task_cls\": PendulumSwingUp,\n            \"robot_cls\": pybullet.pendulum.PendulumPyBulletRobot,\n            \"model\": \"Pendulum/Pendulum.urdf\",\n            \"world\": \"plane_implicit.urdf\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,  # To keep errors small, pybullet needs a higher rate\n            \"hard_reset\": False,\n        },\n    )\n\nif \"CartPoleDiscrete-Ignition-PyTest-v0\" not in [\n    spec.id for spec in list(registry.all())\n]:\n    register(\n        id=\"CartPoleDiscrete-Ignition-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.gazebo_runtime:GazeboRuntime\",\n        max_episode_steps=500,\n        kwargs={\n            \"task_cls\": CartPoleDiscrete,\n            \"robot_cls\": gazebo.cartpole.CartPoleGazeboRobot,\n            \"model\": \"CartPole/CartPole.urdf\",\n            \"world\": \"DefaultEmptyWorld.world\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,\n            \"hard_reset\": False,\n        },\n    )\n\nif \"CartPoleDiscrete-PyBullet-PyTest-v0\" not in [\n    spec.id for spec in list(registry.all())\n]:\n    register(\n        id=\"CartPoleDiscrete-PyBullet-PyTest-v0\",\n        entry_point=\"gym_ignition.runtimes.pybullet_runtime:PyBulletRuntime\",\n        max_episode_steps=500,\n        kwargs={\n            \"task_cls\": CartPoleDiscrete,\n            \"robot_cls\": pybullet.cartpole.CartPolePyBulletRobot,\n            \"model\": \"CartPole/CartPole.urdf\",\n            \"world\": \"plane_implicit.urdf\",\n            \"rtf\": 100,\n            \"agent_rate\": 4000,\n            \"physics_rate\": 4000,\n            \"hard_reset\": False,\n        },\n    )\n\n\ndef template_compare_environments(env_name_a: str, env_name_b: str, max_error: float):\n    # Create the pendulum\n    env_a = gym.make(env_name_a)\n    env_b = gym.make(env_name_b)\n\n    assert (\n        env_a.unwrapped.spec._kwargs[\"agent_rate\"]\n        == env_b.unwrapped.spec._kwargs[\"agent_rate\"]\n    )\n\n    logger.set_level(gym.logger.DEBUG)\n\n    # Render the environment\n    # env.render('human')\n    # time.sleep(5)\n\n    # Seed the environment\n    env_a.seed(42)\n    env_b.seed(42)\n\n    range_obs = env_a.observation_space.high - env_a.observation_space.low\n    range_obs = np.where(np.isinf(range_obs), 1000, range_obs)\n\n    for epoch in range(10):\n        # Reset the environments\n        observation_a = env_a.reset()\n        observation_b = env_b.reset()\n\n        assert np.allclose(\n            observation_a, observation_b\n        ), \"Observations after reset don't match\"\n\n        # Initialize intermediate variables\n        iteration = 0\n        done_a = False\n\n        while not done_a:\n            iteration += 1\n\n            # Sample a random action from the environment a\n            action = env_a.action_space.sample()\n\n            # Step the environments\n            observation_a, _, done_a, _ = env_b.step(action)\n            observation_b, _, done_b, _ = env_a.step(action)\n\n            error = np.sum(\n                np.abs(observation_a / range_obs - observation_b / range_obs)\n            )\n\n            if error > max_error:\n                print(\"===================\")\n                print(f\"Environment A name: {env_name_a}\")\n                print(f\"Environment B name: {env_name_b}\")\n                print(f\"Rollout: #{epoch}@{iteration}\")\n                print(f\"Error: {error}\")\n                print(f\"Max Error: {max_error}\")\n                print(f\"Observation A: {observation_a}\")\n                print(f\"Observation B: {observation_b}\")\n                print(\"===================\")\n                assert False, \"The error is bigger than the threshold\"\n\n    env_a.close()\n    env_b.close()\n\n\n@pytest.mark.parametrize(\n    \"env_name_a, env_name_b, max_error\",\n    [\n        (\"Pendulum-Ignition-PyTest-v0\", \"Pendulum-PyBullet-PyTest-v0\", 0.05),\n        (\n            \"CartPoleDiscrete-Ignition-PyTest-v0\",\n            \"CartPoleDiscrete-PyBullet-PyTest-v0\",\n            0.03,\n        ),\n    ],\n)\ndef test_compare_environments(env_name_a: str, env_name_b: str, max_error: float):\n    template_compare_environments(env_name_a, env_name_b, max_error)\n"
  },
  {
    "path": "tests/.python/utils.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport abc\nimport tempfile\n\nimport numpy as np\nimport pybullet as p\nimport pybullet_data\nfrom gym_ignition import gympp_bindings as bindings\nfrom gym_ignition.robots import gazebo_robot, sim\nfrom gym_ignition.utils import resource_finder\nfrom pybullet_utils import bullet_client\n\n\nclass Simulator(abc.ABC):\n    simulator = None\n    simulator_name: str = \"\"\n\n    @abc.abstractmethod\n    def step(self):\n        pass\n\n    @abc.abstractmethod\n    def close(self):\n        pass\n\n\nclass Gazebo(Simulator):\n    simulator_name = \"gazebo\"\n\n    def __init__(\n        self,\n        physics_rate: float,\n        iterations: int = int(1),\n        rtf=float(np.finfo(np.float32).max),\n    ):\n        self.simulator = bindings.GazeboSimulator(iterations, rtf, physics_rate)\n        assert self.simulator\n\n        self.simulator.setVerbosity(4)\n\n        empty_world = resource_finder.find_resource(\"DefaultEmptyWorld.world\")\n        ok_world = self.simulator.setupGazeboWorld(empty_world)\n        assert ok_world\n\n        ok_initialize = self.simulator.initialize()\n        assert ok_initialize\n\n    def step(self):\n        assert self.simulator.initialized()\n\n        ok_run = self.simulator.run()\n        assert ok_run\n\n    def close(self):\n        ok_close = self.simulator.close()\n        assert ok_close\n\n\nclass PyBullet(Simulator):\n    simulator_name = \"pybullet\"\n\n    def __init__(self, physics_rate: float):\n        self.simulator = bullet_client.BulletClient(p.DIRECT)\n        assert self.simulator\n\n        self.simulator.setRealTimeSimulation(0)\n        self.simulator.setGravity(0, 0, -9.81)\n        self.simulator.setTimeStep(1.0 / physics_rate)\n\n        self.simulator.setAdditionalSearchPath(pybullet_data.getDataPath())\n        self.plane_id = self.simulator.loadURDF(\"plane_implicit.urdf\")\n\n    def step(self):\n        self.simulator.stepSimulation()\n\n    def close(self):\n        pass\n\n\n# TODO: we need urdf for the controllers\ndef get_pendulum(simulator: Simulator, **kwargs):\n    if simulator.simulator_name == \"gazebo\":\n        return sim.gazebo.pendulum.PendulumGazeboRobot(\n            gazebo=simulator.simulator, **kwargs\n        )\n    elif simulator.simulator_name == \"pybullet\":\n        return sim.pybullet.pendulum.PendulumPyBulletRobot(\n            p=simulator.simulator, plane_id=simulator.plane_id, **kwargs\n        )\n    else:\n        raise Exception(f\"Simulator {simulator.simulator_name} not recognized\")\n\n\ndef get_cartpole(simulator: Simulator, **kwargs):\n    if simulator.simulator_name == \"gazebo\":\n        return sim.gazebo.cartpole.CartPoleGazeboRobot(\n            gazebo=simulator.simulator, **kwargs\n        )\n    elif simulator.simulator_name == \"pybullet\":\n        return sim.pybullet.cartpole.CartPolePyBulletRobot(\n            p=simulator.simulator, plane_id=simulator.plane_id, **kwargs\n        )\n    else:\n        raise Exception(f\"Simulator {simulator.simulator_name} not recognized\")\n\n\nclass CubeGazeboRobot(gazebo_robot.GazeboRobot):\n    def __init__(self, gazebo, initial_position: np.ndarray, model_file: str = None):\n\n        if model_file is None:\n            # Serialize the cube urdf\n            handle, model_file = tempfile.mkstemp()\n            with open(handle, \"w\") as f:\n                f.write(get_cube_urdf())\n\n        # Initialize base class\n        super().__init__(model_file=model_file, gazebo=gazebo)\n\n        ok_floating = self.set_as_floating_base(True)\n        assert ok_floating, \"Failed to set the robot as floating base\"\n\n        # Initial base position and orientation\n        base_position = np.array(initial_position)\n        base_orientation = np.array([1.0, 0.0, 0.0, 0.0])\n        ok_base_pose = self.set_initial_base_pose(base_position, base_orientation)\n        assert ok_base_pose, \"Failed to set base pose\"\n\n        # Insert the model in the simulation\n        _ = self.gympp_robot\n\n\ndef get_cube_urdf() -> str:\n    mass = 5.0\n    edge = 0.2\n    i = 1 / 12 * mass * (edge ** 2 + edge ** 2)\n    cube_urdf = f\"\"\"\n    <robot name=\"cube_robot\" xmlns:xacro=\"http://www.ros.org/wiki/xacro\">\n        <link name=\"cube\">\n            <inertial>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n              <mass value=\"{mass}\"/>\n              <inertia ixx=\"{i}\" ixy=\"0\" ixz=\"0\" iyy=\"{i}\" iyz=\"0\" izz=\"{i}\"/>\n            </inertial>\n            <visual>\n              <geometry>\n                <box size=\"{edge} {edge} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n            </visual>\n            <collision>\n              <geometry>\n                <box size=\"{edge} {edge} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n            </collision>\n        </link>\n    </robot>\"\"\"\n    return cube_urdf\n"
  },
  {
    "path": "tests/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import common\n"
  },
  {
    "path": "tests/assets/worlds/fuel_support.sdf",
    "content": "<?xml version=\"1.0\" ?>\n<sdf version=\"1.5\">\n  <world name=\"default\">\n    <include>\n      <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Ground Plane</uri>\n    </include>\n    <include>\n      <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Sun</uri>\n    </include>\n    <model name=\"box\">\n      <pose>0 0 0.5 0 0 0</pose>\n      <link name=\"link\">\n        <collision name=\"collision\">\n          <geometry>\n            <box>\n              <size>1 1 1</size>\n            </box>\n          </geometry>\n        </collision>\n        <visual name=\"visual\">\n          <geometry>\n            <box>\n              <size>1 1 1</size>\n            </box>\n          </geometry>\n        </visual>\n      </link>\n    </model>\n  </world>\n</sdf>\n"
  },
  {
    "path": "tests/common/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nfrom . import utils\n"
  },
  {
    "path": "tests/common/utils.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport dataclasses\nfrom typing import Tuple\n\nimport gym_ignition_models\nimport pytest\nfrom gym_ignition.utils import misc\n\nfrom scenario import gazebo as scenario\n\n\ndef id_gazebo_fn(val: Tuple[float, float, float]):\n    if isinstance(val, tuple) and len(val) == 3:\n        return f\"step={val[0]}_rtf={val[1]}_iters={val[2]}\"\n\n\n@pytest.fixture(scope=\"function\")\ndef gazebo_fixture(request):\n    \"\"\"\n    Return an instance of the GazeboSimulator ensuring that it\n    is closed even in case of failure.\n\n    Example:\n\n        from ..common.utils import gazebo_fixture as gazebo\n\n        @pytest.mark.parametrize(\"gazebo\", [(0.001, 1.0, 1)], indirect=True)\n        def test_foo(gazebo: scenario.gazebo.GazeboSimulator):\n\n            assert gazebo.initialize()\n            # ...\n\n        @pytest.mark.parametrize(\"gazebo, name\",\n                                 [((0.001, 1.0, 1), \"name_1\"),\n                                  ((0.001, 1.0, 1), \"name_2\"),\n                                  ((0.001, 1.0, 1), \"name_3\")],\n                                  indirect=\"gazebo\")\n        def test_foo(gazebo: scenario.gazebo.GazeboSimulator, name: str):\n\n            model_name = name\n            assert gazebo.initialize()\n            # ...\n    \"\"\"\n\n    step_size, rtf, iterations = request.param\n    gazebo = scenario.GazeboSimulator(step_size, rtf, iterations)\n\n    yield gazebo\n\n    gazebo.close()\n\n\n@pytest.fixture(scope=\"function\")\ndef default_world_fixture(request):\n    \"\"\"\n    Initialize a default world with ground and physics.\n\n    Example:\n\n        from ..common.utils import default_world_fixture as default_world\n\n        @pytest.mark.parametrize(\"default_world\", [(0.001, 1.0, 1)], indirect=True)\n        def test_foo(default_world: Tuple[scenario.GazeboSimulator, scenario.World]):\n\n            # Get the simulator and the world\n            gazebo, world = default_world\n\n            # ...\n    \"\"\"\n\n    step_size, rtf, iterations = request.param\n    gazebo = scenario.GazeboSimulator(step_size, rtf, iterations)\n\n    assert gazebo.initialize()\n\n    world = gazebo.get_world().to_gazebo()\n    assert world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    yield gazebo, world\n\n    gazebo.close()\n\n\ndef get_multi_world_sdf_file() -> str:\n\n    multi_world_sdf_string = f\"\"\"\n    <?xml version=\"1.0\" ?>\n    <sdf version=\"1.6\">\n        <world name=\"world1\">\n        </world>\n        <world name=\"world2\">\n        </world>\n    </sdf>\"\"\"\n\n    multi_world_sdf = misc.string_to_file(multi_world_sdf_string)\n    return multi_world_sdf\n\n\ndef get_cube_sdf_string() -> str:\n    return \"\"\"\n    <?xml version=\"1.0\" ?>\n    <sdf version=\"1.6\">\n        <model name='box'>\n        <pose>0 0 0.5 0 -0 0</pose>\n            <link name='box_link'>\n                <inertial>\n                <inertia>\n                    <ixx>1</ixx>\n                    <ixy>0</ixy>\n                    <ixz>0</ixz>\n                    <iyy>1</iyy>\n                    <iyz>0</iyz>\n                    <izz>1</izz>\n                </inertia>\n                <mass>1</mass>\n                </inertial>\n                <collision name='box_collision'>\n                <geometry>\n                    <box>\n                        <size>1 1 1</size>\n                    </box>\n                </geometry>\n                <surface>\n                    <friction>\n                        <ode/>\n                    </friction>\n                    <contact/>\n                </surface>\n                </collision>\n                <visual name='box_visual'>\n                <geometry>\n                    <box>\n                    <size>1 1 1</size>\n                    </box>\n                </geometry>\n                <material>\n                    <ambient>1 0 0 1</ambient>\n                    <diffuse>1 0 0 1</diffuse>\n                    <specular>1 0 0 1</specular>\n                </material>\n                </visual>\n            </link>\n        </model>\n    </sdf>\n    \"\"\"\n\n\ndef get_cube_urdf_string() -> str:\n\n    mass = 5.0\n    edge = 0.2\n    i = 1 / 12 * mass * (edge ** 2 + edge ** 2)\n    cube_urdf = f\"\"\"\n    <robot name=\"cube_robot\" xmlns:xacro=\"http://www.ros.org/wiki/xacro\">\n        <link name=\"cube\">\n            <inertial>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n              <mass value=\"{mass}\"/>\n              <inertia ixx=\"{i}\" ixy=\"0\" ixz=\"0\" iyy=\"{i}\" iyz=\"0\" izz=\"{i}\"/>\n            </inertial>\n            <visual>\n              <geometry>\n                <box size=\"{edge} {edge} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n            </visual>\n            <collision>\n              <geometry>\n                <box size=\"{edge} {edge} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n            </collision>\n        </link>\n    </robot>\"\"\"\n\n    return cube_urdf\n\n\ndef get_cube_urdf() -> str:\n\n    model_file = misc.string_to_file(get_cube_urdf_string())\n    return model_file\n\n\ndef get_empty_world_sdf() -> str:\n\n    world_sdf_string = scenario.get_empty_world()\n\n    world_file = misc.string_to_file(world_sdf_string)\n    return world_file\n\n\n@dataclasses.dataclass\nclass SphereURDF:\n\n    mass: float = 5.0\n    radius: float = 0.1\n    restitution: float = 0\n\n    def urdf(self) -> str:\n\n        i = 2.0 / 5 * self.mass * self.radius * self.radius\n        urdf = f\"\"\"\n            <robot name=\"sphere_model\" xmlns:xacro=\"http://www.ros.org/wiki/xacro\">\n                <link name=\"sphere\">\n                    <inertial>\n                      <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n                      <mass value=\"{self.mass}\"/>\n                      <inertia ixx=\"{i}\" ixy=\"0\" ixz=\"0\" iyy=\"{i}\" iyz=\"0\" izz=\"{i}\"/>\n                    </inertial>\n                    <visual>\n                      <geometry>\n                        <sphere radius=\"{self.radius}\"/>\n                      </geometry>\n                      <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n                    </visual>\n                    <collision>\n                      <geometry>\n                        <sphere radius=\"{self.radius}\"/>\n                      </geometry>\n                      <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n                    </collision>\n                </link>\n                <gazebo reference=\"sphere\">\n                  <collision><surface><bounce>\n                    <restitution_coefficient>{self.restitution}</restitution_coefficient>\n                  </bounce></surface></collision>\n                </gazebo>\n            </robot>\n            \"\"\"\n\n        return urdf\n"
  },
  {
    "path": "tests/test_gym_ignition/__init__.py",
    "content": "# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n"
  },
  {
    "path": "tests/test_gym_ignition/test_inverse_kinematics.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.gym_ignition\n\nfrom typing import Tuple\n\nimport numpy as np\nfrom gym_ignition.context.gazebo import controllers\nfrom gym_ignition.rbd.idyntree import inverse_kinematics_nlp\nfrom gym_ignition_environments import models\n\nfrom scenario import gazebo as scenario_gazebo\n\nfrom ..common.utils import default_world_fixture as default_world\n\n# Set the verbosity\nscenario_gazebo.set_verbosity(scenario_gazebo.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\"default_world\", [(1.0 / 1_000, 1.0, 1)], indirect=True)\ndef test_inverse_kinematics(\n    default_world: Tuple[scenario_gazebo.GazeboSimulator, scenario_gazebo.World]\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    # Get the robot\n    panda = models.panda.Panda(world=world)\n    gazebo.run(paused=True)\n\n    # Control all the joints\n    controlled_joints = panda.joint_names()\n\n    # Set the controller period\n    assert panda.set_controller_period(gazebo.step_size())\n    assert panda.controller_period() == gazebo.step_size()\n\n    # Insert the ComputedTorqueFixedBase controller\n    assert panda.to_gazebo().insert_model_plugin(\n        *controllers.ComputedTorqueFixedBase(\n            kp=[20.0] * panda.dofs(),\n            ki=[0.0] * panda.dofs(),\n            kd=[5.0] * panda.dofs(),\n            urdf=panda.get_model_file(),\n            joints=controlled_joints,\n        ).args()\n    )\n\n    # Create the IK object\n    ik = inverse_kinematics_nlp.InverseKinematicsNLP(\n        urdf_filename=panda.get_model_file(),\n        considered_joints=controlled_joints,\n        joint_serialization=panda.joint_names(),\n    )\n\n    # Initialize IK\n    ik.initialize(verbosity=1, floating_base=False, cost_tolerance=1e-8)\n\n    # There should be no active targets\n    assert len(ik.get_active_target_names()) == 0\n\n    # Add the cartesian target of the end effector\n    end_effector = \"end_effector_frame\"\n    ik.add_target(\n        frame_name=end_effector,\n        target_type=inverse_kinematics_nlp.TargetType.POSE,\n        as_constraint=False,\n    )\n\n    assert set(ik.get_active_target_names()) == {end_effector}\n    assert (\n        ik.get_target_data(target_name=end_effector).type\n        == inverse_kinematics_nlp.TargetType.POSE\n    )\n\n    # Desired EE position\n    target_ee_position = np.array([0.5, -0.3, 1.0])\n    target_ee_quaternion = np.array([0.0, 1.0, 0.0, 0.0])\n\n    # Update the target transform\n    ik.update_transform_target(\n        target_name=end_effector,\n        position=target_ee_position,\n        quaternion=target_ee_quaternion,\n    )\n\n    # Check that the target transform was stored\n    assert isinstance(\n        ik.get_target_data(target_name=end_effector).data,\n        inverse_kinematics_nlp.TransformTargetData,\n    )\n    assert ik.get_target_data(target_name=end_effector).data.position == pytest.approx(\n        target_ee_position\n    )\n    assert ik.get_target_data(\n        target_name=end_effector\n    ).data.quaternion == pytest.approx(target_ee_quaternion)\n\n    # Set the current configuration\n    ik.set_current_robot_configuration(\n        base_position=np.array(panda.base_position()),\n        base_quaternion=np.array(panda.base_orientation()),\n        joint_configuration=np.array(panda.joint_positions()),\n    )\n\n    # Solve the IK problem\n    ik.solve()\n\n    # Get the full solution\n    ik_solution = ik.get_full_solution()\n\n    # Validate the solution\n    assert ik_solution.joint_configuration.size == len(controlled_joints)\n    assert ik_solution.base_position == pytest.approx(np.array([0.0, 0, 0]))\n    assert ik_solution.base_quaternion == pytest.approx(np.array([1.0, 0, 0, 0]))\n\n    # Set the desired joint configuration\n    assert panda.set_joint_position_targets(\n        ik_solution.joint_configuration, controlled_joints\n    )\n    assert panda.set_joint_velocity_targets([0.0] * len(controlled_joints))\n    assert panda.set_joint_acceleration_targets([0.0] * len(controlled_joints))\n\n    for _ in range(5_000):\n        gazebo.run()\n\n    # Check that the desired joint configuration has been reached\n    assert panda.joint_positions(controlled_joints) == pytest.approx(\n        ik_solution.joint_configuration, abs=np.deg2rad(0.1)\n    )\n\n    # Get the end effector pose\n    ee_position = panda.get_link(link_name=end_effector).position()\n    ee_quaternion = panda.get_link(link_name=end_effector).orientation()\n\n    assert ee_position == pytest.approx(target_ee_position, abs=0.005)\n    assert ee_quaternion == pytest.approx(target_ee_quaternion, abs=0.005)\n"
  },
  {
    "path": "tests/test_gym_ignition/test_normalization.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.gym_ignition\n\nfrom gym_ignition.utils.math import denormalize, normalize\n\ntest_matrix = [\n    # Float, None\n    (1, None, None, 1),\n    (1, 0, None, 1),\n    (1, None, 0, 1),\n    # Float / Float\n    (0, -1, 1, 0),\n    (-1, -1, 1, -1),\n    (1, -1, 1, 1),\n    # List / Float\n    ([-1, 0, 1, 2], -2, 2, [-0.5, 0, 0.5, 1]),\n    ([-1, 0, 1, 2], -2.0, 2.0, [-0.5, 0, 0.5, 1]),\n    ([-1.0, 0, 1, 2], -2, 2, [-0.5, 0, 0.5, 1]),\n    ([-1.0, 0, 1, 2], 1, 1, [-1.0, 0, 1, 2]),\n    # List / List\n    ([-1, 0, 2.0], [-1, -2, 1], [-1, 4, 3], [-1, -0.3333333, 0]),\n]\n\n\n@pytest.mark.parametrize(\"input,low, high, output\", test_matrix)\ndef test_normalization(input, low, high, output):\n\n    normalized_input = normalize(input=input, low=low, high=high)\n\n    assert output == pytest.approx(normalized_input)\n    assert input == pytest.approx(\n        denormalize(input=normalized_input, low=low, high=high)\n    )\n"
  },
  {
    "path": "tests/test_gym_ignition/test_reproducibility.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.gym_ignition\n\nimport gym\nfrom gym_ignition.utils.logger import set_level\nfrom gym_ignition_environments import randomizers\n\n# Set the verbosity\nset_level(gym.logger.DEBUG)\n\n\ndef make_env(**kwargs) -> gym.Env:\n\n    import gym\n    import gym_ignition_environments\n\n    return gym.make(\"CartPoleDiscreteBalancing-Gazebo-v0\", **kwargs)\n\n\n@pytest.mark.parametrize(\"num_physics_rollouts\", [0, 2])\ndef test_reproducibility(num_physics_rollouts: int):\n\n    env1 = randomizers.cartpole.CartpoleEnvRandomizer(\n        env=make_env, num_physics_rollouts=num_physics_rollouts\n    )\n\n    env2 = randomizers.cartpole.CartpoleEnvRandomizer(\n        env=make_env, num_physics_rollouts=num_physics_rollouts\n    )\n\n    assert env1 != env2\n\n    # Seed the environment\n    env1.seed(42)\n    env2.seed(42)\n\n    for _ in range(5):\n\n        # Reset the environments\n        observation1 = env1.reset()\n        observation2 = env2.reset()\n        assert observation1 == pytest.approx(observation2)\n\n        # Initialize returned values\n        done = False\n\n        while not done:\n\n            # Sample a random action\n            action1 = env1.action_space.sample()\n            action2 = env2.action_space.sample()\n            assert action1 == pytest.approx(action2)\n\n            # Step the environment\n            observation1, reward1, done1, info1 = env1.step(action1)\n            observation2, reward2, done2, info2 = env2.step(action2)\n\n            assert done1 == pytest.approx(done2)\n            assert info1 == pytest.approx(info2)\n            assert reward1 == pytest.approx(reward2)\n            assert observation1 == pytest.approx(observation2)\n\n            done = done1\n\n    env1.close()\n    env2.close()\n"
  },
  {
    "path": "tests/test_gym_ignition/test_sdf_randomizer.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.gym_ignition\n\nimport gym_ignition_models\nfrom gym_ignition.randomizers.model import sdf\nfrom gym_ignition.randomizers.model.sdf import (\n    Distribution,\n    GaussianParams,\n    Method,\n    UniformParams,\n)\nfrom gym_ignition.utils import misc\nfrom lxml import etree\n\nfrom scenario import gazebo as scenario\n\n\ndef test_sdf_randomizer():\n\n    # Get the URDF model\n    urdf_model = gym_ignition_models.get_model_file(\"cartpole\")\n\n    # Convert it to a SDF string\n    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)\n\n    # Write the SDF string to a temp file\n    sdf_model = misc.string_to_file(sdf_model_string)\n\n    # Create the randomizer\n    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)\n\n    # Get the original model string. It is parsed and then serialized without changes.\n    orig_model = randomizer.sample(pretty_print=True)\n\n    with pytest.raises(ValueError):\n        # Setting wrong distribution\n        randomizer.new_randomization().at_xpath(\n            \"*/link[@name='pole']/inertial/inertia/ixx\"\n        ).method(Method.Additive).sampled_from(\n            Distribution.Uniform, GaussianParams(mean=0, variance=0.1)\n        ).add()\n\n    # Add a uniform randomization\n    randomizer.new_randomization().at_xpath(\n        \"*/link[@name='pole']/inertial/inertia/ixx\"\n    ).method(Method.Additive).sampled_from(\n        Distribution.Gaussian, GaussianParams(mean=0, variance=0.1)\n    ).add()\n\n    randomizer.process_data()\n    assert len(randomizer.get_active_randomizations()) == 1\n\n    assert randomizer.sample(pretty_print=True) != orig_model\n\n    # Clean the randomizer\n    randomizer.clean()\n    assert len(randomizer.get_active_randomizations()) == 0\n    assert randomizer.sample(pretty_print=True) == orig_model\n\n    # Add a multi-match randomization\n    randomizer.new_randomization().at_xpath(\"*/link/inertial/inertia/ixx\").method(\n        Method.Coefficient\n    ).sampled_from(Distribution.Uniform, UniformParams(low=0.8, high=1.2)).add()\n\n    assert len(randomizer.get_active_randomizations()) == 1\n\n    # Expand the matches\n    randomizer.process_data()\n    assert len(randomizer.get_active_randomizations()) > 1\n\n    # Sample\n    assert randomizer.sample(pretty_print=True) != orig_model\n\n\ndef test_randomizer_reproducibility():\n\n    # Get the model\n    sdf_model = gym_ignition_models.get_model_file(\"ground_plane\")\n\n    # Initialize the randomizers\n    randomizer1 = sdf.SDFRandomizer(sdf_model=sdf_model)\n    randomizer2 = sdf.SDFRandomizer(sdf_model=sdf_model)\n    randomizer3 = sdf.SDFRandomizer(sdf_model=sdf_model)\n\n    # Randomize the ground friction of all links (the ground plane collision)\n    frictions = randomizer1.find_xpath(\"*/link/collision/surface/friction\")\n    assert len(frictions) == 1\n\n    # Get the original model string. It is parsed and then serialized without changes.\n    orig_model_string1 = randomizer1.sample(pretty_print=True)\n    orig_model_string2 = randomizer2.sample(pretty_print=True)\n    orig_model_string3 = randomizer3.sample(pretty_print=True)\n    assert orig_model_string1 == orig_model_string2 == orig_model_string3\n\n    # Do not seed #3\n    randomizer1.seed(42)\n    randomizer2.seed(42)\n\n    # Add randomizations for #1\n    randomizer1.new_randomization().at_xpath(\n        \"*/link/collision/surface/friction/ode/mu\"\n    ).method(Method.Absolute).sampled_from(\n        Distribution.Uniform, UniformParams(low=0, high=100)\n    ).add()\n\n    # Add randomizations for #2\n    randomizer2.new_randomization().at_xpath(\n        \"*/link/collision/surface/friction/ode/mu\"\n    ).method(Method.Absolute).sampled_from(\n        Distribution.Uniform, UniformParams(low=0, high=100)\n    ).add()\n\n    # Add randomizations for #3\n    randomizer3.new_randomization().at_xpath(\n        \"*/link/collision/surface/friction/ode/mu\"\n    ).method(Method.Absolute).sampled_from(\n        Distribution.Uniform, UniformParams(low=0, high=100)\n    ).add()\n\n    # Process the randomizations\n    randomizer1.process_data()\n    randomizer2.process_data()\n    randomizer3.process_data()\n\n    for _ in range(5):\n        model1 = randomizer1.sample()\n        model2 = randomizer2.sample()\n        model3 = randomizer3.sample()\n\n        assert model1 == model2\n        assert model1 != model3\n\n\ndef test_randomize_missing_element():\n\n    # Get the URDF model\n    urdf_model = gym_ignition_models.get_model_file(\"pendulum\")\n\n    # Convert it to a SDF string\n    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)\n\n    # Write the SDF string to a temp file\n    sdf_model = misc.string_to_file(sdf_model_string)\n\n    # Create the randomizer\n    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)\n\n    # Try to randomize a missing element\n    with pytest.raises(RuntimeError):\n        # The ode/mu elements are missing\n        randomizer.new_randomization().at_xpath(\n            \"*/link/collision/surface/friction/ode/mu\"\n        ).method(Method.Absolute).sampled_from(\n            Distribution.Uniform, UniformParams(low=0, high=100)\n        ).add()\n\n    # Add the missing friction/ode/mu element. We assume that friction exists.\n    frictions = randomizer.find_xpath(\"*/link/collision/surface/friction\")\n\n    for friction in frictions:\n\n        # Create parent 'ode' first\n        if friction.find(\"ode\") is None:\n            etree.SubElement(friction, \"ode\")\n\n        # Create child 'mu' after\n        ode = friction.find(\"ode\")\n        if ode.find(\"mu\") is None:\n            etree.SubElement(ode, \"mu\")\n\n        # Assign a dummy value to mu\n        mu = ode.find(\"mu\")\n        mu.text = str(0)\n\n    # Apply the same randomization\n    randomizer.new_randomization().at_xpath(\n        \"*/link/collision/surface/friction/ode/mu\"\n    ).method(Method.Absolute).sampled_from(\n        Distribution.Uniform, UniformParams(low=0, high=100)\n    ).ignore_zeros(\n        False\n    ).add()\n\n    # Process the randomization and sample a model\n    randomizer.process_data()\n\n    model1 = randomizer.sample(pretty_print=True)\n    model2 = randomizer.sample(pretty_print=True)\n    assert model1 != model2\n\n\ndef test_full_panda_randomization():\n\n    # Get the URDF model\n    urdf_model = gym_ignition_models.get_model_file(\"panda\")\n\n    # Convert it to a SDF string\n    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)\n\n    # Write the SDF string to a temp file\n    sdf_model = misc.string_to_file(sdf_model_string)\n\n    # Create the randomizer\n    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)\n\n    joint_dynamics = randomizer.find_xpath(\"*/joint/axis/dynamics\")\n    assert len(joint_dynamics) > 0\n\n    # Add the friction and damping elements since they're missing in the model\n    for joint_dynamic in joint_dynamics:\n\n        if joint_dynamic.find(\"friction\") is None:\n            etree.SubElement(joint_dynamic, \"friction\")\n            friction = joint_dynamic.find(\"friction\")\n            friction.text = str(0)\n\n        if joint_dynamic.find(\"damping\") is None:\n            etree.SubElement(joint_dynamic, \"damping\")\n            damping = joint_dynamic.find(\"damping\")\n            damping.text = str(3)\n\n    randomization_config = {\n        \"*/link/inertial/mass\": {\n            # mass + U(-0.5, 0.5)\n            \"method\": Method.Additive,\n            \"distribution\": Distribution.Uniform,\n            \"params\": UniformParams(low=-0.5, high=0.5),\n            \"ignore_zeros\": True,\n            \"force_positive\": True,\n        },\n        \"*/link/inertial/inertia/ixx\": {\n            # inertia * N(1, 0.2)\n            \"method\": Method.Coefficient,\n            \"distribution\": Distribution.Gaussian,\n            \"params\": GaussianParams(mean=1.0, variance=0.2),\n            \"ignore_zeros\": True,\n            \"force_positive\": True,\n        },\n        \"*/link/inertial/inertia/iyy\": {\n            \"method\": Method.Coefficient,\n            \"distribution\": Distribution.Gaussian,\n            \"params\": GaussianParams(mean=1.0, variance=0.2),\n            \"ignore_zeros\": True,\n            \"force_positive\": True,\n        },\n        \"*/link/inertial/inertia/izz\": {\n            \"method\": Method.Coefficient,\n            \"distribution\": Distribution.Gaussian,\n            \"params\": GaussianParams(mean=1.0, variance=0.2),\n            \"ignore_zeros\": True,\n            \"force_positive\": True,\n        },\n        \"*/joint/axis/dynamics/friction\": {\n            # friction in [0, 5]\n            \"method\": Method.Absolute,\n            \"distribution\": Distribution.Uniform,\n            \"params\": UniformParams(low=0, high=5),\n            \"ignore_zeros\": False,  # We initialized the value as 0\n            \"force_positive\": True,\n        },\n        \"*/joint/axis/dynamics/damping\": {\n            # damping (= 3.0) * [0.8, 1.2]\n            \"method\": Method.Coefficient,\n            \"distribution\": Distribution.Uniform,\n            \"params\": UniformParams(low=0.8, high=1.2),\n            \"ignore_zeros\": True,\n            \"force_positive\": True,\n        },\n        # TODO: */joint/axis/limit/effort\n    }\n\n    for xpath, config in randomization_config.items():\n\n        randomizer.new_randomization().at_xpath(xpath).method(\n            config[\"method\"]\n        ).sampled_from(config[\"distribution\"], config[\"params\"]).force_positive(\n            config[\"distribution\"]\n        ).ignore_zeros(\n            config[\"ignore_zeros\"]\n        ).add()\n\n    randomizer.process_data()\n    assert len(randomizer.get_active_randomizations()) > 0\n\n    randomizer.sample(pretty_print=True)\n"
  },
  {
    "path": "tests/test_scenario/__init__.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n"
  },
  {
    "path": "tests/test_scenario/test_contacts.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Callable\n\nimport gym_ignition_models\nimport numpy as np\nfrom gym_ignition.utils import misc\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\ndef get_cube_urdf_string_double_collision() -> str:\n\n    mass = 5.0\n    edge = 0.2\n    i = 1 / 12 * mass * (edge ** 2 + edge ** 2)\n    cube_urdf = f\"\"\"\n    <robot name=\"cube_robot\" xmlns:xacro=\"http://www.ros.org/wiki/xacro\">\n        <link name=\"cube\">\n            <inertial>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n              <mass value=\"{mass}\"/>\n              <inertia ixx=\"{i}\" ixy=\"0\" ixz=\"0\" iyy=\"{i}\" iyz=\"0\" izz=\"{i}\"/>\n            </inertial>\n            <visual>\n              <geometry>\n                <box size=\"{edge} {edge} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n            </visual>\n            <collision>\n              <geometry>\n                <box size=\"{edge} {edge / 2} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 -{edge / 4} 0\"/>\n            </collision>\n            <collision>\n              <geometry>\n                <box size=\"{edge} {edge / 2} {edge}\"/>\n              </geometry>\n              <origin rpy=\"0 0 0\" xyz=\"0 {edge / 4} 0\"/>\n            </collision>\n        </link>\n    </robot>\"\"\"\n\n    return cube_urdf\n\n\n@pytest.mark.parametrize(\n    \"gazebo, get_model_str\",\n    [\n        ((0.001, 1.0, 1), utils.get_cube_urdf_string),\n        ((0.001, 1.0, 1), get_cube_urdf_string_double_collision),\n    ],\n    indirect=[\"gazebo\"],\n    ids=utils.id_gazebo_fn,\n)\ndef test_cube_contact(gazebo: scenario.GazeboSimulator, get_model_str: Callable):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world().to_gazebo()\n\n    # Insert the Physics system\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    # Insert the ground plane\n    assert world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n    assert len(world.model_names()) == 1\n\n    # Insert the cube\n    cube_urdf = misc.string_to_file(get_model_str())\n    assert world.insert_model(\n        cube_urdf, core.Pose([0, 0, 0.15], [1.0, 0, 0, 0]), \"cube\"\n    )\n    assert len(world.model_names()) == 2\n\n    # Get the cube\n    cube = world.get_model(\"cube\")\n\n    # Enable contact detection\n    assert not cube.contacts_enabled()\n    assert cube.enable_contacts(enable=True)\n    assert cube.contacts_enabled()\n\n    # The cube was inserted floating in the air with a 5cm gap wrt to ground.\n    # There should be no contacts.\n    gazebo.run(paused=True)\n    assert not cube.get_link(\"cube\").in_contact()\n    assert len(cube.contacts()) == 0\n\n    # Make the cube fall for 150ms\n    for _ in range(150):\n        gazebo.run()\n\n    # There should be only one contact, between ground and the cube\n    assert cube.get_link(\"cube\").in_contact()\n    assert len(cube.contacts()) == 1\n\n    # Get the contact\n    contact_with_ground = cube.contacts()[0]\n\n    assert contact_with_ground.body_a == \"cube::cube\"\n    assert contact_with_ground.body_b == \"ground_plane::link\"\n\n    # Check contact points\n    for point in contact_with_ground.points:\n\n        assert point.normal == pytest.approx([0, 0, 1])\n\n    # Check that the contact force matches the weight of the cube\n    z_forces = [point.force[2] for point in contact_with_ground.points]\n    assert np.sum(z_forces) == pytest.approx(-5 * world.gravity()[2], abs=0.1)\n\n    # Forces of all contact points are combined by the following method\n    assert cube.get_link(\"cube\").contact_wrench() == pytest.approx(\n        [0, 0, np.sum(z_forces), 0, 0, 0]\n    )\n\n\n@pytest.mark.parametrize(\n    \"gazebo, get_model_str\",\n    [\n        ((0.001, 1.0, 1), utils.get_cube_urdf_string),\n        ((0.001, 1.0, 1), get_cube_urdf_string_double_collision),\n    ],\n    indirect=[\"gazebo\"],\n    ids=utils.id_gazebo_fn,\n)\ndef test_cube_multiple_contacts(\n    gazebo: scenario.GazeboSimulator, get_model_str: Callable\n):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world().to_gazebo()\n\n    # Insert the Physics system\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    # Insert the ground plane\n    assert world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n    assert len(world.model_names()) == 1\n\n    # Insert two cubes side to side with a 10cm gap\n    cube_urdf = misc.string_to_file(get_model_str())\n    assert world.insert_model(\n        cube_urdf, core.Pose([0, -0.15, 0.101], [1.0, 0, 0, 0]), \"cube1\"\n    )\n    assert world.insert_model(\n        cube_urdf, core.Pose([0, 0.15, 0.101], [1.0, 0, 0, 0]), \"cube2\"\n    )\n    assert len(world.model_names()) == 3\n\n    # Get the cubes\n    cube1 = world.get_model(\"cube1\")\n    cube2 = world.get_model(\"cube2\")\n\n    # Enable contact detection\n    assert not cube1.contacts_enabled()\n    assert cube1.enable_contacts(enable=True)\n    assert cube1.contacts_enabled()\n\n    # Enable contact detection\n    assert not cube2.contacts_enabled()\n    assert cube2.enable_contacts(enable=True)\n    assert cube2.contacts_enabled()\n\n    # The cubes were inserted floating in the air with a 1mm gap wrt to ground.\n    # There should be no contacts.\n    gazebo.run(paused=True)\n    assert not cube1.get_link(\"cube\").in_contact()\n    assert not cube2.get_link(\"cube\").in_contact()\n    assert len(cube1.contacts()) == 0\n    assert len(cube2.contacts()) == 0\n\n    # Make the cubes fall for 50ms\n    for _ in range(50):\n        gazebo.run()\n\n    assert cube1.get_link(\"cube\").in_contact()\n    assert cube2.get_link(\"cube\").in_contact()\n    assert len(cube1.contacts()) == 1\n    assert len(cube2.contacts()) == 1\n\n    # Now we make another cube fall above the gap. It will touch both cubes.\n    assert world.insert_model(\n        cube_urdf, core.Pose([0, 0, 0.301], [1.0, 0, 0, 0]), \"cube3\"\n    )\n    assert len(world.model_names()) == 4\n\n    cube3 = world.get_model(\"cube3\")\n    assert not cube3.contacts_enabled()\n    assert cube3.enable_contacts(enable=True)\n    assert cube3.contacts_enabled()\n\n    gazebo.run(paused=True)\n    assert not cube3.get_link(\"cube\").in_contact()\n    assert len(cube3.contacts()) == 0\n\n    # Make the cube fall for 50ms\n    for _ in range(50):\n        gazebo.run()\n\n    # There will be two contacts, respectively with cube1 and cube2.\n    # Contacts are related to the link, not the collision elements. In the case of two\n    # collisions elements associated to the same link, contacts are merged together.\n    assert cube3.get_link(\"cube\").in_contact()\n    assert len(cube3.contacts()) == 2\n\n    contact1 = cube3.contacts()[0]\n    contact2 = cube3.contacts()[1]\n\n    assert contact1.body_a == \"cube3::cube\"\n    assert contact2.body_a == \"cube3::cube\"\n\n    assert contact1.body_b == \"cube1::cube\"\n    assert contact2.body_b == \"cube2::cube\"\n\n    # Calculate the total contact wrench of cube3\n    assert cube3.get_link(\"cube\").contact_wrench() == pytest.approx(\n        [0, 0, 50, 0, 0, 0], abs=1.1\n    )\n\n    # Calculate the total contact force of the cubes below.\n    # They will have 1.5 their weight from below and -0.5 from above.\n    assert cube1.get_link(\"cube\").contact_wrench()[2] == pytest.approx(50, abs=1.1)\n    assert cube1.get_link(\"cube\").contact_wrench()[2] == pytest.approx(50, abs=1.1)\n\n    # Check the normals and the sign of the forces\n    for contact in cube2.contacts():\n        if contact.body_b == \"cube3::cube\":\n            for point in contact.points:\n                assert point.force[2] < 0\n                assert point.normal == pytest.approx([0, 0, -1], abs=0.001)\n        if contact.body_b == \"ground_plane::link\":\n            for point in contact.points:\n                assert point.force[2] > 0\n                assert point.normal == pytest.approx([0, 0, 1], abs=0.001)\n"
  },
  {
    "path": "tests/test_scenario/test_custom_controllers.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nimport gym_ignition_models\nimport numpy as np\nfrom gym_ignition.context.gazebo import controllers\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 5.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_computed_torque_fixed_base(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    step_size = gazebo.step_size()\n\n    # Get the default world\n    world = gazebo.get_world()\n\n    # Insert the physics\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    # Get the panda urdf\n    panda_urdf = gym_ignition_models.get_model_file(\"panda\")\n\n    # Insert the panda arm\n    model_name = \"panda\"\n    assert world.insert_model(panda_urdf, core.Pose_identity(), model_name)\n\n    # import time\n    # gazebo.gui()\n    # time.sleep(3)\n    # gazebo.run(paused=True)\n\n    # Get the model\n    panda = world.get_model(model_name).to_gazebo()\n\n    # Set the controller period\n    panda.set_controller_period(step_size)\n\n    # Insert the controller\n    assert panda.insert_model_plugin(\n        *controllers.ComputedTorqueFixedBase(\n            kp=[10.0] * panda.dofs(),\n            ki=[0.0] * panda.dofs(),\n            kd=[3.0] * panda.dofs(),\n            urdf=panda_urdf,\n            joints=panda.joint_names(),\n        ).args()\n    )\n\n    # Set the references\n    assert panda.set_joint_position_targets([0.0] * panda.dofs())\n    assert panda.set_joint_velocity_targets([0.0] * panda.dofs())\n    assert panda.set_joint_acceleration_targets([0.0] * panda.dofs())\n\n    joints_no_fingers = [j for j in panda.joint_names() if j.startswith(\"panda_joint\")]\n    nr_of_joints = len(joints_no_fingers)\n    assert nr_of_joints > 0\n\n    # Reset the joints state\n    q0 = [np.deg2rad(45)] * nr_of_joints\n    dq0 = [0.1] * nr_of_joints\n    assert panda.reset_joint_positions(q0, joints_no_fingers)\n    assert panda.reset_joint_velocities(dq0, joints_no_fingers)\n\n    assert gazebo.run(True)\n    assert panda.joint_positions(joints_no_fingers) == pytest.approx(q0)\n    assert panda.joint_velocities(joints_no_fingers) == pytest.approx(dq0)\n\n    # Step the simulator for a couple of seconds\n    for _ in range(3000):\n        gazebo.run()\n\n    # Check that the the references have been reached\n    assert panda.joint_positions() == pytest.approx(\n        panda.joint_position_targets(), abs=np.deg2rad(1)\n    )\n    assert panda.joint_velocities() == pytest.approx(\n        panda.joint_velocity_targets(), abs=0.05\n    )\n\n    # Apply an external force\n    assert (\n        panda.get_link(\"panda_link4\").to_gazebo().apply_world_force([100.0, 0, 0], 0.5)\n    )\n\n    for _ in range(4000):\n        assert gazebo.run()\n\n    # Check that the the references have been reached\n    assert panda.joint_positions() == pytest.approx(\n        panda.joint_position_targets(), abs=np.deg2rad(1)\n    )\n    assert panda.joint_velocities() == pytest.approx(\n        panda.joint_velocity_targets(), abs=0.05\n    )\n"
  },
  {
    "path": "tests/test_scenario/test_external_wrench.py",
    "content": "# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Tuple\n\nimport numpy as np\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import default_world_fixture as default_world\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\"default_world\", [(1.0 / 1_000, 1.0, 1)], indirect=True)\ndef test_fixed_base(default_world: Tuple[scenario.GazeboSimulator, scenario.World]):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    # Insert a sphere\n    pose = core.Pose([0, 0.0, 1.0], [1.0, 0, 0, 0])\n    assert world.insert_model_from_string(\n        utils.SphereURDF(mass=10.0).urdf(), pose, \"sphere\"\n    )\n    assert \"sphere\" in world.model_names()\n\n    # Get the sphere\n    sphere = world.get_model(\"sphere\")\n    link = sphere.get_link(\"sphere\").to_gazebo()\n\n    # Get the initial z position\n    initial_height = link.position()[2]\n\n    # Apply a vertical force that counterbalances gravity\n    assert link.apply_world_force(\n        force=-np.array(world.gravity()) * sphere.total_mass(), duration=0.5\n    )\n\n    # Run the simulation for a while\n    for _ in range(500):\n        gazebo.run()\n        assert link.position()[2] == pytest.approx(initial_height)\n\n    # Run the simulation for a while\n    for _ in range(500):\n        gazebo.run()\n        assert link.position()[2] < initial_height\n"
  },
  {
    "path": "tests/test_scenario/test_gazebo_simulator.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nimport gym_ignition_models\n\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\n    \"gazebo\",\n    [\n        (0.001, 1.0, 1),\n        (0.1, 5.0, 5),\n        (0.001, 0.0, 1),\n        (0.001, -1.0, 1),\n        (0.001, 1.0, 0),\n        (0, 1.0, 1),\n    ],\n    indirect=True,\n    ids=utils.id_gazebo_fn,\n)\ndef test_initialization(gazebo: scenario.GazeboSimulator):\n\n    ok = gazebo.initialize()\n\n    rtf = gazebo.real_time_factor()\n    step_size = gazebo.step_size()\n    iterations = gazebo.steps_per_run()\n\n    if step_size <= 0:\n        assert not ok\n        assert not gazebo.initialized()\n        assert not gazebo.run()\n\n    if rtf <= 0:\n        assert not ok\n        assert not gazebo.initialized()\n        assert not gazebo.run()\n\n    if iterations <= 0:\n        assert not ok\n        assert not gazebo.initialized()\n        assert not gazebo.run()\n\n    if rtf > 0 and iterations > 0 and step_size > 0:\n        assert ok\n        assert gazebo.initialized()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_run(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    assert gazebo.run(paused=True)\n    assert gazebo.run()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_pause(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    assert not gazebo.running()\n    assert gazebo.pause()\n\n    assert gazebo.initialize()\n\n    assert not gazebo.running()\n    assert gazebo.pause()\n\n    assert gazebo.run(paused=True)\n    assert not gazebo.running()\n    assert gazebo.pause()\n\n    assert gazebo.run(paused=False)\n    assert not gazebo.running()\n    assert gazebo.pause()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_paused_step(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    world = gazebo.get_world().to_gazebo()\n    assert world.insert_model(gym_ignition_models.get_model_file(\"ground_plane\"))\n    assert \"ground_plane\" in world.model_names()\n    gazebo.run(paused=True)\n\n    world.remove_model(\"ground_plane\")\n\n    assert \"ground_plane\" in world.model_names()\n    gazebo.run(paused=True)\n    assert \"ground_plane\" not in world.model_names()\n    assert world.time() == 0.0\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_load_default_world(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    assert gazebo.world_names()\n    assert len(gazebo.world_names()) == 1\n\n    world1 = gazebo.get_world()\n    assert world1\n    assert world1.name() in gazebo.world_names()\n\n    world2 = gazebo.get_world(gazebo.world_names()[0])\n    assert world2\n\n    assert world1.id() == world2.id()\n    assert world1.name() == world2.name()\n\n    # TODO: understand how to compare shared ptr returned by swig with nullptr\n    # world3 = gazebo.get_world(\"foo\")\n    # assert world3\n"
  },
  {
    "path": "tests/test_scenario/test_ignition_fuel.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom pathlib import Path\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\n# See https://github.com/robotology/gym-ignition/pull/339#issuecomment-828300490\n@pytest.mark.xfail(strict=False)\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_download_model_from_fuel(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    # Get the default world\n    world = gazebo.get_world()\n\n    # Download a model from Fuel (testing a name with spaces)\n    model_name = \"Electrical Box\"\n    model_sdf = scenario.get_model_file_from_fuel(\n        f\"https://fuel.ignitionrobotics.org/openrobotics/models/{model_name}\", False\n    )\n    assert model_sdf\n\n    assert world.insert_model(model_sdf, core.Pose_identity())\n    assert model_name in world.model_names()\n\n    # Insert another model changing its name\n    other_model_name = \"my_box\"\n    other_model_pose = core.Pose([3.0, 0.0, 0.0], [1.0, 0, 0, 0])\n    assert world.insert_model(model_sdf, other_model_pose, other_model_name)\n    assert other_model_name in world.model_names()\n\n    assert gazebo.run()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_fuel_world(gazebo: scenario.GazeboSimulator):\n    # (setup) load a world that includes a fuel model\n    worlds_folder = Path(__file__) / \"..\" / \"..\" / \"assets\" / \"worlds\"\n    world_file = worlds_folder / \"fuel_support.sdf\"\n    assert gazebo.insert_world_from_sdf(str(world_file.resolve()))\n    assert gazebo.initialize()\n    assert gazebo.run(paused=True)\n\n    # the actual test\n    assert \"ground_plane\" in gazebo.get_world().model_names()\n"
  },
  {
    "path": "tests/test_scenario/test_link_velocities.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Callable, Tuple\n\nimport gym_ignition_models\nimport numpy as np\nfrom gym_ignition.utils.scenario import get_joint_positions_space\nfrom scipy.spatial.transform import Rotation\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import default_world_fixture as default_world\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\ndef to_wxyz(xyzw: np.ndarray) -> np.ndarray:\n\n    if xyzw.shape != (4,):\n        raise ValueError(xyzw)\n\n    return xyzw[[3, 0, 1, 2]]\n\n\ndef to_xyzw(wxyz: np.ndarray) -> np.ndarray:\n\n    if wxyz.shape != (4,):\n        raise ValueError(wxyz)\n\n    return wxyz[[1, 2, 3, 0]]\n\n\ndef to_matrix(quaternion: Tuple[float, float, float, float]) -> np.ndarray:\n\n    quaternion_xyzw = to_xyzw(np.array(quaternion))\n    return Rotation.from_quat(quaternion_xyzw).as_matrix()\n\n\ndef get_random_panda(\n    gazebo: scenario.GazeboSimulator, world: scenario.World\n) -> core.Model:\n\n    panda_urdf = gym_ignition_models.get_model_file(\"panda\")\n    assert world.insert_model(panda_urdf)\n    assert \"panda\" in world.model_names()\n\n    panda = world.get_model(\"panda\")\n\n    joint_space = get_joint_positions_space(model=panda)\n    joint_space.seed(10)\n\n    q = joint_space.sample()\n    dq = joint_space.np_random.uniform(low=-1.0, high=1.0, size=q.shape)\n\n    assert panda.to_gazebo().reset_joint_positions(q.tolist())\n    assert panda.to_gazebo().reset_joint_velocities(dq.tolist())\n\n    assert gazebo.run(paused=True)\n    return panda\n\n\ndef get_cube(gazebo: scenario.GazeboSimulator, world: scenario.World) -> core.Model:\n\n    quaternion = to_wxyz(Rotation.from_euler(\"x\", 45, degrees=True).as_quat())\n    initial_pose = core.Pose([0, 0, 0.5], quaternion.tolist())\n\n    cube_urdf = utils.get_cube_urdf()\n    assert world.insert_model(cube_urdf, initial_pose)\n    assert \"cube_robot\" in world.model_names()\n\n    cube = world.get_model(\"cube_robot\")\n\n    assert cube.to_gazebo().reset_base_world_linear_velocity([0.1, -0.2, -0.3])\n    assert cube.to_gazebo().reset_base_world_angular_velocity([-0.1, 2.0, 0.3])\n\n    assert gazebo.run(paused=True)\n    return cube\n\n\n# 1. VELOCITY LINEAR\n@pytest.mark.parametrize(\n    \"default_world, get_model, link_name\",\n    [\n        ((1.0 / 10_000, 1.0, 1), get_random_panda, \"panda_link7\"),\n        ((1.0 / 10_000, 1.0, 1), get_cube, \"cube\"),\n    ],\n    indirect=[\"default_world\"],\n)\ndef test_linear_velocity(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World],\n    get_model: Callable[[scenario.GazeboSimulator, scenario.World], core.Model],\n    link_name: str,\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n    dt = gazebo.step_size()\n\n    # Get the model\n    model = get_model(gazebo, world)\n\n    # Get the link.\n    # If the link is the base link, get the data through the base methods.\n    link = model.get_link(link_name)\n\n    if link.name() != model.base_frame():\n\n        position = link.position\n        orientation = link.orientation\n        body_linear_velocity = link.body_linear_velocity\n        world_linear_velocity = link.world_linear_velocity\n\n    else:\n\n        position = model.base_position\n        orientation = model.base_orientation\n        body_linear_velocity = model.base_body_linear_velocity\n        world_linear_velocity = model.base_world_linear_velocity\n\n    # 0.5 seconds of simulation\n    for _ in range(int(0.5 / dt)):\n\n        position_old = np.array(position())\n        assert gazebo.run()\n        position_new = np.array(position())\n\n        world_velocity = (position_new - position_old) / dt\n\n        # Test the world velocity (MIXED)\n        assert world_velocity == pytest.approx(world_linear_velocity(), abs=1e-2)\n\n        # Eq 18\n        # Test the BODY velocity\n        W_R_L = to_matrix(orientation())\n        body_velocity = W_R_L.transpose() @ np.array(world_linear_velocity())\n        assert body_velocity == pytest.approx(body_linear_velocity())\n\n    gazebo.close()\n\n\n# 2. VELOCITY ANGULAR\n@pytest.mark.parametrize(\n    \"default_world, get_model, link_name\",\n    [\n        ((1.0 / 10_000, 1.0, 1), get_random_panda, \"panda_link7\"),\n        ((1.0 / 10_000, 1.0, 1), get_cube, \"cube\"),\n    ],\n    indirect=[\"default_world\"],\n)\ndef test_angular_velocity(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World],\n    get_model: Callable[[scenario.GazeboSimulator, scenario.World], core.Model],\n    link_name: str,\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n    dt = gazebo.step_size()\n\n    # Get the model\n    model = get_model(gazebo, world)\n\n    # Get the link.\n    # If the link is the base link, get the data through the base methods.\n    link = model.get_link(link_name)\n\n    if link.name() != model.base_frame():\n\n        orientation = link.orientation\n        body_angular_velocity = link.body_angular_velocity\n        world_angular_velocity = link.world_angular_velocity\n\n    else:\n\n        orientation = model.base_orientation\n        body_angular_velocity = model.base_body_angular_velocity\n        world_angular_velocity = model.base_world_angular_velocity\n\n    skew = lambda matrix: (matrix - matrix.transpose()) / 2\n    vee = lambda matrix: [matrix[2, 1], matrix[0, 2], matrix[1, 0]]\n\n    for _ in range(int(0.5 / dt)):\n\n        W_R_L_old = to_matrix(orientation())\n        assert gazebo.run()\n        W_R_L_new = to_matrix(orientation())\n\n        dot_rotation_matrix = (W_R_L_new - W_R_L_old) / dt\n        world_velocity = dot_rotation_matrix @ W_R_L_new.transpose()\n\n        # Test the world velocity (MIXED)\n        assert vee(skew(world_velocity)) == pytest.approx(\n            world_angular_velocity(), abs=0.005\n        )\n\n        # Test the BODY velocity\n        body_velocity = W_R_L_new.transpose() @ dot_rotation_matrix\n        assert vee(skew(body_velocity)) == pytest.approx(\n            body_angular_velocity(), abs=0.005\n        )\n\n\n# 3. ACCELERATION LINEAR\n@pytest.mark.parametrize(\n    \"default_world, get_model, link_name\",\n    [\n        ((1.0 / 10_000, 1.0, 1), get_random_panda, \"panda_link7\"),\n        # ((1.0 / 10_000, 1.0, 1), get_cube, \"cube\"),  # TODO\n    ],\n    indirect=[\"default_world\"],\n)\ndef test_linear_acceleration(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World],\n    get_model: Callable[[scenario.GazeboSimulator, scenario.World], core.Model],\n    link_name: str,\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n    dt = gazebo.step_size()\n\n    # Get the model\n    model = get_model(gazebo, world)\n\n    # Get the link.\n    # If the link is the base link, get the data through the base methods.\n    link = model.get_link(link_name)\n\n    if link.name() != model.base_frame():\n\n        orientation = link.orientation\n        world_linear_velocity = link.world_linear_velocity\n        body_linear_acceleration = link.body_linear_acceleration\n        world_linear_acceleration = link.world_linear_acceleration\n\n    else:\n\n        orientation = model.base_orientation\n        world_linear_velocity = model.base_world_linear_velocity\n        body_linear_acceleration = model.base_body_linear_acceleration\n        world_linear_acceleration = model.base_word_linear_acceleration\n\n    # 0.5 seconds of simulation\n    for _ in range(int(0.5 / dt)):\n\n        velocity_old = np.array(world_linear_velocity())\n        assert gazebo.run()\n        velocity_new = np.array(world_linear_velocity())\n\n        world_acceleration = (velocity_new - velocity_old) / dt\n\n        # By time to time there are steps where the acceleration becomes extremely high,\n        # like 1000 m/s/s when the average is never exceeds 4 m/s/s.\n        # We exclude those points. We should understand why this happens.\n        if (np.array(world_linear_acceleration()) > 100.0).any():\n            continue\n\n        # Test the world acceleration (MIXED)\n        assert world_linear_acceleration() == pytest.approx(world_acceleration, abs=0.5)\n\n        # Test the BODY acceleration\n        # Note: https://github.com/ignitionrobotics/ign-gazebo/issues/87\n        W_R_L = to_matrix(orientation())\n        body_acceleration = W_R_L.transpose() @ np.array(world_linear_acceleration())\n        assert body_acceleration == pytest.approx(body_linear_acceleration())\n\n    gazebo.close()\n\n\n# 2. ACCELERATION ANGULAR\n@pytest.mark.parametrize(\n    \"default_world, get_model, link_name\",\n    [\n        ((1.0 / 10_000, 1.0, 1), get_random_panda, \"panda_link7\"),\n        # ((1.0 / 10_000, 1.0, 1), get_cube, \"cube\"),  # TODO\n    ],\n    indirect=[\"default_world\"],\n)\ndef test_angular_acceleration(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World],\n    get_model: Callable[[scenario.GazeboSimulator, scenario.World], core.Model],\n    link_name: str,\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n    dt = gazebo.step_size()\n\n    # Get the model\n    model = get_model(gazebo, world)\n\n    # Get the link.\n    # If the link is the base link, get the data through the base methods.\n    link = model.get_link(link_name)\n\n    if link.name() != model.base_frame():\n\n        orientation = link.orientation\n        world_angular_velocity = link.world_angular_velocity\n        body_angular_acceleration = link.body_angular_acceleration\n        world_angular_acceleration = link.world_angular_acceleration\n\n    else:\n\n        orientation = model.base_orientation\n        world_angular_velocity = model.base_world_angular_velocity\n        body_angular_acceleration = model.base_body_angular_acceleration\n        world_angular_acceleration = model.base_word_angular_acceleration\n\n    for _ in range(int(0.5 / dt)):\n\n        world_velocity_old = np.array(world_angular_velocity())\n        assert gazebo.run()\n        world_velocity_new = np.array(world_angular_velocity())\n\n        world_acceleration = (world_velocity_new - world_velocity_old) / dt\n\n        # By time to time there are steps where the acceleration becomes extremely high,\n        # like 1000 rad/s/s when the average is never exceeds 20 rad/s/s.\n        # We exclude those points. We should understand why this happens.\n        if (np.array(world_angular_acceleration()) > 100.0).any():\n            continue\n\n        # Test the world acceleration (MIXED)\n        assert world_acceleration == pytest.approx(\n            world_angular_acceleration(), abs=0.2\n        )\n\n        # Note: https://github.com/ignitionrobotics/ign-gazebo/issues/87\n        W_R_L = to_matrix(orientation())\n        body_acceleration = W_R_L.transpose() @ np.array(world_angular_acceleration())\n        assert body_acceleration == pytest.approx(body_angular_acceleration())\n"
  },
  {
    "path": "tests/test_scenario/test_model.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Tuple\n\nimport gym_ignition_models\nimport numpy as np\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import default_world_fixture as default_world\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\ndef get_model(\n    gazebo: scenario.GazeboSimulator, gym_ignition_models_name: str\n) -> scenario.Model:\n\n    # Get the world and cast it to a Gazebo world\n    world = gazebo.get_world().to_gazebo()\n\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    model_urdf = gym_ignition_models.get_model_file(gym_ignition_models_name)\n\n    assert world.insert_model(\n        model_urdf, core.Pose_identity(), gym_ignition_models_name\n    )\n\n    # Get the model and cast it to a Gazebo model\n    model = world.get_model(gym_ignition_models_name).to_gazebo()\n    assert model.id() != 0\n    assert model.valid()\n\n    return model\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_model_core_api(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    gym_ignition_model_name = \"cartpole\"\n    model = get_model(gazebo, gym_ignition_model_name)\n\n    assert model.id() != 0\n    assert model.valid()\n    assert model.name() == gym_ignition_model_name\n\n    assert len(model.link_names()) == model.nr_of_links()\n    assert len(model.joint_names()) == model.nr_of_joints()\n\n    assert model.set_controller_period(0.42)\n    assert model.controller_period() == 0.42\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_model_joints(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    gym_ignition_model_name = \"panda\"\n    model = get_model(gazebo, gym_ignition_model_name)\n\n    q = model.joint_positions()\n    assert pytest.approx(q) == [0.0] * model.dofs()\n\n    dq = model.joint_velocities()\n    assert pytest.approx(dq) == [0.0] * model.dofs()\n\n    assert model.reset_joint_positions([0.05] * model.dofs())\n    assert model.joint_positions() == pytest.approx([0.0] * model.dofs())\n    gazebo.run(paused=True)\n    assert model.joint_positions() == pytest.approx([0.05] * model.dofs())\n    assert model.joint_velocities() == pytest.approx([0.0] * model.dofs())\n\n    gazebo.run(paused=False)\n    assert model.joint_velocities() != pytest.approx([0.0] * model.dofs())\n\n    assert model.reset_joint_velocities([-0.1] * model.dofs())\n    assert model.joint_velocities() != pytest.approx([-0.1] * model.dofs())\n    gazebo.run(paused=True)\n    assert model.joint_velocities() == pytest.approx([-0.1] * model.dofs())\n\n    assert model.reset_joint_positions([0.0] * model.dofs())\n    assert model.reset_joint_velocities([0.0] * model.dofs())\n\n    joint_subset = model.joint_names()[0:4]\n    assert model.reset_joint_positions([-0.4] * len(joint_subset), joint_subset)\n    assert model.reset_joint_velocities([3.0] * len(joint_subset), joint_subset)\n    gazebo.run(paused=True)\n    assert model.joint_positions(joint_subset) == pytest.approx(\n        [-0.4] * len(joint_subset)\n    )\n    assert model.joint_velocities(joint_subset) == pytest.approx(\n        [3.0] * len(joint_subset)\n    )\n    assert model.joint_positions() == pytest.approx(\n        [-0.4] * len(joint_subset) + [0.0] * (model.dofs() - len(joint_subset))\n    )\n    assert model.joint_velocities() == pytest.approx(\n        [3.0] * len(joint_subset) + [0.0] * (model.dofs() - len(joint_subset))\n    )\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_model_base_pose(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    gym_ignition_model_name = \"pendulum\"\n    model = get_model(gazebo, gym_ignition_model_name)\n    assert gym_ignition_model_name in gazebo.get_world().model_names()\n\n    assert model.base_frame() == \"support\"\n    # assert model.set_base_frame(\"support\")  # TODO: Not yet supported\n    # assert model.set_base_frame(\"pendulum\")  # TODO: Not yet supported\n\n    # Check that the pose is the identical\n    gazebo.run(paused=True)\n    assert model.base_position() == pytest.approx([0, 0, 0])\n    assert model.base_orientation() == pytest.approx([1, 0, 0, 0])\n\n    # Reset the base pose\n    new_base_pose = dict(position=[5, 5, 0], orientation=[0, 1, 0, 0])\n    assert model.reset_base_pose(\n        new_base_pose[\"position\"], new_base_pose[\"orientation\"]\n    )\n\n    # Before stepping the simulation the pose should be the initial one\n    assert model.base_position() == pytest.approx([0, 0, 0])\n    assert model.base_orientation() == pytest.approx([1, 0, 0, 0])\n\n    # Step the simulator and check that the pose changes\n    gazebo.run(paused=True)\n    assert model.base_position() == pytest.approx(new_base_pose[\"position\"])\n    assert model.base_orientation() == pytest.approx(new_base_pose[\"orientation\"])\n\n\n@pytest.mark.parametrize(\n    \"default_world\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_model_base_velocity(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World]\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    model_urdf = gym_ignition_models.get_model_file(\"pendulum\")\n\n    # Insert the first pendulum\n    model1_name = \"pendulum1\"\n    model1_pose = core.Pose([0, 1.0, 1.0], [1.0, 0, 0, 0])\n    assert world.insert_model(model_urdf, model1_pose, model1_name)\n    model1 = world.get_model(model1_name).to_gazebo()\n    assert model1.valid()\n    assert model1_name in gazebo.get_world().model_names()\n    assert model1.base_frame() == \"support\"\n\n    # Insert the second pendulum\n    model2_name = \"pendulum2\"\n    model2_pose = core.Pose([0, -1.0, 1.0], [1.0, 0, 0, 0])\n    assert world.insert_model(model_urdf, model2_pose, model2_name)\n    model2 = world.get_model(model2_name).to_gazebo()\n    assert model2.valid()\n    assert model2_name in gazebo.get_world().model_names()\n    assert model2.base_frame() == \"support\"\n\n    # Target velocity\n    lin_velocity = [0, 0, 5.0]\n    ang_velocity = [0.1, 0.5, -3.0]\n\n    # Reset both linear and angular of pendulum1 by calling the combined method\n    assert model1.reset_base_world_velocity(lin_velocity, ang_velocity)\n    assert model1.base_world_linear_velocity() == pytest.approx([0, 0, 0])\n    assert model1.base_world_angular_velocity() == pytest.approx([0, 0, 0])\n\n    # Reset both linear and angular of pendulum2 by calling the individual method\n    assert model2.reset_base_world_linear_velocity(lin_velocity)\n    assert model2.reset_base_world_angular_velocity(ang_velocity)\n    assert model2.base_world_linear_velocity() == pytest.approx([0, 0, 0])\n    assert model2.base_world_angular_velocity() == pytest.approx([0, 0, 0])\n\n    # Run the simulation\n    gazebo.run()\n\n    # Check model1 velocity\n    assert model1.base_world_linear_velocity() == pytest.approx(lin_velocity, abs=0.01)\n    assert model1.base_world_angular_velocity() == pytest.approx(ang_velocity, abs=0.01)\n\n    # Check model2 velocity\n    assert model2.base_world_linear_velocity() == pytest.approx(lin_velocity, abs=0.01)\n    assert model2.base_world_angular_velocity() == pytest.approx(ang_velocity, abs=0.01)\n\n    # The velocity of the base link must be the same\n    assert model1.get_link(\"support\").world_linear_velocity() == pytest.approx(\n        lin_velocity, abs=0.01\n    )\n    assert model1.get_link(\"support\").world_angular_velocity() == pytest.approx(\n        ang_velocity, abs=0.01\n    )\n\n    # The velocity of the base link must be the same\n    assert model2.get_link(\"support\").world_linear_velocity() == pytest.approx(\n        lin_velocity, abs=0.01\n    )\n    assert model2.get_link(\"support\").world_angular_velocity() == pytest.approx(\n        ang_velocity, abs=0.01\n    )\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_model_references(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n\n    gym_ignition_model_name = \"cartpole\"\n    model = get_model(gazebo, gym_ignition_model_name)\n    assert gym_ignition_model_name in gazebo.get_world().model_names()\n\n    assert model.set_joint_control_mode(core.JointControlMode_force)\n\n    assert model.set_joint_position_targets([0.5, -3])\n    assert model.joint_position_targets() == pytest.approx([0.5, -3])\n    assert model.joint_position_targets([\"pivot\"]) == pytest.approx([-3])\n\n    assert model.set_joint_velocity_targets([-0.1, 6])\n    assert model.joint_velocity_targets() == pytest.approx([-0.1, 6])\n    assert model.joint_velocity_targets([\"pivot\"]) == pytest.approx([6])\n\n    assert model.set_joint_acceleration_targets([-0, 3.14])\n    assert model.joint_acceleration_targets() == pytest.approx([-0, 3.14])\n    assert model.joint_acceleration_targets([\"pivot\"]) == pytest.approx([3.14])\n\n    assert model.set_joint_generalized_force_targets([20.1, -13])\n    assert model.joint_generalized_force_targets() == pytest.approx([20.1, -13])\n    assert model.joint_generalized_force_targets([\"pivot\"]) == pytest.approx([-13])\n\n    assert model.set_base_pose_target((0, 0, 5), (0, 0, 0, 1.0))\n    assert model.set_base_orientation_target((0, 0, 1.0, 0))\n    assert model.base_position_target() == pytest.approx([0, 0, 5])\n    assert model.base_orientation_target() == pytest.approx([0, 0, 1.0, 0])\n\n    assert model.set_base_world_linear_velocity_target((1, 2, 3))\n    assert model.set_base_world_angular_velocity_target((4, 5, 6))\n    assert model.set_base_world_angular_acceleration_target((-1, -2, -3))\n    assert model.base_world_linear_velocity_target() == pytest.approx([1, 2, 3])\n    assert model.base_world_angular_velocity_target() == pytest.approx([4, 5, 6])\n    assert model.base_world_angular_acceleration_target() == pytest.approx([-1, -2, -3])\n\n\n# def test_model_contacts():\n#     pass\n\n\n@pytest.mark.parametrize(\"default_world\", [(1.0 / 1_000, 1.0, 1)], indirect=True)\ndef test_history_of_joint_forces(\n    default_world: Tuple[scenario.GazeboSimulator, scenario.World]\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    # Insert a panda model\n    panda_urdf = gym_ignition_models.get_model_file(\"panda\")\n    assert world.insert_model(panda_urdf)\n    assert \"panda\" in world.model_names()\n\n    # Get the model\n    panda = world.get_model(\"panda\")\n\n    # Control the robot in Force\n    assert panda.set_joint_control_mode(core.JointControlMode_force)\n\n    # Enable the history for 3 steps\n    assert panda.enable_history_of_applied_joint_forces(True, 3)\n\n    # Initialize the torques applied in the first run\n    torques = np.zeros(panda.dofs())\n\n    # History of joint forces\n    history_last_three_runs = np.zeros(panda.dofs() * 3)\n\n    for _ in range(10):\n\n        torques += 0.1\n        assert panda.set_joint_generalized_force_targets(torques)\n\n        gazebo.run()\n\n        history_last_three_runs = np.concatenate((history_last_three_runs, torques))\n        history_last_three_runs = history_last_three_runs[-panda.dofs() * 3 :]\n\n        assert panda.history_of_applied_joint_forces() == pytest.approx(\n            history_last_three_runs\n        )\n"
  },
  {
    "path": "tests/test_scenario/test_multi_world.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\n# import gym_ignition_models\n# import numpy as np\n# from gym_ignition.utils import misc\n\n# from scenario import core as scenario_core\nfrom scenario import gazebo as scenario_gazebo\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario_gazebo.set_verbosity(scenario_gazebo.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_insert_multiple_worlds(gazebo: scenario_gazebo.GazeboSimulator):\n\n    empty_world_sdf = utils.get_empty_world_sdf()\n    assert gazebo.insert_world_from_sdf(empty_world_sdf, \"myWorld1\")\n\n    assert not gazebo.insert_world_from_sdf(empty_world_sdf, \"myWorld1\")\n    assert gazebo.insert_world_from_sdf(empty_world_sdf, \"myWorld2\")\n\n    assert gazebo.initialize()\n    assert \"myWorld1\" in gazebo.world_names()\n    assert \"myWorld2\" in gazebo.world_names()\n\n    my_world1 = gazebo.get_world(\"myWorld1\")\n    my_world2 = gazebo.get_world(\"myWorld2\")\n\n    assert my_world1.id() != my_world2.id()\n    assert my_world1.name() == \"myWorld1\"\n    assert my_world2.name() == \"myWorld2\"\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_insert_multiple_world(gazebo: scenario_gazebo.GazeboSimulator):\n\n    multi_world_sdf = utils.get_multi_world_sdf_file()\n\n    assert gazebo.insert_worlds_from_sdf(multi_world_sdf)\n    assert gazebo.initialize()\n\n    assert \"world1\" in gazebo.world_names()\n    assert \"world2\" in gazebo.world_names()\n\n    world1 = gazebo.get_world(\"world1\")\n    world2 = gazebo.get_world(\"world2\")\n\n    assert world1.name() == \"world1\"\n    assert world2.name() == \"world2\"\n\n    assert world1.id() != world2.id()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_insert_multiple_world_rename(gazebo: scenario_gazebo.GazeboSimulator):\n\n    multi_world_sdf = utils.get_multi_world_sdf_file()\n\n    assert not gazebo.insert_worlds_from_sdf(multi_world_sdf, [\"only_one_name\"])\n    assert gazebo.insert_worlds_from_sdf(multi_world_sdf, [\"myWorld1\", \"myWorld2\"])\n    assert gazebo.initialize()\n\n    assert \"myWorld1\" in gazebo.world_names()\n    assert \"myWorld2\" in gazebo.world_names()\n\n    world1 = gazebo.get_world(\"myWorld1\")\n    world2 = gazebo.get_world(\"myWorld2\")\n\n    assert world1.name() == \"myWorld1\"\n    assert world2.name() == \"myWorld2\"\n\n    assert world1.id() != world2.id()\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_insert_world_multiple_calls(gazebo: scenario_gazebo.GazeboSimulator):\n\n    single_world_sdf = utils.get_empty_world_sdf()\n\n    assert gazebo.insert_world_from_sdf(single_world_sdf)\n    assert not gazebo.insert_world_from_sdf(single_world_sdf)\n    assert gazebo.insert_world_from_sdf(single_world_sdf, \"world2\")\n    assert gazebo.initialize()\n\n    assert \"default\" in gazebo.world_names()\n    assert \"world2\" in gazebo.world_names()\n\n    world1 = gazebo.get_world(\"default\")\n    world2 = gazebo.get_world(\"world2\")\n\n    assert world1.name() == \"default\"\n    assert world2.name() == \"world2\"\n\n    assert world1.id() != world2.id()\n\n\n# # This test is flaky\n# @pytest.mark.xfail(strict=False)\n# @pytest.mark.parametrize(\"gazebo, solver\",\n#                          [((0.001, 2.0, 1), \"pgs\"),\n#                           ((0.001, 2.0, 1), \"dantzig\")],\n#                          indirect=[\"gazebo\"],\n#                          ids=utils.id_gazebo_fn)\n# def test_multi_world_simulation(gazebo: scenario_gazebo.GazeboSimulator,\n#                                 solver: str):\n#\n#     # Empty DART world with bullet as collision detector.\n#     # It should prevent ODE crashes in a multi-world setting due to its static variables.\n#     world_sdf_string = f\"\"\"\n#     <?xml version=\"1.0\" ?>\n#     <sdf version=\"1.7\">\n#         <world name=\"default\">\n#             <physics default=\"true\" type=\"dart\">\n#                 <dart>\n#                     <collision_detector>bullet</collision_detector>\n#                     <solver>\n#                         <solver_type>{solver}</solver_type>\n#                     </solver>\n#                 </dart>\n#             </physics>\n#             <light type=\"directional\" name=\"sun\">\n#                 <cast_shadows>true</cast_shadows>\n#                 <pose>0 0 10 0 0 0</pose>\n#                 <diffuse>1 1 1 1</diffuse>\n#                 <specular>0.5 0.5 0.5 1</specular>\n#                 <attenuation>\n#                     <range>1000</range>\n#                     <constant>0.9</constant>\n#                     <linear>0.01</linear>\n#                     <quadratic>0.001</quadratic>\n#                 </attenuation>\n#                 <direction>-0.5 0.1 -0.9</direction>\n#             </light>\n#         </world>\n#     </sdf>\n#     \"\"\"\n#\n#     # Create a tmp file from the SDF string\n#     world_sdf_file = misc.string_to_file(string=world_sdf_string)\n#\n#     # Load two different worlds\n#     assert gazebo.insert_world_from_sdf(world_sdf_file, \"dart1\")\n#     assert gazebo.insert_world_from_sdf(world_sdf_file, \"dart2\")\n#\n#     # Initialize the simulator\n#     assert gazebo.initialize()\n#\n#     # gazebo.gui()\n#     # import time\n#     # time.sleep(1)\n#     # gazebo.run(paused=True)\n#\n#     sphere_urdf_string = utils.SphereURDF(restitution=0.8).urdf()\n#     sphere_urdf = misc.string_to_file(sphere_urdf_string)\n#     ground_plane_urdf = gym_ignition_models.get_model_file(robot_name=\"ground_plane\")\n#\n#     # Pose of the sphere\n#     sphere_pose = scenario_core.Pose([0, 0, 0.5], [1, 0, 0, 0])\n#\n#     # Populate the first DART world\n#     world1 = gazebo.get_world(\"dart1\")\n#     world1.set_physics_engine(scenario_gazebo.PhysicsEngine_dart)\n#     world1.insert_model(ground_plane_urdf)\n#     world1.insert_model(sphere_urdf, sphere_pose)\n#     sphere1 = world1.get_model(model_name=\"sphere_model\")\n#\n#     # Populate the second DART world\n#     world2 = gazebo.get_world(\"dart2\")\n#     world2.set_physics_engine(scenario_gazebo.PhysicsEngine_dart)\n#     world2.insert_model(ground_plane_urdf)\n#     world2.insert_model(sphere_urdf, sphere_pose)\n#     sphere2 = world2.get_model(model_name=\"sphere_model\")\n#\n#     # Integration time\n#     dt = gazebo.step_size() * gazebo.steps_per_run()\n#\n#     # Enable contacts\n#     sphere1.enable_contacts(True)\n#     sphere2.enable_contacts(True)\n#\n#     for _ in np.arange(start=0.0, stop=5.0, step=dt):\n#\n#         # Run the simulator\n#         assert gazebo.run()\n#\n#         # Check that both worlds evolve similarly\n#         assert sphere1.base_position() == \\\n#                pytest.approx(sphere2.base_position(), abs=0.001)\n#         assert sphere1.base_world_linear_velocity() == \\\n#                pytest.approx(sphere2.base_world_linear_velocity(), abs=0.001)\n#         assert sphere1.base_world_angular_velocity() == \\\n#                pytest.approx(sphere2.base_world_angular_velocity())\n"
  },
  {
    "path": "tests/test_scenario/test_pid_controllers.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Tuple\n\nimport gym_ignition_models\nimport numpy as np\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common.utils import default_world_fixture as default_world\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n# Panda PID gains\n# https://github.com/mkrizmancic/franka_gazebo/blob/master/config/default.yaml\npanda_pid_gains_1000Hz = {\n    \"panda_joint1\": core.PID(50, 0, 20),\n    \"panda_joint2\": core.PID(10000, 0, 500),\n    \"panda_joint3\": core.PID(100, 0, 10),\n    \"panda_joint4\": core.PID(1000, 0, 50),\n    \"panda_joint5\": core.PID(100, 0, 10),\n    \"panda_joint6\": core.PID(100, 0, 10),\n    \"panda_joint7\": core.PID(10, 0.5, 0.1),\n    \"panda_finger_joint1\": core.PID(100, 0, 50),\n    \"panda_finger_joint2\": core.PID(100, 0, 50),\n}\n\n\n@pytest.mark.parametrize(\"default_world\", [(1.0 / 1_000, 1.0, 1)], indirect=True)\ndef test_position_pid(default_world: Tuple[scenario.GazeboSimulator, scenario.World]):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    # Insert a panda model\n    panda_urdf = gym_ignition_models.get_model_file(\"panda\")\n    assert world.insert_model(panda_urdf)\n    assert \"panda\" in world.model_names()\n\n    # Get the model and cast it to Gazebo\n    panda = world.get_model(\"panda\").to_gazebo()\n\n    # Disable any velocity and torque limits of the model\n    _ = [j.set_velocity_limit(np.finfo(float).max) for j in panda.joints()]\n    _ = [j.set_max_generalized_force(np.finfo(float).max) for j in panda.joints()]\n\n    # Show the GUI\n    # import time\n    # gazebo.gui()\n    # gazebo.run(paused=True)\n    # time.sleep(3)\n\n    # Reset joint1 to its middle position\n    joint1 = panda.get_joint(\"panda_joint1\").to_gazebo()\n    joint1_range = np.abs(joint1.position_limit().max - joint1.position_limit().min)\n    joint1_middle = joint1.position_limit().min + joint1_range / 2\n    assert joint1.reset_position(joint1_middle)\n\n    # Reset joint6 to its middle position\n    joint6 = panda.get_joint(\"panda_joint6\").to_gazebo()\n    joint6_range = np.abs(joint6.position_limit().max - joint6.position_limit().min)\n    joint6_middle = joint6.position_limit().min + joint6_range / 2\n    assert joint6.reset_position(joint6_middle)\n\n    # Update the model state without stepping the physics\n    assert gazebo.run(paused=True)\n\n    # Set the controller period equal to the physics step (1000Hz)\n    panda.set_controller_period(gazebo.step_size())\n\n    # Check that we have gains for all joints\n    assert set(panda.joint_names()) == set(panda_pid_gains_1000Hz.keys())\n\n    # Set the PID gains\n    for joint_name, pid in panda_pid_gains_1000Hz.items():\n        assert panda.get_joint(joint_name).set_pid(pid=pid)\n\n    # Switch to position control mode (it sets the current position as active target)\n    assert panda.set_joint_control_mode(core.JointControlMode_position)\n    assert panda.joint_position_targets() == pytest.approx(panda.joint_positions())\n\n    # Just fight gravity for a while\n    for _ in range(1_000):\n        assert gazebo.run()\n\n    # Check that it didn't move\n    assert panda.joint_positions() == pytest.approx(\n        panda.joint_position_targets(), abs=np.deg2rad(1)\n    )\n\n    # joint1 trajectory\n    q0_joint1 = joint1.position()\n    q_joint1 = (\n        0.9 * joint1_range / 2 * np.sin(2 * np.pi * 0.33 * t)\n        for t in np.arange(start=0, stop=10.0, step=gazebo.step_size())\n    )\n\n    # joint6 trajectory\n    q0_joint6 = joint6.position()\n    q_joint6 = (\n        0.9 * joint6_range / 2 * np.sin(2 * np.pi * 0.33 * t)\n        for t in np.arange(start=0, stop=10.0, step=gazebo.step_size())\n    )\n\n    for _ in range(5_000):\n\n        # Generate the new references\n        joint1_reference = q0_joint1 + next(q_joint1)\n        joint6_reference = q0_joint6 + next(q_joint6)\n\n        # Set the new references\n        assert joint1.set_position_target(position=joint1_reference)\n        assert joint6.set_position_target(position=joint6_reference)\n\n        # Run the simulation\n        assert gazebo.run()\n\n        # Check that trajectory is being followed\n        assert joint1.position() == pytest.approx(joint1_reference, abs=np.deg2rad(3))\n        assert joint6.position() == pytest.approx(joint6_reference, abs=np.deg2rad(3))\n"
  },
  {
    "path": "tests/test_scenario/test_velocity_direct.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom typing import Tuple\n\nimport gym_ignition_models\nimport numpy as np\n\nfrom scenario import core as scenario_core\nfrom scenario import gazebo as scenario_gazebo\n\nfrom ..common.utils import default_world_fixture as default_world\n\n# Set the verbosity\nscenario_gazebo.set_verbosity(scenario_gazebo.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\"default_world\", [(1.0 / 1_000, 1.0, 1)], indirect=True)\ndef test_velocity_direct(\n    default_world: Tuple[scenario_gazebo.GazeboSimulator, scenario_gazebo.World]\n):\n\n    # Get the simulator and the world\n    gazebo, world = default_world\n\n    # Get the URDF model\n    pendulum_urdf = gym_ignition_models.get_model_file(\"pendulum\")\n\n    # Insert a pendulum model\n    assert world.insert_model(pendulum_urdf)\n    assert \"pendulum\" in world.model_names()\n\n    # Get the model and cast it to Gazebo\n    pendulum = world.get_model(\"pendulum\").to_gazebo()\n\n    # Disable any velocity (and torque) limits of the model, otherwise the velocity\n    # cannot change too abruptly\n    _ = [j.set_velocity_limit(np.finfo(float).max) for j in pendulum.joints()]\n    _ = [j.set_max_generalized_force(np.finfo(float).max) for j in pendulum.joints()]\n\n    # Add some friction\n    assert pendulum.get_joint(\"pivot\").to_gazebo().set_coulomb_friction(value=0.01)\n    assert pendulum.get_joint(\"pivot\").to_gazebo().set_viscous_friction(value=0.2)\n\n    # Show the GUI\n    # import time\n    # gazebo.gui()\n    # time.sleep(2)\n\n    # Get the pivot joint\n    assert \"pivot\" in pendulum.joint_names()\n    pivot = pendulum.get_joint(joint_name=\"pivot\")\n\n    # Reset the joint to 90 degs and make it swing\n    assert pivot.to_gazebo().reset_position(position=np.deg2rad(90))\n    [gazebo.run() for _ in range(5_000)]\n\n    # It should rest in its stable equilibrium point\n    assert np.deg2rad(179.7) <= pivot.position() <= np.deg2rad(180.3)\n\n    # Control the joint in velocity direct\n    assert pivot.set_control_mode(\n        mode=scenario_core.JointControlMode_velocity_follower_dart\n    )\n\n    # Set the velocity reference to 3.14 rad / s\n    assert pivot.set_velocity_target(velocity=np.pi)\n\n    # The target should be reached after just one run\n    assert gazebo.run()\n    assert pivot.velocity() == pytest.approx(np.pi)\n\n    # Simulate for a while\n    [gazebo.run() for _ in range(1_500)]\n\n    # Check again\n    assert pivot.velocity() == pytest.approx(np.pi)\n\n    # Change direction abruptly\n    assert pivot.set_velocity_target(velocity=-np.pi)\n    assert gazebo.run()\n    assert pivot.velocity() == pytest.approx(-np.pi)\n\n    # Go in idle and make it swing\n    assert pivot.set_control_mode(mode=scenario_core.JointControlMode_idle)\n    [gazebo.run() for _ in range(5_000)]\n\n    # It should rest in its stable equilibrium point\n    assert (\n        2 * np.pi + np.deg2rad(179.7)\n        <= pivot.position()\n        <= 2 * np.pi + np.deg2rad(180.3)\n    )\n"
  },
  {
    "path": "tests/test_scenario/test_world.py",
    "content": "# Copyright (C) 2020 Istituto Italiano di Tecnologia (IIT). All rights reserved.\n# This software may be modified and distributed under the terms of the\n# GNU Lesser General Public License v2.1 or any later version.\n\nimport pytest\n\npytestmark = pytest.mark.scenario\n\nfrom scenario import core\nfrom scenario import gazebo as scenario\n\nfrom ..common import utils\nfrom ..common.utils import gazebo_fixture as gazebo\n\n# Set the verbosity\nscenario.set_verbosity(scenario.Verbosity_debug)\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_load_default_world(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    assert world.id() != 0\n    assert world.time() == 0.0\n    assert world.name() == \"default\"\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_load_default_world_from_file(gazebo: scenario.GazeboSimulator):\n\n    empty_world_sdf = utils.get_empty_world_sdf()\n\n    assert gazebo.insert_world_from_sdf(empty_world_sdf)\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    assert world.id() != 0\n    assert world.time() == 0.0\n    assert world.name() == \"default\"\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_rename_default_world(gazebo: scenario.GazeboSimulator):\n\n    empty_world_sdf = utils.get_empty_world_sdf()\n    assert gazebo.insert_world_from_sdf(empty_world_sdf, \"myWorld\")\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    assert world.id() != 0\n    assert world.time() == 0.0\n    assert world.name() == \"myWorld\"\n\n    world1 = gazebo.get_world(\"myWorld\")\n\n    assert world1.id() == world.id()\n    assert world1.time() == 0.0\n    assert world1.name() == \"myWorld\"\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_world_api(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    gravity = [0, 0, 10.0]\n    assert world.set_gravity(gravity)\n    assert world.gravity() == pytest.approx(gravity)\n\n    assert len(world.model_names()) == 0\n\n    # Insert a model from an non existent file\n    assert not world.insert_model(\"\")\n\n    # Insert first cube with default name and pose\n    cube_urdf = utils.get_cube_urdf()\n    assert world.insert_model(cube_urdf)\n    assert len(world.model_names()) == 1\n\n    default_model_name = scenario.get_model_name_from_sdf(cube_urdf)\n    assert default_model_name in world.model_names()\n    cube1 = world.get_model(default_model_name)\n    # TODO: assert cube1\n\n    assert cube1.name() == default_model_name\n    assert cube1.base_position() == pytest.approx([0, 0, 0])\n    assert cube1.base_orientation() == pytest.approx([1, 0, 0, 0])\n\n    # Inserting a model with the same name should fail\n    assert not world.insert_model(cube_urdf)\n    assert len(world.model_names()) == 1\n\n    # Insert second cube with custom name and pose\n    custom_model_name = \"other_cube\"\n    assert custom_model_name != default_model_name\n    custom_model_pose = core.Pose([1, 1, 0], [0, 0, 0, 1])\n\n    assert world.insert_model(cube_urdf, custom_model_pose, custom_model_name)\n    assert custom_model_name in world.model_names()\n    assert len(world.model_names()) == 2\n\n    cube2 = world.get_model(custom_model_name)\n    assert cube1 != cube2\n    # TODO: assert cube2\n\n    assert cube2.name() == custom_model_name\n    assert cube2.base_position() == pytest.approx(custom_model_pose.position)\n    assert cube2.base_orientation() == pytest.approx(custom_model_pose.orientation)\n\n    # insert a cube from urdf string\n    cube_3_pose = core.Pose([1, 0, 0], [0, 0, 0, 1])\n    assert world.insert_model_from_string(\n        utils.get_cube_urdf_string(), cube_3_pose, \"cube3\"\n    )\n    assert \"cube3\" in world.model_names()\n\n    # insert a cube from sdf string\n    cube_4_pose = core.Pose([2, 0, 0], [0, 0, 0, 1])\n    assert world.insert_model_from_string(\n        utils.get_cube_sdf_string(), cube_4_pose, \"cube4\"\n    )\n    assert \"cube4\" in world.model_names()\n\n    # Remove the first model (requires either a paused or unpaused step)\n    assert world.remove_model(default_model_name)\n    assert len(world.model_names()) == 4\n    gazebo.run(paused=True)\n    assert len(world.model_names()) == 3\n\n    # Without the physics system, the time should not increase\n    gazebo.run()\n    gazebo.run()\n    gazebo.run()\n    assert world.time() == 0.0\n\n\n# See: https://github.com/robotology/gym-ignition/issues/366\n@pytest.mark.xfail(strict=False)\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_world_physics_plugin(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    dt = gazebo.step_size()\n\n    assert world.time() == 0\n\n    # Insert a cube\n    cube_urdf = utils.get_cube_urdf()\n    cube_name = \"my_cube\"\n    cube_pose = core.Pose([0, 0, 1.0], [1, 0, 0, 0])\n    assert world.insert_model(cube_urdf, cube_pose, cube_name)\n    assert cube_name in world.model_names()\n\n    cube = world.get_model(cube_name)\n\n    # There's no physics, the cube should not move\n    for _ in range(10):\n        gazebo.run()\n        assert cube.base_position() == cube_pose.position\n\n    assert world.time() == 0\n\n    # Insert the Physics system\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n\n    # After the first step, the physics catches up with time\n    gazebo.run()\n    assert world.time() == pytest.approx(11 * dt)\n\n    # The cube should start falling\n    assert cube.base_position()[2] < cube_pose.position[2]\n\n    gazebo.run()\n    assert world.time() == pytest.approx(12 * dt)\n\n    # Paused steps do not increase the time\n    gazebo.run(paused=True)\n    assert world.time() == pytest.approx(12 * dt)\n\n\n@pytest.mark.parametrize(\n    \"gazebo\", [(0.001, 1.0, 1), (1e-9, 1.0, 1)], indirect=True, ids=utils.id_gazebo_fn\n)\ndef test_sim_time_starts_from_zero(gazebo: scenario.GazeboSimulator):\n\n    assert gazebo.initialize()\n    world = gazebo.get_world()\n\n    dt = gazebo.step_size()\n\n    assert world.time() == 0\n    assert world.set_physics_engine(scenario.PhysicsEngine_dart)\n    assert world.time() == 0\n\n    gazebo.run(paused=True)\n    assert world.time() == 0\n\n    gazebo.run(paused=False)\n    assert world.time() == dt\n\n    gazebo.run(paused=False)\n    assert world.time() == 2 * dt\n\n    gazebo.run(paused=False)\n    assert world.time() == pytest.approx(3 * dt)\n"
  }
]