/*------------------------------------------------------------------------------ * Copyright (c) 2023 by Bai Bing (seread@163.com) * See COPYING file for copying and redistribution conditions. * * Alians IT Studio. *----------------------------------------------------------------------------*/ #pragma once #include #include #include #include #include #include #include #include #include "_Define.h" #include "core/UUID.h" #include "utils/Misc.h" #include "ASPoint.h" namespace ais { template class AIS_EXPORT Discontinuity { public: Discontinuity() = default; Discontinuity(const char *name_, std::vector points_) : name(name_), points(points_) { build_polygon_box(); }; Discontinuity(const char *contents) { std::istringstream ss(contents); std::vector lines; for (std::string line; std::getline(ss, line);) { if (!line.empty()) lines.emplace_back(line); } if (!lines.empty()) { auto header = lines[0]; auto tokens = ais::str_split_all(header, ","); size_t pointCount = std::atoi(tokens[0].c_str()); bool nodataFlags = bool(std::atoi(tokens[1].c_str())); if (pointCount == lines.size() - 1) { // ensure the header information is correct name = tokens.size() > 2 ? tokens[2] : ais::uuid(); for (int i = 0; i < pointCount; i++) { points.emplace_back(PT(lines[i + 1].c_str())); } } } build_polygon_box(); } ~Discontinuity() = default; inline virtual std::string type() const { return "Discontinuity"; } std::string name; std::vector points; std::vector polygon; // points which can contain an enclosed polygon std::vector box; // outside box which to help quickly test for grid iteration void build_polygon_box() { // build the polygon points if exists auto i = points.begin(); auto di = points.end(); for (; i < di; ++i) { for (auto j = i + 1; j != di; ++j) { if (*i == *j) { di = j; break; } } if (di != points.end()) { // the polygon begin and end point are same for an enclosed area polygon = std::vector(i, di + 1); break; } } // build box for quick test if (!points.empty()) { auto xMinMax = getMinMax(getAxisValues(points, Axis3DType::X)); auto yMinMax = getMinMax(getAxisValues(points, Axis3DType::Y)); box = std::vector{ {xMinMax.first, yMinMax.first}, {xMinMax.first, yMinMax.second}, {xMinMax.second, yMinMax.second}, {xMinMax.second, yMinMax.first}, {xMinMax.first, yMinMax.first}, }; } } const std::string str() const { std::stringstream ss; ss << type() << ": " << name << std::endl; ss << "-----------------------------------------------" << std::endl; for (auto &p : points) { ss << p; if (std::find(points.begin(), points.end(), p) != points.end()) ss << " P"; ss << std::endl; } return ss.str(); } }; template class AIS_EXPORT DiscontinuityFile { public: DiscontinuityFile() = default; DiscontinuityFile(const char *filename) { try { load(filename); } catch (const std::exception &e) { std::cerr << "Error loading " << filename << ", " << e.what() << std::endl; } } //============================================================================ /// /// @param filename /// /// @return count of loaded breaklines /// virtual size_t load(const char *filename) { size_t lineCount = 0; std::filesystem::path path(filename); if (!std::filesystem::exists(filename)) { std::string msg(filename); msg += " is not existed!"; THROW_INVALID_ARGUMENT(msg.c_str()); } std::string ext = path.extension().string(); ext = ais::tolower(ext); if (ext == ".bln") { lineCount = load_bln_file(filename); } else if (ext == ".dfd") { lineCount = load_dfd_file(filename); } else { lineCount = load_dat_file(filename); } return lineCount; } inline virtual void clear() { discontinuities.clear(); }; ais::Discontinuity &operator[](const char *name) const { return discontinuities[name]; }; std::map> discontinuities; private: virtual size_t load_bln_file(const char *filename) { std::ifstream file(filename); if (!file.good()) { std::string msg("Can't open file "); msg += filename; THROW_INVALID_ARGUMENT(msg.c_str()); } bool inLine = false; std::smatch m; std::regex regHeader("^([\\d]+),([\\d]?)(.*?)$"); std::regex regexLine("([\\d\\-\\.]+)"); std::stringstream ss; std::string line = ""; while (getline(file, line)) { if (line[0] == '#' || line.empty()) { // close current line information inLine = false; // transfer line informaiton auto s = ss.str(); if (s.empty()) continue; ais::Discontinuity discontinuity(s.c_str()); if (!discontinuity.points.empty()) { discontinuities[discontinuity.name] = discontinuity; } ss.str(""); // skip comments and empty lines continue; } if (!inLine && std::regex_match(line, m, regHeader)) { // capture header line inLine = true; ss << line << std::endl; continue; } if (inLine && std::regex_search(line, m, regexLine)) { ss << line << std::endl; continue; } } // for finally line auto s = ss.str(); if (!s.empty()) { ais::Discontinuity discontinuity(s.c_str()); if (!discontinuity.points.empty()) { discontinuities[discontinuity.name] = discontinuity; } } return discontinuities.size(); } virtual size_t load_dfd_file(const char *filename) { std::ifstream file(filename); if (!file.good()) { std::string msg("Can't open file "); msg += filename; THROW_INVALID_ARGUMENT(msg.c_str()); } std::vector skipRegexStrings = {"version", "HowToViewCurve", "Property", "Solid", "NoDraw", "#", "NameIn", "Times_New_Roman"}; bool inLine = false; std::stringstream ss; ss << std::fixed << std::setprecision(4); std::string line = ""; size_t linePointCount = 0; std::string lineName; while (getline(file, line)) { std::smatch m; for (auto &rex : skipRegexStrings) { std::regex r(rex, std::regex_constants::icase); if (std::regex_search(line, m, r)) { // skip comments and empty lines continue; } } std::regex regexHeader("^pline(.*)", std::regex_constants::icase); if (std::regex_search(line, m, regexHeader)) { // line start inLine = true; lineName = m[1].str().substr(1); linePointCount = 0; ss.str(std::string()); continue; } std::regex regexLine("([\\d\\-\\.]+)"); if (inLine && std::regex_search(line, m, regexLine)) { // line point information ss << line << std::endl; linePointCount++; continue; } if (inLine && line.empty()) { // line end and build discontinuity informaiton std::string s = std::to_string(linePointCount) + ",1," + lineName + "\n"; s += ss.str(); // reset line information inLine = false; linePointCount = 0; lineName = ""; ss.str(std::string()); // covert discontinuity to object ais::Discontinuity discontinuity(s.c_str()); if (!discontinuity.points.empty()) { discontinuities.emplace(discontinuity.name, discontinuity); } } } return discontinuities.size(); } virtual size_t load_dat_file(const char *filename) { std::ifstream file(filename); if (!file.good()) { std::string msg("Can't open file "); msg += filename; THROW_INVALID_ARGUMENT(msg.c_str()); } bool inLine = false; std::stringstream ss; ss << std::fixed << std::setprecision(4); std::string line = ""; size_t linePointCount = 0; std::string lineName; while (getline(file, line)) { if (line[0] == '#' || line.empty()) { // skip comments and empty lines continue; } auto tokens = ais::str_split_all(line, " "); double x = 0, y = 0; std::string flag; std::string name; if (tokens.size() != 4) { // skip line which may incorrectly continue; } // line infomation x = std::stod(tokens[0]); y = std::stod(tokens[1]); flag = tokens[2]; name = tokens[3]; if (!inLine && flag == "6") { // line start inLine = true; lineName = name; ss.str(std::string()); // put point to line content ss << x << "," << y << std::endl; linePointCount = 1; } else if (inLine && flag == "7" && name == lineName) { // in line, put point to line content ss << x << "," << y << std::endl; linePointCount++; } else if (inLine && flag == "8" && name == lineName) { // line stop ss << x << "," << y << std::endl; linePointCount++; inLine = false; // build discontinuity informaiton std::string s = std::to_string(linePointCount) + ",1," + lineName + "\n"; s += ss.str(); // reset line information linePointCount = 0; lineName = ""; ss.str(std::string()); // covert discontinuity to object ais::Discontinuity discontinuity(s.c_str()); if (!discontinuity.points.empty()) { discontinuities.emplace(discontinuity.name, discontinuity); } } } return discontinuities.size(); } }; }