繁体   English   中英

如何在 yaml 文件中发出或编写地图地图? C++

[英]How to emit or write a map of maps in yaml file? c++

所以我有几个虚拟护目镜……每个都有不同的校准参数。 我决定将这些参数保存到一个 yaml 文件中(作为配置文件)……每个护目镜都有自己的序列号/识别号……然后根据这个编号,我选择要使用的那个。 如果没有预先保存的护目镜信息。 我校准它并将这些参数添加到文件中

所以现在我正在尝试写入一个如下所示的 yaml 文件:

Headset:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
  GyroOffset:
    GyroX:
      Value: -0.013776619
    GyroY:
      Value: -0.016475508
    GyroZ:
      Value: -0.0114268782

这就是我实际得到的:

Headset2:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
? GyroOffset:
    GyroX:
      Value: -0.013776619
  ? GyroY:
      Value: -0.016475508
  : GyroZ:
      Value: -0.0114268782

我不明白我做错了什么! .. 这是我写入 yaml 文件的函数:

void ParseInputDeviceYaml::addCalibrationToConfigFile(const char* identificationNumber, const float* in)
{
    try {
        std::ofstream updatedFile;
        updatedFile.open(m_filename.toStdString(), std::ios::app);

        std::map<std::string, std::string>                  IDNumber;
        std::map<std::string, std::map<std::string, float>> gyroXOffset;
        std::map<std::string, std::map<std::string, float>> gyroYOffset;
        std::map<std::string, std::map<std::string, float>> gyroZOffset;

        IDNumber["IdentificationNumber"] = identificationNumber;

        gyroXOffset["GyroX"]["Value"] = *in;
        gyroYOffset["GyroY"]["Value"] = *(in + 1);
        gyroZOffset["GyroZ"]["Value"] = *(in + 2);

        YAML::Emitter newNode;


        newNode << YAML::BeginMap;
        newNode << YAML::Key << "Headset2";
        newNode << YAML::Value << YAML::BeginMap << YAML::Key << "IdentificationNumber" << YAML::Value << identificationNumber << YAML::EndMap;
        newNode << YAML::BeginMap << YAML::Key << "GyroOffset" << YAML::Value << gyroXOffset << gyroYOffset << gyroZOffset << YAML::EndMap;
        newNode << YAML::EndMap;

        updatedFile << newNode.c_str() << "\n";

        updatedFile.close();
    } catch (std::exception& e) {
        LOG4CPLUS_FATAL(m_logger, e.what());
        throw std::runtime_error(QObject::tr("Writing gyroscope offsets ").toStdString());
    }
}

主要问题似乎是您建立在大量错误信息的基础上。 我会试着澄清一些事情:

  • 是否使用序列与能够修改现有值或向文件添加新值完全无关。 问题是您使用std::ios::app附加到文件,这将始终创建一个新条目。 相反,您应该将文件加载到 YAML 节点中,修改该节点的内容,然后写回整个节点。
  • 没有您提供的序列的 YAML 文件肯定不会按照您的想法执行,因为您放置? GyroOffset ? GyroOffset在同一深度为Headset2:使其成为同级Headset2 另请注意,在同一映射中将隐式 ( foo: ) 与显式 ( ? foo ) 键混合是一种极端情况,可能会混淆某些实现。 YAML 文件可以简单地如下所示:
Headset2:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
  GyroOffset:
    GyroX:
      Value: -0.012388126
    GyroY:
      Value: -0.0155748781
    GyroZ:
      Value: -0.0115196211

为了使您的代码更具可读性,我建议使用辅助类来访问您的值。 假设上面的代码是整个 YAML 文件,它可能如下所示:

struct Value {
  YAML::Node data;
  // access existing node
  explicit Value(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  // create new node
  explicit Value(float value) {
    data["Value"] = value;
  }

  float get() { return data["Value"].as<float>(); }
  void set(float value) { data["Value"] = value; }
};

struct GyroOffset {
  YAML::Node data;
  explicit GyroOffset(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  GyroOffset(float x, float y, float z) {
    data["GyroX"] = Value(x).data;
    data["GyroY"] = Value(y).data;
    data["GyroZ"] = Value(z).data;
  }
  Value gyroX() { return Value(data["GyroX"]); }
  Value gyroX() { return Value(data["GyroY"]); }
  Value gyroZ() { return Value(data["GyroZ"]); }
};

struct Headset {
  YAML::Node data;
  Headset(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  Headset(const char *id) {
    data["IdentificationNumber"] = id;
    // initialize with zero values
    data["GyroOffset"] = GyroOffset(0, 0, 0).data;
  }

  std::string id() { return data["IdentificationNumber"].as<std::string>(); }
  void setId(const char *value) { data["IdentificationNumber"] = value; }

  GyroOffset gyroOffset() { return GyroOffset(data["GyroOffset"]); }
}

现在,找到给定标识号的 GyroOffset 看起来像这样(我展示了一个简单的函数,因为我不知道您类的字段,因为您没有显示它们):

// write found values to output of found
bool findHedasetGyroOffset(Yaml::Node &input /* the file as shown above */, const char *id, GyroOffset &output) {
  for (auto it = input.begin(); it != input.end(); ++it) {
    Headset hs(it->second);
    if (hs.id() == id) {
      output = hs.gyroOffset();
      return true;
    }
  }
  return false;
}

由于YAML::Node基本上是一个引用,因此当您更改返回的GyroOffset值时,原始数据会发生变化。 然后,您可以将根节点写回文件(而不是附加它)并拥有一个更新的文件。

附加一个新耳机看起来像这样:

void addCalibrationToConfigFile(Yaml::Node &file, const char* identificationNumber, const float* in) {
  Headset newHs(identificationNumber);
  auto go = newHs.gyroOffset();
  go.gyroX().set(*in);
  go.gyroY().set(*(in + 1));
  go.gyroZ().set(*(in + 2));
  // note that this will overwrite an existing Headset2
  file["Headset2"] = newHs.data;
}

虽然我试图坚持你展示的结构,但我觉得映射中的实际键不应该是Headset2 ,而是 IdentificationNumber:

b630cc42-9a03-42da-a039-0e023cf5b090:
  Name: Headset2
  GyroOffset:
    GyroX:
      Value: -0.012388126
    GyroY:
      Value: -0.0155748781
    GyroZ:
      Value: -0.0115196211

由于您根据 ID 进行查找,这会更有意义。 此外,创建新配置实际上会起作用(目前,由于硬编码的"Headset2"值,如果存在,它将始终覆盖该耳机)。

当心,我写的代码只是作为演示,并没有测试它; 可能有错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM