#include "shapefile_handler.h" #include "core/resources.h" #include "dbf_file/dbf_file.h" #include "image/text.h" #include "imgui/imgui.h" #include "init.h" #include "logger.h" #include "core/style.h" #include "imgui/implot/implot.h" namespace satdump { namespace handlers { ShapefileHandler::ShapefileHandler() { handler_tree_icon = u8"\uf84c"; } ShapefileHandler::ShapefileHandler(std::string shapefile) { handler_tree_icon = u8"\uf84c"; std::ifstream f(shapefile, std::ios::binary); file = std::make_unique(f); std::string db = std::filesystem::path(shapefile).parent_path().string() + "/" + std::filesystem::path(shapefile).stem().string() + ".dbf"; shapefile_name = std::filesystem::path(shapefile).stem().string() + ".shp"; logger->critical(db); if (std::filesystem::exists(db)) { dbf_file = dbf_file::readDbfFile(db); // logger->critical("JSON : \n%s\n", dbf_file.dump(4).c_str()); has_dbf = true; } setConfig(satdump::db->get_user_json("shapefile_defaults/" + std::filesystem::path(shapefile_name).stem().string())); } ShapefileHandler::~ShapefileHandler() { satdump::db->set_user_json("shapefile_defaults/" + std::filesystem::path(shapefile_name).stem().string(), getConfig()); } void ShapefileHandler::drawMenu() { if (ImGui::CollapsingHeader("Settings", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::ColorEdit3("Draw Color##shapefilecolor", (float *)&color_to_draw, ImGuiColorEditFlags_NoInputs /*| ImGuiColorEditFlags_NoLabel*/); ImGui::Checkbox("Anti-Alias", &antialias); ImGui::InputInt("Font Size", &font_size); if (has_dbf) ImGui::InputInt("Scale Rank (Cities Only)", &scalerank_filter); } } void ShapefileHandler::drawMenuBar() {} void ShapefileHandler::drawContents(ImVec2 win_size) { if (ImPlot::BeginPlot("##shapefileplot", ImVec2(win_size.x, win_size.y - 16 * ui_scale), ImPlotFlags_Equal)) { auto polylineDraw = [this](std::vector> parts, int num) { for (std::vector coordinates : parts) { std::vector line_x, line_y; for (int i = 0; i < (int)coordinates.size(); i++) { line_x.push_back(coordinates[i].x); line_y.push_back(coordinates[i].y); } std::string shapeID = "Polygon " + std::to_string(num); if (has_dbf) { if (dbf_file[num]["NAME_1"].is_string()) shapeID = dbf_file[num]["NAME_1"]; if (dbf_file[num]["name"].is_string()) shapeID = dbf_file[num]["name"]; } ImPlot::PlotLine(shapeID.c_str(), line_x.data(), line_y.data(), line_x.size()); } }; auto pointDraw = [this](shapefile::point_t coordinates, int num) { std::string shapeID = "Point " + std::to_string(num); if (has_dbf) { if (dbf_file[num]["NAME_1"].is_string()) shapeID = dbf_file[num]["NAME_1"]; if (dbf_file[num]["name"].is_string()) shapeID = dbf_file[num]["name"]; } ImPlot::PlotScatter(shapeID.c_str(), &coordinates.x, &coordinates.y, 1); }; for (shapefile::PolyLineRecord &polylineRecord : file->polyline_records) polylineDraw(polylineRecord.parts_points, polylineRecord.record_number - 1); for (shapefile::PolygonRecord &polygonRecord : file->polygon_records) polylineDraw(polygonRecord.parts_points, polygonRecord.record_number - 1); for (shapefile::PointRecord &pointRecord : file->point_records) pointDraw(pointRecord.point, pointRecord.record_number - 1); for (shapefile::MultiPointRecord &multipointRecord : file->multipoint_records) for (shapefile::point_t p : multipointRecord.points) pointDraw(p, multipointRecord.record_number - 1); ImPlot::EndPlot(); } } void ShapefileHandler::setConfig(nlohmann::json p) { if (p.contains("color")) { auto &c = p["color"]; color_to_draw.x = c[0]; color_to_draw.y = c[1]; color_to_draw.z = c[2]; color_to_draw.w = c[3]; } if (p.contains("antialias")) antialias = p["antialias"]; if (p.contains("font_size")) font_size = p["font_size"]; if (p.contains("scalerank_filter")) scalerank_filter = p["scalerank_filter"]; } nlohmann::json ShapefileHandler::getConfig() { nlohmann::json p; p["color"] = {color_to_draw.x, color_to_draw.y, color_to_draw.z, color_to_draw.w}; p["antialias"] = antialias; p["font_size"] = font_size; p["scalerank_filter"] = scalerank_filter; return p; } void ShapefileHandler::draw_to_image(image::Image &img, std::function(double, double, double, double)> projectionFunc) { if (img.channels() < 3) img.to_rgb(); // TODOREWORK std::vector color = {color_to_draw.x, color_to_draw.y, color_to_draw.z, color_to_draw.w}; image::TextDrawer text_drawer; text_drawer.init_font(resources::getResourcePath("fonts/font.ttf")); { std::function>, int num)> polylineDraw = [this, color, &img, &projectionFunc](std::vector> parts, int num) { int width = img.width(); int height = img.height(); for (std::vector coordinates : parts) { std::pair start = projectionFunc(coordinates[0].y, coordinates[0].x, height, width); for (int i = 1; i < (int)coordinates.size() - 1; i++) { std::pair end = projectionFunc(coordinates[i].y, coordinates[i].x, height, width); if (start.first != -1 && start.second != -1 && end.first != -1 && end.second != -1) { if (antialias) img.draw_aa_line(start.first, start.second, end.first, end.second, color); else img.draw_line(start.first, start.second, end.first, end.second, color); } start = end; } } }; std::function pointDraw = [this, color, &text_drawer, &img, &projectionFunc](shapefile::point_t coordinates, int num) { std::pair cc = projectionFunc(coordinates.y, coordinates.x, img.height(), img.width()); if (cc.first == -1 || cc.second == -1) return; if (has_dbf) { if (dbf_file[num]["scalerank"].is_string()) if (scalerank_filter < std::stoi(dbf_file[num]["scalerank"].get())) return; } #if 0 img.draw_pixel(cc.first, cc.second, color); #else if (antialias) { img.draw_aa_line(cc.first - font_size * 0.3, cc.second - font_size * 0.3, cc.first + font_size * 0.3, cc.second + font_size * 0.3, color); img.draw_aa_line(cc.first + font_size * 0.3, cc.second - font_size * 0.3, cc.first - font_size * 0.3, cc.second + font_size * 0.3, color); } else { img.draw_line(cc.first - font_size * 0.3, cc.second - font_size * 0.3, cc.first + font_size * 0.3, cc.second + font_size * 0.3, color); img.draw_line(cc.first + font_size * 0.3, cc.second - font_size * 0.3, cc.first - font_size * 0.3, cc.second + font_size * 0.3, color); } img.draw_circle(cc.first, cc.second, 0.15 * font_size, color, true); std::string shapeID; if (has_dbf) { if (dbf_file[num]["NAME_1"].is_string()) shapeID = dbf_file[num]["NAME_1"]; if (dbf_file[num]["name"].is_string()) shapeID = dbf_file[num]["name"]; } if (shapeID.size()) text_drawer.draw_text(img, cc.first, cc.second + font_size * 0.15, color, font_size, shapeID); #endif }; for (shapefile::PolyLineRecord &polylineRecord : file->polyline_records) polylineDraw(polylineRecord.parts_points, polylineRecord.record_number - 1); for (shapefile::PolygonRecord &polygonRecord : file->polygon_records) polylineDraw(polygonRecord.parts_points, polygonRecord.record_number - 1); for (shapefile::PointRecord &pointRecord : file->point_records) pointDraw(pointRecord.point, pointRecord.record_number - 1); for (shapefile::MultiPointRecord &multipointRecord : file->multipoint_records) for (shapefile::point_t p : multipointRecord.points) pointDraw(p, multipointRecord.record_number - 1); } } } // namespace handlers } // namespace satdump