<commit_before>/* Copyright 2017 The Apollo Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "modules/map/hdmap/adapter/xml_parser/lanes_xml_parser.h"

#include <algorithm>
#include <string>
#include <vector>

#include "modules/map/hdmap/adapter/xml_parser/util_xml_parser.h"

namespace {
double ToMPS(double speed) { return speed * 1000.0 / 3600.0; }
bool IsReferenceLane(int lane_id) { return lane_id == 0; }
};

namespace apollo {
namespace hdmap {
namespace adapter {

Status LanesXmlParser::Parse(const tinyxml2::XMLElement& xml_node,
                             const std::string& road_id,
                             std::vector<RoadSectionInternal>* sections) {
  CHECK_NOTNULL(sections);
  const auto lanes_node = xml_node.FirstChildElement("lanes");
  CHECK_NOTNULL(lanes_node);
  const tinyxml2::XMLElement* sub_node =
      lanes_node->FirstChildElement("laneSection");
  CHECK_NOTNULL(sub_node);

  size_t section_cnt = 0;
  while (sub_node) {
    RoadSectionInternal section_internal;
    std::string section_id = std::to_string(++section_cnt);
    section_internal.id = section_id;
    section_internal.section.mutable_id()->set_id(section_id);
    RETURN_IF_ERROR(ParseLaneSection(*sub_node,
                                     &section_internal.lanes));
    RETURN_IF_ERROR(ParseSectionBoundary(
        *sub_node,
        section_internal.section.mutable_boundary()->mutable_outer_polygon()));
    sections->push_back(section_internal);

    sub_node = sub_node->NextSiblingElement("laneSection");
  }

  CHECK_GT(sections->size(), 0);

  return Status::OK();
}

Status LanesXmlParser::ParseSectionBoundary(
    const tinyxml2::XMLElement& xml_node, PbBoundaryPolygon* boundary) {
  CHECK_NOTNULL(boundary);

  auto boundaries_node = xml_node.FirstChildElement("boundaries");
  if (boundaries_node == nullptr) {
    std::string err_msg = "Error parse boundaries";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }

  auto sub_node = boundaries_node->FirstChildElement("boundary");
  while (sub_node) {
    PbBoundaryEdge* boundary_edge = boundary->add_edge();
    RETURN_IF_ERROR(
        UtilXmlParser::ParseCurve(*sub_node, boundary_edge->mutable_curve()));
    std::string type;
    int checker = UtilXmlParser::QueryStringAttribute(*sub_node, "type", &type);
    if (checker != tinyxml2::XML_SUCCESS) {
      std::string err_msg = "Error parse boundary type";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    PbBoundaryEdgeType boundary_type;
    RETURN_IF_ERROR(ToPbBoundaryType(type, &boundary_type));
    boundary_edge->set_type(boundary_type);

    sub_node = sub_node->NextSiblingElement("boundary");
  }

  return Status::OK();
}

Status LanesXmlParser::ToPbBoundaryType(const std::string& type,
                                        PbBoundaryEdgeType* boundary_type) {
  CHECK_NOTNULL(boundary_type);

  std::string upper_type = UtilXmlParser::ToUpper(type);

  if (upper_type == "LEFTBOUNDARY") {
    *boundary_type = hdmap::BoundaryEdge::LEFT_BOUNDARY;
  } else if (upper_type == "RIGHTBOUNDARY") {
    *boundary_type = hdmap::BoundaryEdge::RIGHT_BOUNDARY;
  } else {
    *boundary_type = hdmap::BoundaryEdge::NORMAL;
  }

  return Status::OK();
}

Status LanesXmlParser::ParseLaneSection(const tinyxml2::XMLElement& xml_node,
                                        std::vector<LaneInternal>* lanes) {
  CHECK_NOTNULL(lanes);

  // left
  const tinyxml2::XMLElement* sub_node = xml_node.FirstChildElement("left");
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("lane");
    while (sub_node) {
      LaneInternal lane_internal;
      RETURN_IF_ERROR(ParseLane(*sub_node, &lane_internal));
      *(lane_internal.lane.mutable_left_boundary()) =
          lane_internal.lane.right_boundary();
      lane_internal.lane.clear_right_boundary();
      if (lanes->size() > 0) {
        PbLane& left_neighbor_lane = lanes->back().lane;
        *(left_neighbor_lane.mutable_right_boundary()) =
            lane_internal.lane.left_boundary();
      }
      lanes->push_back(lane_internal);
      sub_node = sub_node->NextSiblingElement("lane");
    }
  }

  // center
  LaneInternal reference_lane_internal;
  sub_node = xml_node.FirstChildElement("center");
  CHECK_NOTNULL(sub_node);
  sub_node = sub_node->FirstChildElement("lane");
  CHECK_NOTNULL(sub_node);
  RETURN_IF_ERROR(ParseLane(*sub_node, &reference_lane_internal));
  *(reference_lane_internal.lane.mutable_left_boundary()) =
      reference_lane_internal.lane.right_boundary();
  if (lanes->size() > 0) {
    PbLane& left_neighbor_lane = lanes->back().lane;
    *(left_neighbor_lane.mutable_right_boundary()) =
        reference_lane_internal.lane.left_boundary();
  }

  // right
  sub_node = xml_node.FirstChildElement("right");
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("lane");
    PbLane* left_neighbor_lane = &reference_lane_internal.lane;
    while (sub_node) {
      // PbLane lane
      LaneInternal lane_internal;
      RETURN_IF_ERROR(ParseLane(*sub_node, &lane_internal));
      *(lane_internal.lane.mutable_left_boundary()) =
          left_neighbor_lane->right_boundary();
      lanes->push_back(lane_internal);
      left_neighbor_lane = &lanes->back().lane;
      sub_node = sub_node->NextSiblingElement("lane");
    }
  }
  return Status::OK();
}

Status LanesXmlParser::ParseLane(const tinyxml2::XMLElement& xml_node,
                                 LaneInternal* lane_internal) {
  CHECK_NOTNULL(lane_internal);

  PbLane* lane = &lane_internal->lane;
  // lane id
  int id = 0;
  int checker = xml_node.QueryIntAttribute("id", &id);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane id";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  std::string lane_id;
  checker = UtilXmlParser::QueryStringAttribute(xml_node, "uid", &lane_id);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane uid";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  lane->mutable_id()->set_id(lane_id);

  // lane type
  std::string lane_type;
  checker = UtilXmlParser::QueryStringAttribute(xml_node, "type", &lane_type);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane type.";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  PbLaneType pb_lane_type;
  Status success = ToPbLaneType(lane_type, &pb_lane_type);
  if (!success.ok()) {
    std::string err_msg = "Error convert lane type to pb lane type.";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  lane->set_type(pb_lane_type);

  // border
  const tinyxml2::XMLElement* sub_node = xml_node.FirstChildElement("border");
  if (sub_node) {
    PbLaneBoundary* lane_boundary = lane->mutable_right_boundary();
    CHECK(lane_boundary != nullptr);
    success =
        UtilXmlParser::ParseCurve(*sub_node, lane_boundary->mutable_curve());
    if (!success.ok()) {
      std::string err_msg = "Error parse lane border";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    lane_boundary->set_length(
        UtilXmlParser::CurveLength(*lane_boundary->mutable_curve()));
  }

  // road mark
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("borderType");
  }
  while (sub_node) {
    PbLaneBoundary* lane_boundary = lane->mutable_right_boundary();
    PbLaneBoundaryTypeType boundary_type;
    success = ParseLaneBorderMark(*sub_node, &boundary_type);
    if (!success.ok()) {
      std::string err_msg = "Error parse lane border type";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    double s_offset = 0.0;
    checker = sub_node->QueryDoubleAttribute("sOffset", &s_offset);
    if (checker != tinyxml2::XML_SUCCESS) {
      std::string err_msg = "Error parse lane boundary type offset.";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);<commit_msg>add virtual attribute for lane border (#1775)<commit_after>/* Copyright 2017 The Apollo Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "modules/map/hdmap/adapter/xml_parser/lanes_xml_parser.h"

#include <algorithm>
#include <string>
#include <vector>

#include "modules/map/hdmap/adapter/xml_parser/util_xml_parser.h"

namespace {
double ToMPS(double speed) { return speed * 1000.0 / 3600.0; }
bool IsReferenceLane(int lane_id) { return lane_id == 0; }
};

namespace apollo {
namespace hdmap {
namespace adapter {

Status LanesXmlParser::Parse(const tinyxml2::XMLElement& xml_node,
                             const std::string& road_id,
                             std::vector<RoadSectionInternal>* sections) {
  CHECK_NOTNULL(sections);
  const auto lanes_node = xml_node.FirstChildElement("lanes");
  CHECK_NOTNULL(lanes_node);
  const tinyxml2::XMLElement* sub_node =
      lanes_node->FirstChildElement("laneSection");
  CHECK_NOTNULL(sub_node);

  size_t section_cnt = 0;
  while (sub_node) {
    RoadSectionInternal section_internal;
    std::string section_id = std::to_string(++section_cnt);
    section_internal.id = section_id;
    section_internal.section.mutable_id()->set_id(section_id);
    RETURN_IF_ERROR(ParseLaneSection(*sub_node,
                                     &section_internal.lanes));
    RETURN_IF_ERROR(ParseSectionBoundary(
        *sub_node,
        section_internal.section.mutable_boundary()->mutable_outer_polygon()));
    sections->push_back(section_internal);

    sub_node = sub_node->NextSiblingElement("laneSection");
  }

  CHECK_GT(sections->size(), 0);

  return Status::OK();
}

Status LanesXmlParser::ParseSectionBoundary(
    const tinyxml2::XMLElement& xml_node, PbBoundaryPolygon* boundary) {
  CHECK_NOTNULL(boundary);

  auto boundaries_node = xml_node.FirstChildElement("boundaries");
  if (boundaries_node == nullptr) {
    std::string err_msg = "Error parse boundaries";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }

  auto sub_node = boundaries_node->FirstChildElement("boundary");
  while (sub_node) {
    PbBoundaryEdge* boundary_edge = boundary->add_edge();
    RETURN_IF_ERROR(
        UtilXmlParser::ParseCurve(*sub_node, boundary_edge->mutable_curve()));
    std::string type;
    int checker = UtilXmlParser::QueryStringAttribute(*sub_node, "type", &type);
    if (checker != tinyxml2::XML_SUCCESS) {
      std::string err_msg = "Error parse boundary type";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    PbBoundaryEdgeType boundary_type;
    RETURN_IF_ERROR(ToPbBoundaryType(type, &boundary_type));
    boundary_edge->set_type(boundary_type);

    sub_node = sub_node->NextSiblingElement("boundary");
  }

  return Status::OK();
}

Status LanesXmlParser::ToPbBoundaryType(const std::string& type,
                                        PbBoundaryEdgeType* boundary_type) {
  CHECK_NOTNULL(boundary_type);

  std::string upper_type = UtilXmlParser::ToUpper(type);

  if (upper_type == "LEFTBOUNDARY") {
    *boundary_type = hdmap::BoundaryEdge::LEFT_BOUNDARY;
  } else if (upper_type == "RIGHTBOUNDARY") {
    *boundary_type = hdmap::BoundaryEdge::RIGHT_BOUNDARY;
  } else {
    *boundary_type = hdmap::BoundaryEdge::NORMAL;
  }

  return Status::OK();
}

Status LanesXmlParser::ParseLaneSection(const tinyxml2::XMLElement& xml_node,
                                        std::vector<LaneInternal>* lanes) {
  CHECK_NOTNULL(lanes);

  // left
  const tinyxml2::XMLElement* sub_node = xml_node.FirstChildElement("left");
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("lane");
    while (sub_node) {
      LaneInternal lane_internal;
      RETURN_IF_ERROR(ParseLane(*sub_node, &lane_internal));
      *(lane_internal.lane.mutable_left_boundary()) =
          lane_internal.lane.right_boundary();
      lane_internal.lane.clear_right_boundary();
      if (lanes->size() > 0) {
        PbLane& left_neighbor_lane = lanes->back().lane;
        *(left_neighbor_lane.mutable_right_boundary()) =
            lane_internal.lane.left_boundary();
      }
      lanes->push_back(lane_internal);
      sub_node = sub_node->NextSiblingElement("lane");
    }
  }

  // center
  LaneInternal reference_lane_internal;
  sub_node = xml_node.FirstChildElement("center");
  CHECK_NOTNULL(sub_node);
  sub_node = sub_node->FirstChildElement("lane");
  CHECK_NOTNULL(sub_node);
  RETURN_IF_ERROR(ParseLane(*sub_node, &reference_lane_internal));
  *(reference_lane_internal.lane.mutable_left_boundary()) =
      reference_lane_internal.lane.right_boundary();
  if (lanes->size() > 0) {
    PbLane& left_neighbor_lane = lanes->back().lane;
    *(left_neighbor_lane.mutable_right_boundary()) =
        reference_lane_internal.lane.left_boundary();
  }

  // right
  sub_node = xml_node.FirstChildElement("right");
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("lane");
    PbLane* left_neighbor_lane = &reference_lane_internal.lane;
    while (sub_node) {
      // PbLane lane
      LaneInternal lane_internal;
      RETURN_IF_ERROR(ParseLane(*sub_node, &lane_internal));
      *(lane_internal.lane.mutable_left_boundary()) =
          left_neighbor_lane->right_boundary();
      lanes->push_back(lane_internal);
      left_neighbor_lane = &lanes->back().lane;
      sub_node = sub_node->NextSiblingElement("lane");
    }
  }
  return Status::OK();
}

Status LanesXmlParser::ParseLane(const tinyxml2::XMLElement& xml_node,
                                 LaneInternal* lane_internal) {
  CHECK_NOTNULL(lane_internal);

  PbLane* lane = &lane_internal->lane;
  // lane id
  int id = 0;
  int checker = xml_node.QueryIntAttribute("id", &id);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane id";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  std::string lane_id;
  checker = UtilXmlParser::QueryStringAttribute(xml_node, "uid", &lane_id);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane uid";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  lane->mutable_id()->set_id(lane_id);

  // lane type
  std::string lane_type;
  checker = UtilXmlParser::QueryStringAttribute(xml_node, "type", &lane_type);
  if (checker != tinyxml2::XML_SUCCESS) {
    std::string err_msg = "Error parse lane type.";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  PbLaneType pb_lane_type;
  Status success = ToPbLaneType(lane_type, &pb_lane_type);
  if (!success.ok()) {
    std::string err_msg = "Error convert lane type to pb lane type.";
    return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
  }
  lane->set_type(pb_lane_type);

  // border
  const tinyxml2::XMLElement* sub_node = xml_node.FirstChildElement("border");
  if (sub_node) {
    PbLaneBoundary* lane_boundary = lane->mutable_right_boundary();
    CHECK(lane_boundary != nullptr);
    success =
        UtilXmlParser::ParseCurve(*sub_node, lane_boundary->mutable_curve());
    if (!success.ok()) {
      std::string err_msg = "Error parse lane border";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    lane_boundary->set_length(
        UtilXmlParser::CurveLength(*lane_boundary->mutable_curve()));

    bool is_virtual = false;
    std::string virtual_border = "FALSE";
    checker = UtilXmlParser::QueryStringAttribute(*sub_node, "virtual",
            &virtual_border);
    if (checker == tinyxml2::XML_SUCCESS) {
      if (virtual_border == "TRUE") {
        is_virtual = true;
      }
    }
    lane_boundary->set_virtual_(is_virtual);
  }

  // road mark
  if (sub_node) {
    sub_node = sub_node->FirstChildElement("borderType");
  }
  while (sub_node) {
    PbLaneBoundary* lane_boundary = lane->mutable_right_boundary();
    PbLaneBoundaryTypeType boundary_type;
    success = ParseLaneBorderMark(*sub_node, &boundary_type);
    if (!success.ok()) {
      std::string err_msg = "Error parse lane border type";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
    }
    double s_offset = 0.0;
    checker = sub_node->QueryDoubleAttribute("sOffset", &s_offset);
    if (checker != tinyxml2::XML_SUCCESS) {
      std::string err_msg = "Error parse lane boundary type offset.";
      return Status(apollo::common::ErrorCode::HDMAP_DATA_ERROR, err_msg);
{'fraction_non_alphanumeric': 0.1284674852205548, 'fraction_numerical': 0.004604365620736698, 'mean_word_length': 4.257919904363419, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 88, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 59}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5041120', 'n_tokens_mistral': 5681, 'n_tokens_neox': 5546, 'n_words': 1026}