Advertisement
Guest User

Untitled

a guest
Feb 25th, 2020
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.74 KB | None | 0 0
  1. #include "transport_renderer.h"
  2.  
  3. #include <algorithm>
  4. #include <sstream>
  5. #include <limits>
  6. #include <set>
  7. #include <cassert>
  8.  
  9. TransportRenderer::TransportRenderer(const Json::Dict& render_settings_json) {
  10.     mSettings = RenderSettings::fromJson(render_settings_json);
  11.     SetupLayerBuilders();
  12. }
  13.  
  14. void TransportRenderer::Init(std::vector<Stop> stops, std::vector<Bus> buses) {
  15.     SetStops(std::move(stops));
  16.     SetBuses(std::move(buses));
  17. }
  18.  
  19. void TransportRenderer::SetStops(std::vector<Descriptions::Stop> stops) {
  20.     mStops = std::move(stops);
  21.  
  22.     std::sort(mStops.begin(), mStops.end(), [](const Stop& a, const Stop& b) {
  23.         return a.name < b.name;
  24.     });
  25.  
  26.     for (auto& stop : mStops) {
  27.         mNameToStop.insert({stop.name, &stop});
  28.     }
  29.  
  30. }
  31.  
  32. void TransportRenderer::SetBuses(std::vector<Descriptions::Bus> buses) {
  33.     mBuses = std::move(buses);
  34.     std::sort(mBuses.begin(), mBuses.end(), [](const Bus& a, const Bus& b) {
  35.         return a.name < b.name;
  36.     });
  37.  
  38.     InterpolateInternalStops();
  39.     ComputeLatLonIndices();
  40.     ComputeRenderingSteps();
  41. }
  42.  
  43. std::string TransportRenderer::Render() const {
  44.     Svg::Document doc;
  45.  
  46.     for (const auto& layer : mSettings.layers) {
  47.         mBuilders.at(layer)(doc);
  48.     }
  49.  
  50.     std::stringstream sstream;
  51.     doc.Render(sstream);
  52.  
  53. #ifdef DEBUG
  54.     return sstream.str();
  55. #else
  56.     auto rawString = sstream.str();
  57.     std::string convertedString;
  58.     for (auto ch : rawString) {
  59.         if (ch == '\\' || ch == '"')
  60.             convertedString += '\\';
  61.         convertedString += ch;
  62.     }
  63.     return convertedString;
  64. #endif
  65. }
  66.  
  67. Svg::Color ColorFromJson(const Json::Node& node) {
  68.     if (std::holds_alternative<std::string>(node.GetBase())) {
  69.         return Svg::Color(node.AsString());
  70.     } else {
  71.         if (node.AsArray().size() == 3) {
  72.             return Svg::Color(Svg::Rgb{node.AsArray()[0].AsInt(),
  73.                                        node.AsArray()[1].AsInt(),
  74.                                        node.AsArray()[2].AsInt()
  75.             });
  76.         } else {
  77.             return Svg::Color(Svg::Rgba{node.AsArray()[0].AsInt(),
  78.                                         node.AsArray()[1].AsInt(),
  79.                                         node.AsArray()[2].AsInt(),
  80.                                         node.AsArray()[3].AsDouble()
  81.             });
  82.         }
  83.     }
  84. }
  85.  
  86. TransportRenderer::RenderSettings TransportRenderer::RenderSettings::fromJson(const Json::Dict& render_settings_json) {
  87.     TransportRenderer::RenderSettings settings;
  88.  
  89.     settings.width = render_settings_json.at("width").AsDouble();
  90.     settings.height = render_settings_json.at("height").AsDouble();
  91.     settings.padding = render_settings_json.at("padding").AsDouble();
  92.     settings.stopRadius = render_settings_json.at("stop_radius").AsDouble();
  93.     settings.lineWidth = render_settings_json.at("line_width").AsDouble();
  94.     settings.stopLabelFontSize = render_settings_json.at("stop_label_font_size").AsInt();
  95.     settings.stopLabelOffset = {render_settings_json.at("stop_label_offset").AsArray()[0].AsDouble(),
  96.                                 render_settings_json.at("stop_label_offset").AsArray()[1].AsDouble()};
  97.     settings.underlayerWidth = render_settings_json.at("underlayer_width").AsDouble();
  98.     settings.underlayerColor = ColorFromJson(render_settings_json.at("underlayer_color"));
  99.     for (const auto& colorNode : render_settings_json.at("color_palette").AsArray()) {
  100.         settings.colorPalette.push_back(ColorFromJson(colorNode));
  101.     }
  102.     settings.busLabelFontSize = render_settings_json.at("bus_label_font_size").AsInt();
  103.     settings.busLabelOffset = {render_settings_json.at("bus_label_offset").AsArray()[0].AsDouble(),
  104.                                render_settings_json.at("bus_label_offset").AsArray()[1].AsDouble()};
  105.  
  106.     for (const auto& layerNode : render_settings_json.at("layers").AsArray()) {
  107.         settings.layers.push_back(layerNode.AsString());
  108.     }
  109.  
  110.     return settings;
  111. }
  112.  
  113. void TransportRenderer::SetupLayerBuilders() {
  114.     mBuilders["bus_lines"] = [this](Svg::Document& document) {
  115.         for (size_t busIndex = 0; busIndex < mBuses.size(); ++busIndex) {
  116.             auto color = mSettings.colorPalette[busIndex % mSettings.colorPalette.size()];
  117.  
  118.             auto polyline = Svg::Polyline{}.SetStrokeColor(color)
  119.                                            .SetStrokeWidth(mSettings.lineWidth)
  120.                                            .SetStrokeLineCap("round")
  121.                                            .SetStrokeLineJoin("round");
  122.             for (const auto& stopName : mBuses[busIndex].stops) {
  123.                 const auto& stop = *mNameToStop.at(stopName);
  124.                 polyline = polyline.AddPoint(GlobalToLocal(stop));
  125.             }
  126.  
  127.             document.Add(polyline);
  128.         }
  129.     };
  130.  
  131.     mBuilders["bus_labels"] = [this](Svg::Document& document) {
  132.         auto AddBusStopName = [this, &document](const Bus& bus, const Stop& stop, const Svg::Color color) {
  133.             document.Add(Svg::Text{}.SetPoint(GlobalToLocal(stop))
  134.                                     .SetOffset(mSettings.busLabelOffset)
  135.                                     .SetFillColor(color)
  136.                                     .SetFontSize(mSettings.busLabelFontSize)
  137.                                     .SetFontFamily("Verdana")
  138.                                     .SetFontWeight("bold")
  139.                                     .SetData(bus.name)
  140.                                     .SetFillColor(mSettings.underlayerColor)
  141.                                     .SetStrokeColor(mSettings.underlayerColor)
  142.                                     .SetStrokeWidth(mSettings.underlayerWidth)
  143.                                     .SetStrokeLineCap("round")
  144.                                     .SetStrokeLineJoin("round"));
  145.  
  146.             document.Add(Svg::Text{}.SetPoint(GlobalToLocal(stop))
  147.                                     .SetOffset(mSettings.busLabelOffset)
  148.                                     .SetFillColor(color)
  149.                                     .SetFontSize(mSettings.busLabelFontSize)
  150.                                     .SetFontFamily("Verdana")
  151.                                     .SetFontWeight("bold")
  152.                                     .SetData(bus.name));
  153.         };
  154.  
  155.         for (size_t busIndex = 0; busIndex < mBuses.size(); ++busIndex) {
  156.             auto color = mSettings.colorPalette[busIndex % mSettings.colorPalette.size()];
  157.             const auto& bus = mBuses[busIndex];
  158.             auto stopName = bus.stops[0];
  159.             AddBusStopName(mBuses[busIndex], *mNameToStop.at(stopName), color);
  160.             if (!bus.isRoundtrip && stopName != bus.stops[bus.stops.size() / 2])
  161.                 AddBusStopName(mBuses[busIndex], *mNameToStop.at(bus.stops[bus.stops.size() / 2]), color);
  162.         }
  163.     };
  164.  
  165.     mBuilders["stop_points"] = [this](Svg::Document& document) {
  166.         for (const auto& stop : mStops) {
  167.             document.Add(Svg::Circle{}.SetCenter(GlobalToLocal(stop))
  168.                                       .SetRadius(mSettings.stopRadius)
  169.                                       .SetFillColor("white"));
  170.         }
  171.     };
  172.  
  173.     mBuilders["stop_labels"] = [this](Svg::Document& doc) {
  174.         for (const auto& stop : mStops) {
  175.             doc.Add(Svg::Text{}.SetPoint(GlobalToLocal(stop))
  176.                                .SetOffset(mSettings.stopLabelOffset)
  177.                                .SetFontSize(mSettings.stopLabelFontSize)
  178.                                .SetFontFamily("Verdana")
  179.                                .SetData(stop.name)
  180.                                .SetFillColor(mSettings.underlayerColor)
  181.                                .SetStrokeColor(mSettings.underlayerColor)
  182.                                .SetStrokeWidth(mSettings.underlayerWidth)
  183.                                .SetStrokeLineCap("round")
  184.                                .SetStrokeLineJoin("round"));
  185.  
  186.             doc.Add(Svg::Text{}.SetPoint(GlobalToLocal(stop))
  187.                                .SetOffset(mSettings.stopLabelOffset)
  188.                                .SetFontSize(mSettings.stopLabelFontSize)
  189.                                .SetFontFamily("Verdana")
  190.                                .SetData(stop.name)
  191.                                .SetFillColor("black"));
  192.  
  193.         }
  194.     };
  195. }
  196.  
  197. void TransportRenderer::InterpolateInternalStops() {
  198.     std::set<std::string> pivotStops;
  199.  
  200.     std::map<std::string, int> stopToBuses;
  201.     for (const auto& bus : mBuses) {
  202.         if (bus.stops.empty())
  203.             continue;
  204.  
  205.         pivotStops.insert(bus.stops.front());
  206.         if (!bus.isRoundtrip) {
  207.             pivotStops.insert(bus.stops[bus.stops.size() / 2]);
  208.         }
  209.         std::map<std::string, int> stopToCount;
  210.         for (const auto& stop : bus.stops) {
  211.             stopToCount[stop]++;
  212.         }
  213.  
  214.         for (const auto& [stop, count] : stopToCount) {
  215.             if (count > 2)
  216.                 pivotStops.insert(stop);
  217.             stopToBuses[stop]++;
  218.         }
  219.     }
  220.  
  221.     for (const auto& [stop, count] : stopToBuses) {
  222.         if (count > 1) {
  223.             pivotStops.insert(stop);
  224.         }
  225.     }
  226.  
  227.     for (const auto& bus : mBuses) {
  228.         if (bus.stops.size() == 0)
  229.             continue;
  230.  
  231.         int lastPivotIndex = 0;
  232.         auto lastPivotStop = bus.stops[0];
  233.         for (size_t i = 0; i < bus.stops.size(); ++i) {
  234.             auto curStop = bus.stops[i % bus.stops.size()];
  235.             if (pivotStops.count(curStop) > 0) {
  236.                 auto startPosition = mNameToStop[lastPivotStop]->position;
  237.                 auto endPosition = mNameToStop[curStop]->position;
  238.                 for (int j = lastPivotIndex + 1; j < i; ++j) {
  239.                     auto& stop = *mNameToStop[bus.stops[j]];
  240.                     assert(pivotStops.count(stop.name) == 0);
  241.                     stop.position.latitude = startPosition.latitude + (j - lastPivotIndex) *
  242.                                              (endPosition.latitude - startPosition.latitude) / (i - lastPivotIndex);
  243.                     stop.position.longitude = startPosition.longitude + (j - lastPivotIndex) *
  244.                                               (endPosition.longitude - startPosition.longitude) / (i - lastPivotIndex);
  245.                 }
  246.                 lastPivotIndex = static_cast<int>(i);
  247.                 lastPivotStop = curStop;
  248.             }
  249.         }
  250.     }
  251.  
  252.     mPivots = pivotStops;
  253. }
  254.  
  255. void TransportRenderer::ComputeLatLonIndices() {
  256.     auto getSortedCoordinates = [this](auto coordGetter) {
  257.         std::vector<std::pair<double, Stop>> result;
  258.         for (const auto& stop : mStops) {
  259.             result.push_back({coordGetter(stop), stop});
  260.         }
  261.         std::sort(result.begin(), result.end(), [](const std::pair<double, Stop>& a, const std::pair<double, Stop>& b) {
  262.             return a.first + 1e-6 < b.first;
  263.         });
  264.         return result;
  265.     };
  266.  
  267.     const std::vector<std::pair<double, Stop>> sortedLats = getSortedCoordinates([](const Stop& stop) {
  268.         return stop.position.latitude;
  269.     });
  270.     const std::vector<std::pair<double, Stop>> sortedLons = getSortedCoordinates([](const Stop& stop) {
  271.         return stop.position.longitude;
  272.     });
  273.  
  274.     auto computePositionIndices = [this](std::map<std::string, int>& stopToIndex, const std::vector<std::pair<double, Stop>>& sortedCoordinate) {
  275.         std::vector<Stop> currentStops {sortedCoordinate[0].second};
  276.         int curId = 0;
  277.         stopToIndex[currentStops.back().name] = curId;
  278.  
  279.         size_t startIndex = 1;
  280.         for (; startIndex < sortedCoordinate.size(); ++startIndex) {
  281.             if (std::abs(sortedCoordinate[startIndex].first - sortedCoordinate[0].first) < 1e-6) {
  282.                 currentStops.push_back(sortedCoordinate[startIndex].second);
  283.                 stopToIndex[currentStops.back().name] = curId;
  284.             } else {
  285.                 break;
  286.             }
  287.         }
  288.  
  289.         while (startIndex < sortedCoordinate.size()) {
  290.             size_t finishIndex = startIndex;
  291.             while (finishIndex < sortedCoordinate.size() && std::abs(sortedCoordinate[startIndex].first - sortedCoordinate[finishIndex].first) < 1e-6) {
  292.                 finishIndex++;
  293.             }
  294.  
  295.             bool shouldUnion = true;
  296.  
  297.             for (size_t i = startIndex; i < finishIndex; ++i) {
  298.                 Stop stop = sortedCoordinate[i].second;
  299.                 for (const auto& bus : mBuses) {
  300.                     for (int j = 0; j < static_cast<int>(bus.stops.size()); ++j) {
  301.                         if (bus.stops[j] == stop.name) {
  302.                             auto busStop = *mNameToStop[bus.stops[(j + 1) % bus.stops.size()]];
  303.                             if (std::find(currentStops.begin(), currentStops.end(), busStop) != currentStops.end()) {
  304.                                 shouldUnion = false;
  305.                             }
  306.                         }
  307.                         if (bus.stops[(j + 1) % bus.stops.size()] == stop.name) {
  308.                             auto busStop = *mNameToStop[bus.stops[j]];
  309.                             if (std::find(currentStops.begin(), currentStops.end(), busStop) != currentStops.end()) {
  310.                                 shouldUnion = false;
  311.                             }
  312.                         }
  313.                     }
  314.                 }
  315.                 currentStops.push_back(stop);
  316.             }
  317.  
  318.             for (size_t i = startIndex; i < finishIndex; ++i) {
  319.                 currentStops.pop_back();
  320.             }
  321.  
  322.             if (!shouldUnion) {
  323.                 curId++;
  324.                 currentStops.clear();
  325.             }
  326.             for (size_t i = startIndex; i < finishIndex; ++i) {
  327.                 currentStops.push_back(sortedCoordinate[i].second);
  328.                 stopToIndex[currentStops.back().name] = curId;
  329.             }
  330.  
  331.             startIndex = finishIndex;
  332.         }
  333.     };
  334.  
  335.     computePositionIndices(mLatIndex, sortedLats);
  336.     computePositionIndices(mLonIndex, sortedLons);
  337. }
  338.  
  339. void TransportRenderer::ComputeRenderingSteps() {
  340.     int maxLonIndex = 0;
  341.     for (const auto& [key, value] : mLonIndex) {
  342.         maxLonIndex = std::max(maxLonIndex, value);
  343.     }
  344.  
  345.     int maxLatIndex = 0;
  346.     for (const auto& [key, value] : mLatIndex) {
  347.         maxLatIndex = std::max(maxLatIndex, value);
  348.     }
  349.  
  350.     mLongitudeStep = (maxLonIndex == 0 ? 0 : (mSettings.width - 2 * mSettings.padding) / maxLonIndex);
  351.     mLatitudeStep = (maxLatIndex == 0 ? 0 : (mSettings.height - 2 * mSettings.padding) / maxLatIndex);
  352. }
  353.  
  354. Svg::Point TransportRenderer::GlobalToLocal(const Stop& stop) const {
  355.     double x = mSettings.padding + mLonIndex.at(stop.name) * mLongitudeStep;
  356.     double y = mSettings.height - mSettings.padding - mLatIndex.at(stop.name) * mLatitudeStep;
  357.  
  358. //    std::cout << "Stop: " << stop.name << ". " << x << " " << y << std::endl;
  359.  
  360.     return {x, y};
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement