// shape.cpp - Implementació del sistema de formes vectorials // © 2025 Port a C++20 amb SDL3 #include "core/graphics/shape.hpp" #include #include #include #include namespace Graphics { Shape::Shape(const std::string& filepath) : centre_({.x = 0.0F, .y = 0.0F}), escala_defecte_(1.0F), nom_("unnamed") { carregar(filepath); } bool Shape::carregar(const std::string& filepath) { // Llegir fitxer std::ifstream file(filepath); if (!file.is_open()) { std::cerr << "[Shape] Error: no es pot obrir " << filepath << std::endl; return false; } // Llegir tot el contingut std::stringstream buffer; buffer << file.rdbuf(); std::string contingut = buffer.str(); file.close(); // Parsejar return parsejar_fitxer(contingut); } bool Shape::parsejar_fitxer(const std::string& contingut) { std::istringstream iss(contingut); std::string line; while (std::getline(iss, line)) { // Trim whitespace line = trim(line); // Skip comments and blanks if (line.empty() || line[0] == '#') { continue; } // Parse command if (starts_with(line, "name:")) { nom_ = trim(extract_value(line)); } else if (starts_with(line, "scale:")) { try { escala_defecte_ = std::stof(extract_value(line)); } catch (...) { std::cerr << "[Shape] Warning: escala invàlida, usant 1.0" << std::endl; escala_defecte_ = 1.0F; } } else if (starts_with(line, "center:")) { parse_center(extract_value(line)); } else if (starts_with(line, "polyline:")) { auto points = parse_points(extract_value(line)); if (points.size() >= 2) { primitives_.push_back({PrimitiveType::POLYLINE, points}); } else { std::cerr << "[Shape] Warning: polyline amb menys de 2 punts ignorada" << std::endl; } } else if (starts_with(line, "line:")) { auto points = parse_points(extract_value(line)); if (points.size() == 2) { primitives_.push_back({PrimitiveType::LINE, points}); } else { std::cerr << "[Shape] Warning: line ha de tenir exactament 2 punts" << std::endl; } } // Comandes desconegudes ignorades silenciosament } if (primitives_.empty()) { std::cerr << "[Shape] Error: cap primitiva carregada" << std::endl; return false; } return true; } // Helper: trim whitespace std::string Shape::trim(const std::string& str) const { const char* whitespace = " \t\n\r"; size_t start = str.find_first_not_of(whitespace); if (start == std::string::npos) { return ""; } size_t end = str.find_last_not_of(whitespace); return str.substr(start, end - start + 1); } // Helper: starts_with bool Shape::starts_with(const std::string& str, const std::string& prefix) const { if (str.length() < prefix.length()) { return false; } return str.starts_with(prefix); } // Helper: extract value after ':' std::string Shape::extract_value(const std::string& line) const { size_t colon = line.find(':'); if (colon == std::string::npos) { return ""; } return line.substr(colon + 1); } // Helper: parse center "x, y" void Shape::parse_center(const std::string& value) { std::string val = trim(value); size_t comma = val.find(','); if (comma != std::string::npos) { try { centre_.x = std::stof(trim(val.substr(0, comma))); centre_.y = std::stof(trim(val.substr(comma + 1))); } catch (...) { std::cerr << "[Shape] Warning: centre invàlid, usant (0,0)" << std::endl; centre_ = {.x = 0.0F, .y = 0.0F}; } } } // Helper: parse points "x1,y1 x2,y2 x3,y3" std::vector Shape::parse_points(const std::string& str) const { std::vector points; std::istringstream iss(trim(str)); std::string pair; while (iss >> pair) { // Whitespace-separated size_t comma = pair.find(','); if (comma != std::string::npos) { try { float x = std::stof(pair.substr(0, comma)); float y = std::stof(pair.substr(comma + 1)); points.push_back({x, y}); } catch (...) { std::cerr << "[Shape] Warning: punt invàlid ignorat: " << pair << std::endl; } } } return points; } } // namespace Graphics