void add_paddle_constraints(ModifiedObjectReference& obj,
                              Quadtree& q) noexcept
  {
    for(const auto& node : find_containing_nodes(q.root(), obj.obj.volume))
    {
      for(id_type other_id : node->get_data()->ids)
      {
        if(other_id == obj.id) continue;

        const Object& other_obj = q.find_object(other_id);
        if(!isPaddle(other_obj)) continue;

        if(intersecting(obj.obj.volume, other_obj.volume))
        {
          VolumeSides cs = closest_side(obj.obj.volume, other_obj.volume);
          obj.obj.physics_options.constraints |= cs;
        }
      }
    }
  }
  void add_ball_constraints(ModifiedObjectReference& obj,
                            Quadtree& q) noexcept
  {
    for(const auto& node : find_containing_nodes(q.root(), obj.obj.volume))
    {
      for(id_type other_id : node->get_data()->ids)
      {
        if(other_id == obj.id) continue;

        Object& self = obj.obj;

        ModifiedObjectReference other_obj = {other_id,q.find_object(other_id)};
        if(!isBall(other_obj.obj)) continue;
        const Object& other = other_obj.obj;

        if(!intersecting(self.volume, other.volume)) continue;

        VolumeSides cs = closest_side(self.volume, other.volume);
        self.physics_options.constraints |=
                                      other.physics_options.constraints & cs;
      }
    }
  }