void initSceneBindings()

in src/esp/bindings/SceneBindings.cpp [25:219]


void initSceneBindings(py::module& m) {
  // ==== SceneGraph ====

  // !!Warning!!
  // CANNOT apply smart pointers to "SceneNode" or ANY its descendant classes,
  // namely, any class whose instance can be a node in the scene graph. Reason:
  // Memory will be automatically handled in simulator (C++ backend). Using
  // smart pointers on scene graph node from Python code, will claim the
  // ownership and eventually free its resources, which leads to "duplicated
  // deallocation", and thus memory corruption.

  // ==== enum SceneNodeType ====
  py::enum_<SceneNodeType>(m, "SceneNodeType")
      .value("EMPTY", SceneNodeType::EMPTY)
      .value("SENSOR", SceneNodeType::SENSOR)
      .value("AGENT", SceneNodeType::AGENT)
      .value("CAMERA", SceneNodeType::CAMERA)
      .value("OBJECT", SceneNodeType::OBJECT);

  // ==== SceneNode ====
  py::class_<SceneNode, Magnum::SceneGraph::PyObject<SceneNode>, MagnumObject,
             Magnum::SceneGraph::PyObjectHolder<SceneNode>>(m, "SceneNode", R"(
      SceneNode: a node in the scene graph.

      Cannot apply a smart pointer to a SceneNode object.
      You can "create it and forget it".
      Simulator backend will handle the memory.)")
      .def(py::init_alias<std::reference_wrapper<SceneNode>>(),
           R"(Constructor: creates a scene node, and sets its parent.)")
      .def_property("type", &SceneNode::getType, &SceneNode::setType)
      .def_property("semantic_id", &SceneNode::getSemanticId,
                    &SceneNode::setSemanticId)
      .def(
          "create_child", [](SceneNode& self) { return &self.createChild(); },
          R"(Creates a child node, and sets its parent to the current node.)")
      .def("set_parent", &SceneNode::setParent,
           R"(Sets parent to parentNode, and updates ancestors' SensorSuites)")
      .def(
          "compute_cumulative_bb", &SceneNode::computeCumulativeBB,
          R"(Recursively compute the approximate axis aligned bounding boxes of the SceneGraph sub-tree rooted at this node.)")
      .def_property_readonly(
          "cumulative_bb", &SceneNode::getCumulativeBB,
          R"(The approximate axis aligned bounding box of the SceneGraph sub-tree rooted at this node.)")
      .def_property_readonly(
          "mesh_bb", &SceneNode::getMeshBB,
          R"(The axis aligned bounding box of the mesh drawables attached to this node.)")
      .def_property_readonly(
          "absolute_translation",
          py::overload_cast<>(&SceneNode::absoluteTranslation))
      .def_property_readonly(
          "absolute_translation",
          py::overload_cast<>(&SceneNode::absoluteTranslation, py::const_))
      .def_property_readonly("node_sensor_suite",
                             &SceneNode::getNodeSensorSuite,
                             R"(Get node SensorSuite of this SceneNode)")
      .def_property_readonly("subtree_sensor_suite",
                             &SceneNode::getSubtreeSensorSuite,
                             R"(Get subtree SensorSuite of this SceneNode)")
      .def_property_readonly("node_sensors", &SceneNode::getNodeSensors,
                             R"(Get node sensors of this SceneNode)")
      .def_property_readonly("subtree_sensors", &SceneNode::getSubtreeSensors,
                             R"(Get subtree sensors of this SceneNode)");

  py::class_<SceneGraph>(m, "SceneGraph")
      .def(py::init())
      .def("get_root_node",
           py::overload_cast<>(&SceneGraph::getRootNode, py::const_),
           R"(
            Get the root node of the scene graph.

            User can specify transformation of the root node w.r.t. the world
            frame. (const function) PYTHON DOES NOT GET OWNERSHIP)",
           pybind11::return_value_policy::reference)
      .def("get_root_node", py::overload_cast<>(&SceneGraph::getRootNode),
           R"(
            Get the root node of the scene graph.

            User can specify transformation of the root node w.r.t. the world
            frame. PYTHON DOES NOT GET OWNERSHIP)",
           pybind11::return_value_policy::reference);

  // ==== SceneManager ====
  py::class_<SceneManager>(m, "SceneManager")
      .def("init_scene_graph", &SceneManager::initSceneGraph,
           R"(
          Initialize a new scene graph, and return its ID.)")
      .def("get_scene_graph",
           py::overload_cast<int>(&SceneManager::getSceneGraph),
           R"(
             Get the scene graph by scene graph ID.

             PYTHON DOES NOT GET OWNERSHIP)",
           "sceneGraphID"_a, pybind11::return_value_policy::reference)
      .def("get_scene_graph",
           py::overload_cast<int>(&SceneManager::getSceneGraph, py::const_),
           R"(
             Get the scene graph by scene graph ID.

             PYTHON DOES NOT GET OWNERSHIP)",
           "sceneGraphID"_a, pybind11::return_value_policy::reference);

  // ==== SemanticCategory ====
  py::class_<SemanticCategory, SemanticCategory::ptr>(m, "SemanticCategory")
      .def("index", &SemanticCategory::index, "mapping"_a = "")
      .def("name", &SemanticCategory::name, "mapping"_a = "");

  // === Mp3dObjectCategory ===
  py::class_<Mp3dObjectCategory, SemanticCategory, Mp3dObjectCategory::ptr>(
      m, "Mp3dObjectCategory")
      .def("index", &Mp3dObjectCategory::index, "mapping"_a = "")
      .def("name", &Mp3dObjectCategory::name, "mapping"_a = "");

  // === Mp3dRegionCategory ===
  py::class_<Mp3dRegionCategory, SemanticCategory, Mp3dRegionCategory::ptr>(
      m, "Mp3dRegionCategory")
      .def("index", &Mp3dRegionCategory::index, "mapping"_a = "")
      .def("name", &Mp3dRegionCategory::name, "mapping"_a = "");

  // These two are (cyclically) referenced by multiple classes below, define
  // the classes first so pybind has the type definition available when binding
  // functions
  py::class_<SemanticObject, SemanticObject::ptr> semanticObject(
      m, "SemanticObject");
  py::class_<SemanticRegion, SemanticRegion::ptr> semanticRegion(
      m, "SemanticRegion");

  // ==== SemanticLevel ====
  py::class_<SemanticLevel, SemanticLevel::ptr>(m, "SemanticLevel")
      .def_property_readonly("id", &SemanticLevel::id)
      .def_property_readonly("aabb", &SemanticLevel::aabb)
      .def_property_readonly("regions", &SemanticLevel::regions)
      .def_property_readonly("objects", &SemanticLevel::objects);

  // ==== SemanticRegion ====
  semanticRegion
      .def_property_readonly(
          "id", &SemanticRegion::id,
          "The ID of the region, of the form ``<level_id>_<region_id>``")
      .def_property_readonly("level", &SemanticRegion::level)
      .def_property_readonly("aabb", &SemanticRegion::aabb)
      .def_property_readonly("category", &SemanticRegion::category,
                             "The semantic category of the region")
      .def_property_readonly("objects", &SemanticRegion::objects,
                             "All objects in the region");

  // ==== SemanticObject ====
  semanticObject
      .def_property_readonly("id", &SemanticObject::id,
                             "The ID of the object, of the form "
                             "``<level_id>_<region_id>_<object_id>``")
      .def_property_readonly("semantic_id", &SemanticObject::semanticID)
      .def_property_readonly("region", &SemanticObject::region)
      .def_property_readonly("aabb", &SemanticObject::aabb)
      .def_property_readonly("obb", &SemanticObject::obb)
      .def_property_readonly("category", &SemanticObject::category);

  // ==== SemanticScene ====
  py::class_<SemanticScene, SemanticScene::ptr>(m, "SemanticScene")
      .def(py::init(&SemanticScene::create<>))
      .def_static(
          "load_mp3d_house",
          [](const std::string& filename, SemanticScene& scene,
             const vec4f& rotation) {
            // numpy doesn't have a quaternion equivalent, use vec4
            // instead
            return SemanticScene::loadMp3dHouse(
                filename, scene, Eigen::Map<const quatf>(rotation.data()));
          },
          R"(
        Loads a SemanticScene from a Matterport3D House format file into passed
        `SemanticScene`.
      )",
          "file"_a, "scene"_a, "rotation"_a)
      .def_property_readonly("aabb", &SemanticScene::aabb)
      .def_property_readonly("categories", &SemanticScene::categories,
                             "All semantic categories in the house")
      .def_property_readonly("levels", &SemanticScene::levels,
                             "All levels in the house")
      .def_property_readonly("regions", &SemanticScene::regions,
                             "All regions in the house")
      .def_property_readonly("objects", &SemanticScene::objects,
                             "All object in the house")
      .def_property_readonly("semantic_index_map",
                             &SemanticScene::getSemanticIndexMap)
      .def("semantic_index_to_object_index",
           &SemanticScene::semanticIndexToObjectIndex);

  // ==== ObjectControls ====
  py::class_<ObjectControls, ObjectControls::ptr>(m, "ObjectControls")
      .def(py::init(&ObjectControls::create<>))
      .def("action", &ObjectControls::action, R"(
        Take action using this :py:class:`ObjectControls`.
      )",
           "object"_a, "name"_a, "amount"_a, "apply_filter"_a = true);
}