mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-29 01:03:46 +00:00
Merge commit 'eb264889e3' into traffic
This commit is contained in:
@@ -7,11 +7,11 @@
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <boost/core/bit.hpp>
|
||||
#include <boost/uuid/detail/sha1.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <bit>
|
||||
|
||||
namespace coding
|
||||
{
|
||||
@@ -22,7 +22,7 @@ SHA1::Hash ExtractHash(boost::uuids::detail::sha1 & sha1)
|
||||
boost::uuids::detail::sha1::digest_type digest;
|
||||
sha1.get_digest(digest);
|
||||
for (auto & b : digest)
|
||||
b = boost::core::byteswap(b);
|
||||
b = std::byteswap(b);
|
||||
|
||||
SHA1::Hash result;
|
||||
static_assert(result.size() == sizeof(digest));
|
||||
|
||||
@@ -51,9 +51,7 @@ public:
|
||||
uint32_t m_textureIndex = 0;
|
||||
};
|
||||
|
||||
// TODO(AB): Remove?
|
||||
class GlyphRegion : public BaseRegion
|
||||
{};
|
||||
using GlyphRegion = BaseRegion;
|
||||
|
||||
class StippleRegion : public BaseRegion
|
||||
{
|
||||
@@ -61,8 +59,7 @@ public:
|
||||
m2::PointU GetMaskPixelSize() const;
|
||||
};
|
||||
|
||||
class ColorRegion : public BaseRegion
|
||||
{};
|
||||
using ColorRegion = BaseRegion;
|
||||
|
||||
struct Params
|
||||
{
|
||||
|
||||
@@ -194,6 +194,8 @@ bool Metadata::TypeFromString(string_view k, Metadata::EType & outType)
|
||||
outType = Metadata::FMD_OUTDOOR_SEATING;
|
||||
else if (k == "network")
|
||||
outType = Metadata::FMD_NETWORK;
|
||||
else if (k.starts_with("socket:"))
|
||||
outType = Metadata::FMD_CHARGE_SOCKETS;
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -315,6 +317,7 @@ string ToString(Metadata::EType type)
|
||||
case Metadata::FMD_SELF_SERVICE: return "self_service";
|
||||
case Metadata::FMD_OUTDOOR_SEATING: return "outdoor_seating";
|
||||
case Metadata::FMD_NETWORK: return "network";
|
||||
case Metadata::FMD_CHARGE_SOCKETS: CHECK(false, ("FMD_CHARGE_SOCKETS is a compound attribute."));
|
||||
case Metadata::FMD_COUNT: CHECK(false, ("FMD_COUNT can not be used as a type."));
|
||||
};
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ public:
|
||||
FMD_CHECK_DATE = 53,
|
||||
FMD_CHECK_DATE_OPEN_HOURS = 54,
|
||||
FMD_BRANCH = 55,
|
||||
FMD_CHARGE_SOCKETS = 56,
|
||||
FMD_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -459,19 +459,33 @@ OneLevelPOIChecker::OneLevelPOIChecker() : ftypes::BaseChecker(1 /* level */)
|
||||
TwoLevelPOIChecker::TwoLevelPOIChecker() : ftypes::BaseChecker(2 /* level */)
|
||||
{
|
||||
Classificator const & c = classif();
|
||||
base::StringIL arr[] = {{"aeroway", "terminal"}, {"aeroway", "gate"},
|
||||
{"building", "train_station"}, {"emergency", "defibrillator"},
|
||||
{"emergency", "fire_hydrant"}, {"emergency", "phone"},
|
||||
{"highway", "bus_stop"}, {"highway", "elevator"},
|
||||
{"highway", "ford"}, {"highway", "raceway"},
|
||||
{"highway", "rest_area"}, {"highway", "services"},
|
||||
{"highway", "speed_camera"}, {"man_made", "communications_tower"},
|
||||
{"man_made", "cross"}, {"man_made", "lighthouse"},
|
||||
{"man_made", "water_tap"}, {"man_made", "water_well"},
|
||||
{"natural", "beach"}, {"natural", "cave_entrance"},
|
||||
{"natural", "geyser"}, {"natural", "hot_spring"},
|
||||
{"natural", "peak"}, {"natural", "saddle"},
|
||||
{"natural", "spring"}, {"natural", "volcano"},
|
||||
base::StringIL arr[] = {{"aeroway", "terminal"},
|
||||
{"aeroway", "gate"},
|
||||
{"building", "guardhouse"},
|
||||
{"building", "train_station"},
|
||||
{"emergency", "defibrillator"},
|
||||
{"emergency", "fire_hydrant"},
|
||||
{"emergency", "phone"},
|
||||
{"highway", "bus_stop"},
|
||||
{"highway", "elevator"},
|
||||
{"highway", "ford"},
|
||||
{"highway", "raceway"},
|
||||
{"highway", "rest_area"},
|
||||
{"highway", "services"},
|
||||
{"highway", "speed_camera"},
|
||||
{"man_made", "communications_tower"},
|
||||
{"man_made", "cross"},
|
||||
{"man_made", "lighthouse"},
|
||||
{"man_made", "water_tap"},
|
||||
{"man_made", "water_well"},
|
||||
{"natural", "beach"},
|
||||
{"natural", "cave_entrance"},
|
||||
{"natural", "geyser"},
|
||||
{"natural", "hot_spring"},
|
||||
{"natural", "peak"},
|
||||
{"natural", "saddle"},
|
||||
{"natural", "spring"},
|
||||
{"natural", "volcano"},
|
||||
{"waterway", "waterfall"}};
|
||||
|
||||
for (auto const & path : arr)
|
||||
|
||||
@@ -178,6 +178,57 @@ std::string_view MapObject::GetOpeningHours() const
|
||||
return m_metadata.Get(MetadataID::FMD_OPEN_HOURS);
|
||||
}
|
||||
|
||||
ChargeSocketDescriptors MapObject::GetChargeSockets() const
|
||||
{
|
||||
ChargeSocketDescriptors sockets;
|
||||
|
||||
auto s = std::string(m_metadata.Get(MetadataID::FMD_CHARGE_SOCKETS));
|
||||
if (s.empty())
|
||||
return sockets;
|
||||
|
||||
auto tokens = strings::Tokenize(s, ";");
|
||||
|
||||
for (auto token : tokens)
|
||||
{
|
||||
if (token.empty())
|
||||
continue;
|
||||
|
||||
auto fields = strings::Tokenize(token, "|");
|
||||
|
||||
if (fields.size() < 3)
|
||||
continue; // invalid entry, skip
|
||||
|
||||
ChargeSocketDescriptor desc;
|
||||
desc.type = fields[0];
|
||||
|
||||
try
|
||||
{
|
||||
desc.count = std::stoi(std::string(fields[1]));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
desc.count = 0;
|
||||
}
|
||||
|
||||
if (fields.size() >= 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
desc.power = std::stod(std::string(fields[2]));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
desc.power = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
desc.power = 0;
|
||||
|
||||
sockets.push_back(desc);
|
||||
}
|
||||
return sockets;
|
||||
}
|
||||
|
||||
feature::Internet MapObject::GetInternet() const
|
||||
{
|
||||
return feature::InternetFromString(m_metadata.Get(MetadataID::FMD_INTERNET));
|
||||
@@ -242,6 +293,11 @@ int MapObject::GetStars() const
|
||||
return count;
|
||||
}
|
||||
|
||||
std::string MapObject::GetCapacity() const
|
||||
{
|
||||
return std::string(m_metadata.Get(MetadataID::FMD_CAPACITY));
|
||||
}
|
||||
|
||||
bool MapObject::IsPointType() const
|
||||
{
|
||||
return m_geomType == feature::GeomType::Point;
|
||||
|
||||
@@ -17,6 +17,17 @@ namespace osm
|
||||
{
|
||||
class EditableMapObject;
|
||||
|
||||
// struct to store the representation of a charging station socket
|
||||
struct ChargeSocketDescriptor
|
||||
{
|
||||
std::string type; // https://wiki.openstreetmap.org/wiki/Key:socket:*
|
||||
// e.g. "type1"
|
||||
unsigned int count; // number of sockets; 0 means socket present, but unknown count
|
||||
// (eg, OSM tag for count set to 'yes')
|
||||
double power; // power output, in kW. 0 means unknown.
|
||||
};
|
||||
typedef std::vector<ChargeSocketDescriptor> ChargeSocketDescriptors;
|
||||
|
||||
class MapObject
|
||||
{
|
||||
public:
|
||||
@@ -80,9 +91,19 @@ public:
|
||||
|
||||
std::string FormatRoadShields() const;
|
||||
|
||||
/** parses a list of charging station sockets
|
||||
* stored as "<type>|<nb>|[<power>];..." into a vector of
|
||||
* socket descriptors
|
||||
*
|
||||
* For instance:
|
||||
* "type2_combo|2|150;chademo|1|50;type2|4|"
|
||||
*/
|
||||
ChargeSocketDescriptors GetChargeSockets() const;
|
||||
|
||||
std::string_view GetOpeningHours() const;
|
||||
feature::Internet GetInternet() const;
|
||||
int GetStars() const;
|
||||
std::string GetCapacity() const;
|
||||
|
||||
/// @returns true if feature has ATM type.
|
||||
bool HasAtm() const;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "color_parser.hpp"
|
||||
|
||||
#include "coding/hex.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
@@ -31,6 +32,97 @@ std::optional<uint32_t> ParseHexColor(std::string_view c)
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<int, int, int> ExtractRGB(uint32_t rgbaColor)
|
||||
{
|
||||
return {(rgbaColor >> 24) & 0xFF, (rgbaColor >> 16) & 0xFF, (rgbaColor >> 8) & 0xFF};
|
||||
}
|
||||
|
||||
static int ColorDistance(uint32_t rgbaColor1, uint32_t rgbaColor2)
|
||||
{
|
||||
auto const [r1, g1, b1] = ExtractRGB(rgbaColor1);
|
||||
auto const [r2, g2, b2] = ExtractRGB(rgbaColor2);
|
||||
return (r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2);
|
||||
}
|
||||
|
||||
struct RGBAToGarmin
|
||||
{
|
||||
uint32_t rgba;
|
||||
std::string_view color;
|
||||
};
|
||||
|
||||
auto constexpr kRGBAToGarmin = std::to_array<RGBAToGarmin>({{0x000000ff, "Black"},
|
||||
{0x8b0000ff, "DarkRed"},
|
||||
{0x006400ff, "DarkGreen"},
|
||||
{0xb5b820ff, "DarkYellow"},
|
||||
{0x00008bff, "DarkBlue"},
|
||||
{0x8b008bff, "DarkMagenta"},
|
||||
{0x008b8bff, "DarkCyan"},
|
||||
{0xccccccff, "LightGray"},
|
||||
{0x444444ff, "DarkGray"},
|
||||
{0xff0000ff, "Red"},
|
||||
{0x00ff00ff, "Green"},
|
||||
{0xffff00ff, "Yellow"},
|
||||
{0x0000ffff, "Blue"},
|
||||
{0xff00ffff, "Magenta"},
|
||||
{0x00ffffff, "Cyan"},
|
||||
{0xffffffff, "White"}});
|
||||
|
||||
std::string_view MapGarminColor(uint32_t rgba)
|
||||
{
|
||||
std::string_view closestColor = kRGBAToGarmin[0].color;
|
||||
auto minDistance = std::numeric_limits<int>::max();
|
||||
for (auto const & [rgbaGarmin, color] : kRGBAToGarmin)
|
||||
{
|
||||
auto const distance = ColorDistance(rgba, rgbaGarmin);
|
||||
|
||||
if (distance == 0)
|
||||
return color; // Exact match.
|
||||
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
closestColor = color;
|
||||
}
|
||||
}
|
||||
return closestColor;
|
||||
}
|
||||
|
||||
struct RGBAToPredefined
|
||||
{
|
||||
uint32_t rgba;
|
||||
PredefinedColor predefinedColor;
|
||||
};
|
||||
|
||||
static std::array<RGBAToPredefined, kOrderedPredefinedColors.size()> buildRGBAToPredefined()
|
||||
{
|
||||
auto res = std::array<RGBAToPredefined, kOrderedPredefinedColors.size()>();
|
||||
for (size_t i = 0; i < kOrderedPredefinedColors.size(); ++i)
|
||||
res[i] = {ColorFromPredefinedColor(kOrderedPredefinedColors[i]).GetRGBA(), kOrderedPredefinedColors[i]};
|
||||
return res;
|
||||
}
|
||||
|
||||
auto const kRGBAToPredefined = buildRGBAToPredefined();
|
||||
|
||||
PredefinedColor MapPredefinedColor(uint32_t rgba)
|
||||
{
|
||||
auto closestColor = kRGBAToPredefined[0].predefinedColor;
|
||||
auto minDistance = std::numeric_limits<int>::max();
|
||||
for (auto const & [rgbaGarmin, color] : kRGBAToPredefined)
|
||||
{
|
||||
auto const distance = ColorDistance(rgba, rgbaGarmin);
|
||||
|
||||
if (distance == 0)
|
||||
return color; // Exact match.
|
||||
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
closestColor = color;
|
||||
}
|
||||
}
|
||||
return closestColor;
|
||||
}
|
||||
|
||||
// Garmin extensions spec: https://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd
|
||||
// Color mapping: https://help.locusmap.eu/topic/extend-garmin-gpx-compatibilty
|
||||
std::optional<uint32_t> ParseGarminColor(std::string_view c)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace kml
|
||||
{
|
||||
|
||||
@@ -18,4 +20,7 @@ std::optional<uint32_t> ParseHexColor(std::string_view c);
|
||||
std::optional<uint32_t> ParseGarminColor(std::string_view c);
|
||||
std::optional<uint32_t> ParseOSMColor(std::string_view c);
|
||||
|
||||
PredefinedColor MapPredefinedColor(uint32_t rgba);
|
||||
std::string_view MapGarminColor(uint32_t rgba);
|
||||
|
||||
} // namespace kml
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "kml/color_parser.hpp"
|
||||
#include "kml/serdes_common.hpp"
|
||||
#include "kml/serdes_gpx.hpp"
|
||||
|
||||
@@ -38,9 +39,8 @@ static std::string ReadFile(char const * testFile)
|
||||
return sourceFileText;
|
||||
}
|
||||
|
||||
static std::string ReadFileAndSerialize(char const * testFile)
|
||||
static std::string Serialize(kml::FileData const & dataFromFile)
|
||||
{
|
||||
kml::FileData const dataFromFile = LoadGpxFromFile(testFile);
|
||||
std::string resultBuffer;
|
||||
MemWriter<decltype(resultBuffer)> sink(resultBuffer);
|
||||
kml::gpx::SerializerGpx ser(dataFromFile);
|
||||
@@ -48,6 +48,12 @@ static std::string ReadFileAndSerialize(char const * testFile)
|
||||
return resultBuffer;
|
||||
}
|
||||
|
||||
static std::string ReadFileAndSerialize(char const * testFile)
|
||||
{
|
||||
kml::FileData const dataFromFile = LoadGpxFromFile(testFile);
|
||||
return Serialize(dataFromFile);
|
||||
}
|
||||
|
||||
void ImportExportCompare(char const * testFile)
|
||||
{
|
||||
std::string const sourceFileText = ReadFile(testFile);
|
||||
@@ -305,6 +311,13 @@ UNIT_TEST(Color)
|
||||
TEST_EQUAL(dataFromFile.m_tracksData.size(), 3, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ParseExportedGpxColor)
|
||||
{
|
||||
kml::FileData const dataFromFile = LoadGpxFromFile("test_data/gpx/point_with_predefined_color_2.gpx");
|
||||
TEST_EQUAL(0x0066CCFF, dataFromFile.m_bookmarksData[0].m_color.m_rgba, ());
|
||||
TEST_EQUAL(kml::PredefinedColor::Blue, dataFromFile.m_bookmarksData[0].m_color.m_predefinedColor, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(MultiTrackNames)
|
||||
{
|
||||
kml::FileData dataFromFile = LoadGpxFromFile("test_data/gpx/color.gpx");
|
||||
@@ -323,6 +336,20 @@ UNIT_TEST(Empty)
|
||||
TEST_EQUAL(0, dataFromFile.m_tracksData.size(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(ImportExportWptColor)
|
||||
{
|
||||
ImportExportCompare("test_data/gpx/point_with_predefined_color_2.gpx");
|
||||
}
|
||||
|
||||
UNIT_TEST(PointWithPredefinedColor)
|
||||
{
|
||||
kml::FileData dataFromFile = LoadGpxFromFile("test_data/gpx/point_with_predefined_color_1.gpx");
|
||||
dataFromFile.m_bookmarksData[0].m_color.m_predefinedColor = kml::PredefinedColor::Blue;
|
||||
auto const actual = Serialize(dataFromFile);
|
||||
auto const expected = ReadFile("test_data/gpx/point_with_predefined_color_2.gpx");
|
||||
TEST_EQUAL(expected, actual, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(OsmandColor1)
|
||||
{
|
||||
kml::FileData const dataFromFile = LoadGpxFromFile("test_data/gpx/osmand1.gpx");
|
||||
@@ -394,11 +421,11 @@ UNIT_TEST(ParseFromString)
|
||||
|
||||
UNIT_TEST(MapGarminColor)
|
||||
{
|
||||
TEST_EQUAL("DarkCyan", kml::gpx::MapGarminColor(0x008b8bff), ());
|
||||
TEST_EQUAL("White", kml::gpx::MapGarminColor(0xffffffff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::gpx::MapGarminColor(0xb4b820ff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::gpx::MapGarminColor(0xb6b820ff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::gpx::MapGarminColor(0xb5b721ff), ());
|
||||
TEST_EQUAL("DarkCyan", kml::MapGarminColor(0x008b8bff), ());
|
||||
TEST_EQUAL("White", kml::MapGarminColor(0xffffffff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::MapGarminColor(0xb4b820ff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::MapGarminColor(0xb6b820ff), ());
|
||||
TEST_EQUAL("DarkYellow", kml::MapGarminColor(0xb5b721ff), ());
|
||||
}
|
||||
|
||||
} // namespace gpx_tests
|
||||
|
||||
@@ -80,11 +80,10 @@ bool GpxParser::MakeValid()
|
||||
// Set default name.
|
||||
if (m_name.empty())
|
||||
m_name = kml::PointToLineString(m_org);
|
||||
|
||||
// Set default pin.
|
||||
if (m_predefinedColor == PredefinedColor::None)
|
||||
if (m_color != kInvalidColor)
|
||||
m_predefinedColor = MapPredefinedColor(m_color);
|
||||
else
|
||||
m_predefinedColor = PredefinedColor::Red;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -428,61 +427,6 @@ std::string GpxParser::BuildDescription() const
|
||||
return m_description + "\n\n" + m_comment;
|
||||
}
|
||||
|
||||
std::tuple<int, int, int> ExtractRGB(uint32_t color)
|
||||
{
|
||||
return {(color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF};
|
||||
}
|
||||
|
||||
int ColorDistance(uint32_t color1, uint32_t color2)
|
||||
{
|
||||
auto const [r1, g1, b1] = ExtractRGB(color1);
|
||||
auto const [r2, g2, b2] = ExtractRGB(color2);
|
||||
return (r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2);
|
||||
}
|
||||
|
||||
struct RGBAToGarmin
|
||||
{
|
||||
uint32_t rgba;
|
||||
std::string_view color;
|
||||
};
|
||||
|
||||
auto constexpr kRGBAToGarmin = std::to_array<RGBAToGarmin>({{0x000000ff, "Black"},
|
||||
{0x8b0000ff, "DarkRed"},
|
||||
{0x006400ff, "DarkGreen"},
|
||||
{0xb5b820ff, "DarkYellow"},
|
||||
{0x00008bff, "DarkBlue"},
|
||||
{0x8b008bff, "DarkMagenta"},
|
||||
{0x008b8bff, "DarkCyan"},
|
||||
{0xccccccff, "LightGray"},
|
||||
{0x444444ff, "DarkGray"},
|
||||
{0xff0000ff, "Red"},
|
||||
{0x00ff00ff, "Green"},
|
||||
{0xffff00ff, "Yellow"},
|
||||
{0x0000ffff, "Blue"},
|
||||
{0xff00ffff, "Magenta"},
|
||||
{0x00ffffff, "Cyan"},
|
||||
{0xffffffff, "White"}});
|
||||
|
||||
std::string_view MapGarminColor(uint32_t rgba)
|
||||
{
|
||||
std::string_view closestColor = kRGBAToGarmin[0].color;
|
||||
auto minDistance = std::numeric_limits<int>::max();
|
||||
for (auto const & [rgbaGarmin, color] : kRGBAToGarmin)
|
||||
{
|
||||
auto const distance = ColorDistance(rgba, rgbaGarmin);
|
||||
|
||||
if (distance == 0)
|
||||
return color; // Exact match.
|
||||
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
closestColor = color;
|
||||
}
|
||||
}
|
||||
return closestColor;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -524,6 +468,16 @@ void SaveCategoryData(Writer & writer, CategoryData const & categoryData)
|
||||
writer << "</metadata>\n";
|
||||
}
|
||||
|
||||
uint32_t BookmarkColor(BookmarkData const & bookmarkData)
|
||||
{
|
||||
auto const & [predefinedColor, rgba] = bookmarkData.m_color;
|
||||
if (rgba != kInvalidColor)
|
||||
return rgba;
|
||||
if (predefinedColor != PredefinedColor::None && predefinedColor != PredefinedColor::Red)
|
||||
return ColorFromPredefinedColor(predefinedColor).GetRGBA();
|
||||
return kInvalidColor;
|
||||
}
|
||||
|
||||
void SaveBookmarkData(Writer & writer, BookmarkData const & bookmarkData)
|
||||
{
|
||||
auto const [lat, lon] = mercator::ToLatLon(bookmarkData.m_point);
|
||||
@@ -544,6 +498,14 @@ void SaveBookmarkData(Writer & writer, BookmarkData const & bookmarkData)
|
||||
SaveStringWithCDATA(writer, *description);
|
||||
writer << "</desc>\n";
|
||||
}
|
||||
if (auto const color = BookmarkColor(bookmarkData); color != kInvalidColor)
|
||||
{
|
||||
writer << kIndent2 << "<extensions>\n";
|
||||
writer << kIndent4 << "<xsi:gpx><color>#";
|
||||
SaveColorToARGB(writer, color);
|
||||
writer << "</color></xsi:gpx>\n";
|
||||
writer << kIndent2 << "</extensions>\n";
|
||||
}
|
||||
writer << "</wpt>\n";
|
||||
}
|
||||
|
||||
@@ -583,7 +545,7 @@ void SaveTrackData(Writer & writer, TrackData const & trackData)
|
||||
{
|
||||
writer << kIndent2 << "<extensions>\n";
|
||||
writer << kIndent4 << "<gpxx:TrackExtension><gpxx:DisplayColor>";
|
||||
writer << MapGarminColor(color);
|
||||
writer << kml::MapGarminColor(color);
|
||||
writer << "</gpxx:DisplayColor></gpxx:TrackExtension>\n";
|
||||
writer << kIndent4 << "<gpx_style:line><gpx_style:color>";
|
||||
SaveColorToRGB(writer, color);
|
||||
|
||||
@@ -106,8 +106,6 @@ private:
|
||||
std::string BuildDescription() const;
|
||||
};
|
||||
|
||||
std::string_view MapGarminColor(uint32_t rgba);
|
||||
|
||||
} // namespace gpx
|
||||
|
||||
class DeserializerGpx
|
||||
|
||||
@@ -58,6 +58,7 @@ std::string GetBookmarkIconType(kml::BookmarkIcon const & icon)
|
||||
|
||||
std::string const kCustomImageProperty = "CustomImage";
|
||||
std::string const kHasElevationProfileProperty = "has_elevation_profile";
|
||||
int constexpr kInvalidColor = 0;
|
||||
} // namespace
|
||||
|
||||
Bookmark::Bookmark(m2::PointD const & ptOrg) : Base(ptOrg, UserMark::BOOKMARK), m_groupId(kml::kInvalidMarkGroupId)
|
||||
@@ -181,10 +182,16 @@ kml::PredefinedColor Bookmark::GetColor() const
|
||||
return m_data.m_color.m_predefinedColor;
|
||||
}
|
||||
|
||||
void Bookmark::InvalidateRGBAColor()
|
||||
{
|
||||
m_data.m_color.m_rgba = kInvalidColor;
|
||||
}
|
||||
|
||||
void Bookmark::SetColor(kml::PredefinedColor color)
|
||||
{
|
||||
SetDirty();
|
||||
m_data.m_color.m_predefinedColor = color;
|
||||
InvalidateRGBAColor();
|
||||
}
|
||||
|
||||
std::string Bookmark::GetPreferredName() const
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
void SetCustomName(std::string const & customName);
|
||||
|
||||
kml::PredefinedColor GetColor() const;
|
||||
void InvalidateRGBAColor();
|
||||
void SetColor(kml::PredefinedColor color);
|
||||
|
||||
m2::RectD GetViewport() const;
|
||||
|
||||
@@ -2236,7 +2236,10 @@ void BookmarkManager::UpdateBookmark(kml::MarkId bmID, kml::BookmarkData const &
|
||||
ASSERT(bookmark->GetGroupId() != kml::kInvalidMarkGroupId, ());
|
||||
|
||||
if (prevColor != bookmark->GetColor())
|
||||
{
|
||||
bookmark->InvalidateRGBAColor();
|
||||
SetLastEditedBmColor(bookmark->GetColor());
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarkManager::ChangeTrackColor(kml::TrackId trackId, dp::Color color)
|
||||
|
||||
@@ -371,6 +371,27 @@ UNIT_TEST(Bookmarks_Timestamp)
|
||||
DeleteCategoryFiles(arrCat);
|
||||
}
|
||||
|
||||
UNIT_TEST(Bookmarks_ChangeColorForImportedBookmark)
|
||||
{
|
||||
Framework fm(kFrameworkParams);
|
||||
BookmarkManager & bmManager = fm.GetBookmarkManager();
|
||||
bmManager.EnableTestMode(true);
|
||||
|
||||
auto const cat1 = bmManager.CreateBookmarkCategory("cat1", false /* autoSave */);
|
||||
kml::BookmarkData bm1;
|
||||
kml::SetDefaultStr(bm1.m_name, "1");
|
||||
bm1.m_point = m2::PointD(38, 20);
|
||||
bm1.m_color.m_predefinedColor = kml::PredefinedColor::Blue;
|
||||
bm1.m_color.m_rgba = 0x0066CCFF;
|
||||
auto const * pBm1 = bmManager.GetEditSession().CreateBookmark(std::move(bm1), cat1);
|
||||
bm1.m_color.m_predefinedColor = kml::PredefinedColor::Orange;
|
||||
bmManager.GetEditSession().UpdateBookmark(pBm1->GetId(), bm1);
|
||||
bmManager.SaveBookmarkCategory(cat1);
|
||||
pBm1 = bmManager.GetBookmark(pBm1->GetId());
|
||||
TEST_EQUAL(pBm1->GetData().m_color.m_predefinedColor, kml::PredefinedColor::Orange, ());
|
||||
TEST_EQUAL(pBm1->GetData().m_color.m_rgba, 0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Bookmarks_Getting)
|
||||
{
|
||||
Framework fm(kFrameworkParams);
|
||||
|
||||
@@ -284,11 +284,11 @@ UNIT_TEST(MapApiGe0)
|
||||
TEST_EQUAL(p0.m_name, "Zoo Zürich", ());
|
||||
}
|
||||
{
|
||||
ParsedMapApi api("http://comaps.app/o4B4pYZsRs/Zoo_Zürich");
|
||||
ParsedMapApi api("http://comaps.at/o4B4pYZsRs/Zoo_Zürich");
|
||||
TEST_EQUAL(api.GetRequestType(), UrlType::Map, ());
|
||||
}
|
||||
{
|
||||
ParsedMapApi api("https://comaps.app/o4B4pYZsRs/Zoo_Zürich");
|
||||
ParsedMapApi api("https://comaps.at/o4B4pYZsRs/Zoo_Zürich");
|
||||
TEST_EQUAL(api.GetRequestType(), UrlType::Map, ());
|
||||
}
|
||||
{
|
||||
@@ -386,7 +386,7 @@ UNIT_TEST(CrosshairApi)
|
||||
TEST_EQUAL(api.GetAppName(), "Google Maps", ());
|
||||
}
|
||||
{
|
||||
ParsedMapApi api("https://comaps.app/crosshair?cll=47.3813,8.5889&appname=Google%20Maps");
|
||||
ParsedMapApi api("https://comaps.at/crosshair?cll=47.3813,8.5889&appname=Google%20Maps");
|
||||
TEST_EQUAL(api.GetRequestType(), UrlType::Crosshair, ());
|
||||
ms::LatLon latlon = api.GetCenterLatLon();
|
||||
TEST_ALMOST_EQUAL_ABS(latlon.m_lat, 47.3813, kEps, ());
|
||||
|
||||
@@ -97,6 +97,10 @@ void Info::SetFromFeatureType(FeatureType & ft)
|
||||
|
||||
m_uiSubtitle = FormatSubtitle(IsFeature() /* withTypes */, !emptyTitle /* withMainType */);
|
||||
|
||||
auto const branch = GetMetadata(feature::Metadata::FMD_BRANCH);
|
||||
if (!branch.empty())
|
||||
m_uiBranch = std::string(branch);
|
||||
|
||||
// apply to all types after checks
|
||||
m_isHotel = ftypes::IsHotelChecker::Instance()(ft);
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ public:
|
||||
|
||||
/// For showing in UI
|
||||
std::string const & GetTitle() const { return m_uiTitle; }
|
||||
std::string const & GetBranch() const { return m_uiBranch; }
|
||||
/// Convenient wrapper for secondary feature name.
|
||||
std::string const & GetSecondaryTitle() const { return m_uiSecondaryTitle; }
|
||||
/// Convenient wrapper for type, cuisines, elevation, stars, wifi etc.
|
||||
@@ -220,6 +221,7 @@ private:
|
||||
|
||||
/// UI
|
||||
std::string m_uiTitle;
|
||||
std::string m_uiBranch;
|
||||
std::string m_uiSubtitle;
|
||||
std::string m_uiSecondaryTitle;
|
||||
std::string m_uiAddress;
|
||||
|
||||
@@ -320,7 +320,7 @@ UNIT_TEST(ChunksDownloadStrategyDynamicChunks)
|
||||
{
|
||||
vector<string> const servers = {"UrlOfServer1", "UrlOfServer2"};
|
||||
|
||||
typedef pair<int64_t, int64_t> RangeT;
|
||||
typedef std::pair<int64_t, int64_t> RangeT;
|
||||
|
||||
string url;
|
||||
ChunksDownloadStrategy strategy(servers);
|
||||
|
||||
@@ -16,6 +16,14 @@ set(SRC
|
||||
base/routing_result.hpp
|
||||
base/small_list.hpp
|
||||
base/small_list.cpp
|
||||
lanes/lane_info.cpp
|
||||
lanes/lane_info.hpp
|
||||
lanes/lane_way.cpp
|
||||
lanes/lane_way.hpp
|
||||
lanes/lanes_parser.cpp
|
||||
lanes/lanes_parser.hpp
|
||||
lanes/lanes_recommendation.cpp
|
||||
lanes/lanes_recommendation.hpp
|
||||
car_directions.cpp
|
||||
car_directions.hpp
|
||||
checkpoint_predictor.cpp
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "routing/car_directions.hpp"
|
||||
|
||||
#include "routing/lanes/lanes_recommendation.hpp"
|
||||
#include "routing/turns.hpp"
|
||||
#include "routing/turns_generator.hpp"
|
||||
#include "routing/turns_generator_utils.hpp"
|
||||
@@ -83,7 +84,7 @@ void FixupCarTurns(vector<RouteSegment> & routeSegments)
|
||||
routeSegments[idx - 1].ClearTurn();
|
||||
}
|
||||
}
|
||||
SelectRecommendedLanes(routeSegments);
|
||||
turns::lanes::SelectRecommendedLanes(routeSegments);
|
||||
}
|
||||
|
||||
void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingSegmentIndex,
|
||||
@@ -596,73 +597,4 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FixupLaneSet(CarDirection turn, vector<SingleLaneInfo> & lanes, bool (*checker)(LaneWay, CarDirection))
|
||||
{
|
||||
bool isLaneConformed = false;
|
||||
// There are two nested loops below. (There is a for-loop in checker.)
|
||||
// But the number of calls of the body of inner one (in checker) is relatively small.
|
||||
// Less than 10 in most cases.
|
||||
for (auto & singleLane : lanes)
|
||||
{
|
||||
for (LaneWay laneWay : singleLane.m_lane)
|
||||
{
|
||||
if (checker(laneWay, turn))
|
||||
{
|
||||
singleLane.m_isRecommended = true;
|
||||
isLaneConformed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isLaneConformed;
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
bool SelectFirstUnrestrictedLane(LaneWay direction, It lanesBegin, It lanesEnd)
|
||||
{
|
||||
It const firstUnrestricted = find_if(lanesBegin, lanesEnd, IsLaneUnrestricted);
|
||||
if (firstUnrestricted == lanesEnd)
|
||||
return false;
|
||||
|
||||
firstUnrestricted->m_isRecommended = true;
|
||||
firstUnrestricted->m_lane.insert(firstUnrestricted->m_lane.begin(), direction);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SelectUnrestrictedLane(CarDirection turn, vector<SingleLaneInfo> & lanes)
|
||||
{
|
||||
if (IsTurnMadeFromLeft(turn))
|
||||
return SelectFirstUnrestrictedLane(LaneWay::Left, lanes.begin(), lanes.end());
|
||||
else if (IsTurnMadeFromRight(turn))
|
||||
return SelectFirstUnrestrictedLane(LaneWay::Right, lanes.rbegin(), lanes.rend());
|
||||
return false;
|
||||
}
|
||||
|
||||
void SelectRecommendedLanes(vector<RouteSegment> & routeSegments)
|
||||
{
|
||||
for (auto & segment : routeSegments)
|
||||
{
|
||||
auto & t = segment.GetTurn();
|
||||
if (t.IsTurnNone() || t.m_lanes.empty())
|
||||
continue;
|
||||
auto & lanes = segment.GetTurnLanes();
|
||||
// Checking if there are elements in lanes which correspond with the turn exactly.
|
||||
// If so fixing up all the elements in lanes which correspond with the turn.
|
||||
if (FixupLaneSet(t.m_turn, lanes, &IsLaneWayConformedTurnDirection))
|
||||
continue;
|
||||
// If not checking if there are elements in lanes which corresponds with the turn
|
||||
// approximately. If so fixing up all these elements.
|
||||
if (FixupLaneSet(t.m_turn, lanes, &IsLaneWayConformedTurnDirectionApproximately))
|
||||
continue;
|
||||
// If not, check if there is an unrestricted lane which could correspond to the
|
||||
// turn. If so, fix up that lane.
|
||||
if (SelectUnrestrictedLane(t.m_turn, lanes))
|
||||
continue;
|
||||
// Otherwise, we don't have lane recommendations for the user, so we don't
|
||||
// want to send the lane data any further.
|
||||
segment.ClearTurnLanes();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace routing
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "routing/route.hpp"
|
||||
#include "routing_common/num_mwm_id.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -24,11 +23,6 @@ protected:
|
||||
virtual void FixupTurns(std::vector<RouteSegment> & routeSegments);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Selects lanes which are recommended for an end user.
|
||||
*/
|
||||
void SelectRecommendedLanes(std::vector<RouteSegment> & routeSegments);
|
||||
|
||||
void FixupCarTurns(std::vector<RouteSegment> & routeSegments);
|
||||
|
||||
/*!
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "routing/data_source.hpp"
|
||||
#include "routing/fake_feature_ids.hpp"
|
||||
#include "routing/lanes/lanes_parser.hpp"
|
||||
#include "routing/routing_helpers.hpp"
|
||||
#include "routing/turns.hpp"
|
||||
|
||||
@@ -36,7 +37,7 @@ feature::Metadata::EType GetLanesMetadataTag(FeatureType & ft, bool isForward)
|
||||
void LoadLanes(LoadedPathSegment & pathSegment, FeatureType & ft, bool isForward)
|
||||
{
|
||||
auto tag = GetLanesMetadataTag(ft, isForward);
|
||||
ParseLanes(std::string(ft.GetMetadata(tag)), pathSegment.m_lanes);
|
||||
pathSegment.m_lanes = lanes::ParseLanes(ft.GetMetadata(tag));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ EdgeEstimator::EdgeEstimator(VehicleType vehicleType, double maxWeightSpeedKMpH,
|
||||
double penalty;
|
||||
};
|
||||
|
||||
#define N 144
|
||||
#define N 288
|
||||
|
||||
static auto constexpr kTurnPenaltyMatrix = []
|
||||
{
|
||||
@@ -348,6 +348,150 @@ EdgeEstimator::EdgeEstimator(VehicleType vehicleType, double maxWeightSpeedKMpH,
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTrunk, VehicleType::Car, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTrunkLink, VehicleType::Car, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayUnclassified, VehicleType::Car, 0.08},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayLivingStreet, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.11},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayService, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayPrimary, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayService, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayPrimaryLink, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayResidential, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayService, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwaySecondary, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.05},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.05},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayService, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.05},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.05},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwaySecondaryLink, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayService, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiary, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTertiaryLink, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.05},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.03},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayService, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.01},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.01},
|
||||
{HighwayType::HighwayTrunk, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.11},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.04},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayService, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.06},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.02},
|
||||
{HighwayType::HighwayTrunkLink, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.1},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayLivingStreet, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayPrimary, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayPrimaryLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayResidential, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwaySecondary, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwaySecondaryLink, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayService, VehicleType::Bicycle, 0.08},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTertiary, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTertiaryLink, VehicleType::Bicycle, 0.07},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTrunk, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayTrunkLink, VehicleType::Bicycle, 0.09},
|
||||
{HighwayType::HighwayUnclassified, HighwayType::HighwayUnclassified, VehicleType::Bicycle, 0.08},
|
||||
}};
|
||||
|
||||
array<TurnPenaltyMatrix, N> result{};
|
||||
@@ -507,10 +651,7 @@ public:
|
||||
double GetUTurnPenalty(Purpose /* purpose */) const override { return 20.0 /* seconds */; }
|
||||
|
||||
double GetTurnPenalty(Purpose purpose, double angle, RoadGeometry const & from_road, RoadGeometry const & to_road,
|
||||
bool is_left_hand_traffic = false) const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
bool is_left_hand_traffic = false) const override;
|
||||
|
||||
double GetFerryLandingPenalty(Purpose purpose) const override
|
||||
{
|
||||
@@ -557,6 +698,35 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
double BicycleEstimator::GetTurnPenalty(Purpose purpose, double angle, RoadGeometry const & from_road,
|
||||
RoadGeometry const & to_road, bool is_left_hand_traffic) const
|
||||
{
|
||||
auto penalty = m_defaultPenalty;
|
||||
|
||||
if (from_road.GetHighwayType().has_value() && to_road.GetHighwayType().has_value())
|
||||
{
|
||||
int const from_road_idx = static_cast<int>(from_road.GetHighwayType().value());
|
||||
int const to_road_idx = static_cast<int>(to_road.GetHighwayType().value());
|
||||
auto const pen = m_turnPenaltyMap.find(from_road_idx * 65535 + to_road_idx);
|
||||
if (pen != m_turnPenaltyMap.end())
|
||||
penalty = pen->second;
|
||||
}
|
||||
|
||||
// Determine if turn crosses traffic based on driving side
|
||||
// For bicycles, crossing traffic is less dangerous than for cars but still a factor
|
||||
bool turn_crosses_traffic;
|
||||
if (is_left_hand_traffic)
|
||||
turn_crosses_traffic = angle < 0;
|
||||
else
|
||||
turn_crosses_traffic = angle > 0;
|
||||
|
||||
// Penalty multiplier for bicycles crossing traffic
|
||||
auto const extra_penalty = turn_crosses_traffic ? 2.0 : 1.0;
|
||||
auto const result = fabs(angle) * penalty * extra_penalty;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// CarEstimator ------------------------------------------------------------------------------------
|
||||
class CarEstimator final : public EdgeEstimator
|
||||
{
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "geometry/latlon.hpp"
|
||||
|
||||
#include "platform/distance.hpp"
|
||||
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
#include "routing/turns.hpp"
|
||||
#include "routing/turns_sound_settings.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@@ -26,23 +24,6 @@ public:
|
||||
, m_pedestrianTurn(turns::PedestrianDirection::None)
|
||||
{}
|
||||
|
||||
// SingleLaneInfoClient is used for passing information about a lane to client platforms such as
|
||||
// Android, iOS and so on.
|
||||
struct SingleLaneInfoClient
|
||||
{
|
||||
std::vector<int8_t> m_lane; // Possible directions for the lane.
|
||||
bool m_isRecommended; // m_isRecommended is true if the lane is recommended for a user.
|
||||
|
||||
explicit SingleLaneInfoClient(turns::SingleLaneInfo const & singleLaneInfo)
|
||||
: m_isRecommended(singleLaneInfo.m_isRecommended)
|
||||
{
|
||||
turns::TSingleLane const & lane = singleLaneInfo.m_lane;
|
||||
m_lane.resize(lane.size());
|
||||
std::transform(lane.cbegin(), lane.cend(), m_lane.begin(),
|
||||
[](turns::LaneWay l) { return static_cast<int8_t>(l); });
|
||||
}
|
||||
};
|
||||
|
||||
bool IsValid() const { return m_distToTarget.IsValid(); }
|
||||
|
||||
/// @name Formatted covered distance.
|
||||
@@ -57,8 +38,8 @@ public:
|
||||
uint32_t m_exitNum;
|
||||
//@}
|
||||
int m_time;
|
||||
// m_lanes contains lane information on the edge before the turn.
|
||||
std::vector<SingleLaneInfoClient> m_lanes;
|
||||
/// Contains lane information on the edge before the turn.
|
||||
turns::lanes::LanesInfo m_lanes;
|
||||
// m_turnNotifications contains information about the next turn notifications.
|
||||
// If there is nothing to pronounce m_turnNotifications is empty.
|
||||
// If there is something to pronounce the size of m_turnNotifications may be one or even more
|
||||
|
||||
@@ -182,11 +182,11 @@ bool ReadSpeedCamsFromMwm(MwmValue const & mwmValue, SpeedCamerasMapT & camerasM
|
||||
}
|
||||
catch (Reader::OpenException const &)
|
||||
{
|
||||
LOG(LWARNING, (CAMERAS_INFO_FILE_TAG "section not found"));
|
||||
LOG(LWARNING, (CAMERAS_INFO_FILE_TAG "section not found in", mwmValue.GetCountryFileName()));
|
||||
}
|
||||
catch (Reader::Exception const & e)
|
||||
{
|
||||
LOG(LERROR, ("Error while reading", CAMERAS_INFO_FILE_TAG, "section.", e.Msg()));
|
||||
LOG(LERROR, ("Error while reading", CAMERAS_INFO_FILE_TAG, "section in", mwmValue.GetCountryFileName(), ":", e.Msg()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -202,11 +202,11 @@ bool ReadRoadAccessFromMwm(MwmValue const & mwmValue, VehicleType vehicleType, R
|
||||
}
|
||||
catch (Reader::OpenException const &)
|
||||
{
|
||||
LOG(LWARNING, (ROAD_ACCESS_FILE_TAG, "section not found"));
|
||||
LOG(LWARNING, (ROAD_ACCESS_FILE_TAG, "section not found in", mwmValue.GetCountryFileName()));
|
||||
}
|
||||
catch (Reader::Exception const & e)
|
||||
{
|
||||
LOG(LERROR, ("Error while reading", ROAD_ACCESS_FILE_TAG, "section.", e.Msg()));
|
||||
LOG(LERROR, ("Error while reading", ROAD_ACCESS_FILE_TAG, "section in", mwmValue.GetCountryFileName(), ":", e.Msg()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -236,11 +236,11 @@ bool ReadRoadPenaltyFromMwm(MwmValue const & mwmValue, VehicleType vehicleType,
|
||||
catch (Reader::OpenException const &)
|
||||
{
|
||||
// This is expected for older mwm files - not an error
|
||||
LOG(LDEBUG, (ROAD_PENALTY_FILE_TAG, "section not found - using legacy penalty system"));
|
||||
LOG(LINFO, (ROAD_PENALTY_FILE_TAG, "section not found in", mwmValue.GetCountryFileName(), "- using legacy penalty system"));
|
||||
}
|
||||
catch (Reader::Exception const & e)
|
||||
{
|
||||
LOG(LERROR, ("Error while reading", ROAD_PENALTY_FILE_TAG, "section.", e.Msg()));
|
||||
LOG(LERROR, ("Error while reading", ROAD_PENALTY_FILE_TAG, "section in", mwmValue.GetCountryFileName(), ":", e.Msg()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
24
libs/routing/lanes/lane_info.cpp
Normal file
24
libs/routing/lanes/lane_info.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "lane_info.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
std::string DebugPrint(LaneInfo const & laneInfo)
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "LaneInfo{" << DebugPrint(laneInfo.laneWays) << ", recommendedWay: " << DebugPrint(laneInfo.recommendedWay)
|
||||
<< "}";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string DebugPrint(LanesInfo const & lanesInfo)
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "LanesInfo[";
|
||||
for (auto const & laneInfo : lanesInfo)
|
||||
out << DebugPrint(laneInfo) << ", ";
|
||||
out << "]";
|
||||
return out.str();
|
||||
}
|
||||
} // namespace routing::turns::lanes
|
||||
23
libs/routing/lanes/lane_info.hpp
Normal file
23
libs/routing/lanes/lane_info.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/lanes/lane_way.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
struct LaneInfo
|
||||
{
|
||||
LaneWays laneWays;
|
||||
LaneWay recommendedWay = LaneWay::None;
|
||||
|
||||
bool operator==(LaneInfo const & rhs) const
|
||||
{
|
||||
return laneWays == rhs.laneWays && recommendedWay == rhs.recommendedWay;
|
||||
}
|
||||
};
|
||||
using LanesInfo = std::vector<LaneInfo>;
|
||||
|
||||
std::string DebugPrint(LaneInfo const & laneInfo);
|
||||
std::string DebugPrint(LanesInfo const & lanesInfo);
|
||||
} // namespace routing::turns::lanes
|
||||
50
libs/routing/lanes/lane_way.cpp
Normal file
50
libs/routing/lanes/lane_way.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "lane_way.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
std::string DebugPrint(LaneWay const laneWay)
|
||||
{
|
||||
using enum LaneWay;
|
||||
switch (laneWay)
|
||||
{
|
||||
case None: return "None";
|
||||
case ReverseLeft: return "ReverseLeft";
|
||||
case SharpLeft: return "SharpLeft";
|
||||
case Left: return "Left";
|
||||
case MergeToLeft: return "MergeToLeft";
|
||||
case SlightLeft: return "SlightLeft";
|
||||
case Through: return "Through";
|
||||
case SlightRight: return "SlightRight";
|
||||
case MergeToRight: return "MergeToRight";
|
||||
case Right: return "Right";
|
||||
case SharpRight: return "SharpRight";
|
||||
case ReverseRight: return "ReverseRight";
|
||||
case Count: return "Count";
|
||||
default:
|
||||
ASSERT_FAIL("Unsupported value: " + std::to_string(static_cast<std::uint8_t>(laneWay)));
|
||||
return "Unsupported";
|
||||
}
|
||||
}
|
||||
|
||||
std::string DebugPrint(LaneWays const & laneWays)
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "LaneWays: [";
|
||||
std::uint8_t const waysCount = laneWays.m_laneWays.count();
|
||||
std::uint8_t waysPrinted = 0;
|
||||
for (std::size_t i = 0; i < laneWays.m_laneWays.size(); ++i)
|
||||
{
|
||||
if (laneWays.m_laneWays.test(i))
|
||||
{
|
||||
out << DebugPrint(static_cast<LaneWay>(i));
|
||||
if (waysPrinted < waysCount - 1)
|
||||
out << ", ";
|
||||
waysPrinted++;
|
||||
}
|
||||
}
|
||||
out << "]";
|
||||
return out.str();
|
||||
}
|
||||
} // namespace routing::turns::lanes
|
||||
84
libs/routing/lanes/lane_way.hpp
Normal file
84
libs/routing/lanes/lane_way.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <bitset>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
enum class LaneWay : std::uint8_t
|
||||
{
|
||||
None = 0,
|
||||
ReverseLeft,
|
||||
SharpLeft,
|
||||
Left,
|
||||
MergeToLeft,
|
||||
SlightLeft,
|
||||
Through,
|
||||
SlightRight,
|
||||
MergeToRight,
|
||||
Right,
|
||||
SharpRight,
|
||||
ReverseRight,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
class LaneWays
|
||||
{
|
||||
using LaneWaysT = std::bitset<static_cast<std::uint8_t>(LaneWay::Count)>;
|
||||
|
||||
friend std::string DebugPrint(LaneWays const & laneWays);
|
||||
|
||||
public:
|
||||
constexpr LaneWays() = default;
|
||||
constexpr LaneWays(std::initializer_list<LaneWay> const laneWays)
|
||||
{
|
||||
for (auto const & laneWay : laneWays)
|
||||
Add(laneWay);
|
||||
}
|
||||
|
||||
constexpr bool operator==(LaneWays const & rhs) const { return m_laneWays == rhs.m_laneWays; }
|
||||
|
||||
constexpr void Add(LaneWay laneWay)
|
||||
{
|
||||
ASSERT_LESS(laneWay, LaneWay::Count, ());
|
||||
m_laneWays.set(static_cast<std::uint8_t>(laneWay));
|
||||
}
|
||||
|
||||
constexpr void Remove(LaneWay laneWay)
|
||||
{
|
||||
ASSERT_LESS(laneWay, LaneWay::Count, ());
|
||||
m_laneWays.reset(static_cast<std::uint8_t>(laneWay));
|
||||
}
|
||||
|
||||
constexpr bool Contains(LaneWay laneWay) const
|
||||
{
|
||||
ASSERT_LESS(laneWay, LaneWay::Count, ());
|
||||
return m_laneWays.test(static_cast<std::uint8_t>(laneWay));
|
||||
}
|
||||
|
||||
/// An unrestricted lane is a lane that has no restrictions, i.e., it contains no lane ways.
|
||||
constexpr bool IsUnrestricted() const
|
||||
{
|
||||
return m_laneWays.none() || (m_laneWays.count() == 1 && Contains(LaneWay::None));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<LaneWay> GetActiveLaneWays() const
|
||||
{
|
||||
std::vector<LaneWay> result;
|
||||
for (std::size_t i = 0; i < m_laneWays.size(); ++i)
|
||||
if (m_laneWays.test(i))
|
||||
result.emplace_back(static_cast<LaneWay>(i));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
LaneWaysT m_laneWays;
|
||||
};
|
||||
|
||||
std::string DebugPrint(LaneWay laneWay);
|
||||
std::string DebugPrint(LaneWays const & laneWays);
|
||||
} // namespace routing::turns::lanes
|
||||
84
libs/routing/lanes/lanes_parser.cpp
Normal file
84
libs/routing/lanes/lanes_parser.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "lanes_parser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::uint8_t constexpr kLaneWayNamesCount = static_cast<std::uint8_t>(LaneWay::Count) + 4;
|
||||
|
||||
/**
|
||||
* The order is important. Starting with the most frequent tokens according to
|
||||
* taginfo.openstreetmap.org we minimize the number of the comparisons in ParseSingleLane().
|
||||
*
|
||||
* A `none` lane can be represented either as "none" or as "". That means both "none" and ""
|
||||
* should be considered names, even though they refer to the same thing. As a result,
|
||||
* `LaneWay::None` appears twice in this array, which is one longer than the number of
|
||||
* enum values.
|
||||
*/
|
||||
std::array<std::pair<LaneWay, std::string_view>, kLaneWayNamesCount> constexpr g_laneWayNames{{
|
||||
{LaneWay::None, ""},
|
||||
{LaneWay::Through, "through"},
|
||||
{LaneWay::Left, "left"},
|
||||
{LaneWay::Right, "right"},
|
||||
{LaneWay::None, "none"},
|
||||
{LaneWay::SharpLeft, "sharp_left"},
|
||||
{LaneWay::SlightLeft, "slight_left"},
|
||||
{LaneWay::MergeToRight, "merge_to_right"},
|
||||
{LaneWay::MergeToLeft, "merge_to_left"},
|
||||
{LaneWay::SlightRight, "slight_right"},
|
||||
{LaneWay::SharpRight, "sharp_right"},
|
||||
{LaneWay::ReverseLeft, "reverse"},
|
||||
{LaneWay::Right,
|
||||
"next_right"}, // "next_right" means "turn right, not in the first intersection but the one after that".
|
||||
{LaneWay::Through, "slide_left"}, // "slide_left" means "move a bit left within the lane".
|
||||
{LaneWay::Through, "slide_right"} // "slide_right" means "move a bit right within the lane".
|
||||
}};
|
||||
|
||||
bool ParseSingleLane(auto && laneWayRange, LaneWay & laneWay)
|
||||
{
|
||||
auto const it = std::ranges::find_if(
|
||||
g_laneWayNames, [&laneWayRange](auto const & pair) { return std::ranges::equal(laneWayRange, pair.second); });
|
||||
if (it != g_laneWayNames.end())
|
||||
{
|
||||
laneWay = it->first;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LanesInfo ParseLanes(std::string_view lanesString)
|
||||
{
|
||||
if (lanesString.empty())
|
||||
return {};
|
||||
|
||||
LanesInfo lanes;
|
||||
for (auto && laneInfo : lanesString | std::views::split('|'))
|
||||
{
|
||||
LaneInfo lane;
|
||||
if (std::ranges::empty(laneInfo))
|
||||
lane.laneWays.Add(LaneWay::None);
|
||||
else
|
||||
{
|
||||
for (auto && laneWay : laneInfo | std::views::split(';'))
|
||||
{
|
||||
auto way = LaneWay::None;
|
||||
auto && laneWayProcessed = laneWay | std::views::filter([](char const c) { return !std::isspace(c); }) |
|
||||
std::views::transform([](char const c) { return std::tolower(c); });
|
||||
if (!ParseSingleLane(laneWayProcessed, way))
|
||||
return {};
|
||||
lane.laneWays.Add(way);
|
||||
if (way == LaneWay::ReverseLeft)
|
||||
lane.laneWays.Add(LaneWay::ReverseRight);
|
||||
}
|
||||
}
|
||||
|
||||
lanes.push_back(lane);
|
||||
}
|
||||
return lanes;
|
||||
}
|
||||
} // namespace routing::turns::lanes
|
||||
16
libs/routing/lanes/lanes_parser.hpp
Normal file
16
libs/routing/lanes/lanes_parser.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
/**
|
||||
* Parse lane information which comes from lanesString
|
||||
* @param lanesString lane information. Example through|through|through|through;right
|
||||
* @return LanesInfo. @see LanesInfo
|
||||
* @note if lanesString is empty, returns empty LanesInfo.
|
||||
*/
|
||||
LanesInfo ParseLanes(std::string_view lanesString);
|
||||
} // namespace routing::turns::lanes
|
||||
129
libs/routing/lanes/lanes_recommendation.cpp
Normal file
129
libs/routing/lanes/lanes_recommendation.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "lanes_recommendation.hpp"
|
||||
|
||||
#include "routing/route.hpp"
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void FixRecommendedReverseLane(LaneWays & ways, LaneWay const recommendedWay)
|
||||
{
|
||||
if (recommendedWay == LaneWay::ReverseLeft)
|
||||
ways.Remove(LaneWay::ReverseRight);
|
||||
else if (recommendedWay == LaneWay::ReverseRight)
|
||||
ways.Remove(LaneWay::ReverseLeft);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SelectRecommendedLanes(std::vector<RouteSegment> & routeSegments)
|
||||
{
|
||||
for (auto & segment : routeSegments)
|
||||
{
|
||||
auto & t = segment.GetTurn();
|
||||
if (t.IsTurnNone() || t.m_lanes.empty())
|
||||
continue;
|
||||
auto & lanesInfo = segment.GetTurnLanes();
|
||||
// Check if there are elements in lanesInfo that correspond with the turn exactly.
|
||||
// If so, fix up all the elements in lanesInfo that correspond with the turn.
|
||||
if (impl::SetRecommendedLaneWays(t.m_turn, lanesInfo))
|
||||
continue;
|
||||
// If not, check if there are elements in lanesInfo that correspond with the turn
|
||||
// approximately. If so, fix up all those elements.
|
||||
if (impl::SetRecommendedLaneWaysApproximately(t.m_turn, lanesInfo))
|
||||
continue;
|
||||
// If not, check if there is an unrestricted lane that could correspond to the
|
||||
// turn. If so, fix up that lane.
|
||||
if (impl::SetUnrestrictedLaneAsRecommended(t.m_turn, lanesInfo))
|
||||
continue;
|
||||
// Otherwise, we don't have lane recommendations for the user, so we don't
|
||||
// want to send the lane data any further.
|
||||
segment.ClearTurnLanes();
|
||||
}
|
||||
}
|
||||
|
||||
bool impl::SetRecommendedLaneWays(CarDirection const carDirection, LanesInfo & lanesInfo)
|
||||
{
|
||||
LaneWay laneWay;
|
||||
switch (carDirection)
|
||||
{
|
||||
case CarDirection::GoStraight: laneWay = LaneWay::Through; break;
|
||||
case CarDirection::TurnRight: laneWay = LaneWay::Right; break;
|
||||
case CarDirection::TurnSharpRight: laneWay = LaneWay::SharpRight; break;
|
||||
case CarDirection::TurnSlightRight: [[fallthrough]];
|
||||
case CarDirection::ExitHighwayToRight: laneWay = LaneWay::SlightRight; break;
|
||||
case CarDirection::TurnLeft: laneWay = LaneWay::Left; break;
|
||||
case CarDirection::TurnSharpLeft: laneWay = LaneWay::SharpLeft; break;
|
||||
case CarDirection::TurnSlightLeft: [[fallthrough]];
|
||||
case CarDirection::ExitHighwayToLeft: laneWay = LaneWay::SlightLeft; break;
|
||||
case CarDirection::UTurnLeft: laneWay = LaneWay::ReverseLeft; break;
|
||||
case CarDirection::UTurnRight: laneWay = LaneWay::ReverseRight; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
bool isLaneConformed = false;
|
||||
for (auto & [laneWays, recommendedWay] : lanesInfo)
|
||||
{
|
||||
if (laneWays.Contains(laneWay))
|
||||
{
|
||||
recommendedWay = laneWay;
|
||||
isLaneConformed = true;
|
||||
}
|
||||
FixRecommendedReverseLane(laneWays, recommendedWay);
|
||||
}
|
||||
return isLaneConformed;
|
||||
}
|
||||
|
||||
bool impl::SetRecommendedLaneWaysApproximately(CarDirection const carDirection, LanesInfo & lanesInfo)
|
||||
{
|
||||
std::vector<LaneWay> approximateLaneWays;
|
||||
switch (carDirection)
|
||||
{
|
||||
case CarDirection::UTurnLeft: approximateLaneWays = {LaneWay::SharpLeft}; break;
|
||||
case CarDirection::TurnSharpLeft: approximateLaneWays = {LaneWay::Left}; break;
|
||||
case CarDirection::TurnLeft: approximateLaneWays = {LaneWay::SlightLeft, LaneWay::SharpLeft}; break;
|
||||
case CarDirection::TurnSlightLeft: [[fallthrough]];
|
||||
case CarDirection::ExitHighwayToLeft: approximateLaneWays = {LaneWay::Left}; break;
|
||||
case CarDirection::GoStraight: approximateLaneWays = {LaneWay::SlightRight, LaneWay::SlightLeft}; break;
|
||||
case CarDirection::ExitHighwayToRight: [[fallthrough]];
|
||||
case CarDirection::TurnSlightRight: approximateLaneWays = {LaneWay::Right}; break;
|
||||
case CarDirection::TurnRight: approximateLaneWays = {LaneWay::SlightRight, LaneWay::SharpRight}; break;
|
||||
case CarDirection::TurnSharpRight: approximateLaneWays = {LaneWay::Right}; break;
|
||||
case CarDirection::UTurnRight: approximateLaneWays = {LaneWay::SharpRight}; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
bool isLaneConformed = false;
|
||||
for (auto & [laneWays, recommendedWay] : lanesInfo)
|
||||
{
|
||||
for (auto const & laneWay : approximateLaneWays)
|
||||
{
|
||||
if (laneWays.Contains(laneWay))
|
||||
{
|
||||
recommendedWay = laneWay;
|
||||
isLaneConformed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isLaneConformed;
|
||||
}
|
||||
|
||||
bool impl::SetUnrestrictedLaneAsRecommended(CarDirection const carDirection, LanesInfo & lanesInfo)
|
||||
{
|
||||
static auto constexpr setFirstUnrestrictedLane = [](LaneWay const laneWay, auto beginIt, auto endIt)
|
||||
{
|
||||
auto it = std::find_if(beginIt, endIt, [](auto const & laneInfo) { return laneInfo.laneWays.IsUnrestricted(); });
|
||||
if (it == endIt)
|
||||
return false;
|
||||
it->recommendedWay = laneWay;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (IsTurnMadeFromLeft(carDirection))
|
||||
return setFirstUnrestrictedLane(LaneWay::Left, lanesInfo.begin(), lanesInfo.end());
|
||||
if (IsTurnMadeFromRight(carDirection))
|
||||
return setFirstUnrestrictedLane(LaneWay::Right, lanesInfo.rbegin(), lanesInfo.rend());
|
||||
return false;
|
||||
}
|
||||
} // namespace routing::turns::lanes
|
||||
31
libs/routing/lanes/lanes_recommendation.hpp
Normal file
31
libs/routing/lanes/lanes_recommendation.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace routing
|
||||
{
|
||||
class RouteSegment;
|
||||
|
||||
namespace turns
|
||||
{
|
||||
enum class CarDirection;
|
||||
} // namespace turns
|
||||
} // namespace routing
|
||||
|
||||
namespace routing::turns::lanes
|
||||
{
|
||||
/// Selects lanes which are recommended for an end user.
|
||||
void SelectRecommendedLanes(std::vector<RouteSegment> & routeSegments);
|
||||
|
||||
// Keep signatures in the header for testing purposes
|
||||
namespace impl
|
||||
{
|
||||
bool SetRecommendedLaneWays(CarDirection carDirection, LanesInfo & lanesInfo);
|
||||
|
||||
bool SetRecommendedLaneWaysApproximately(CarDirection carDirection, LanesInfo & lanesInfo);
|
||||
|
||||
bool SetUnrestrictedLaneAsRecommended(CarDirection carDirection, LanesInfo & lanesInfo);
|
||||
} // namespace impl
|
||||
} // namespace routing::turns::lanes
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/maxspeeds.hpp"
|
||||
#include "routing/road_point.hpp"
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
#include "routing/route.hpp"
|
||||
#include "routing/segment.hpp"
|
||||
#include "routing/turns.hpp"
|
||||
@@ -10,7 +9,6 @@
|
||||
|
||||
#include "geometry/point_with_altitude.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace routing
|
||||
@@ -23,7 +21,7 @@ namespace routing
|
||||
struct LoadedPathSegment
|
||||
{
|
||||
std::vector<geometry::PointWithAltitude> m_path;
|
||||
std::vector<turns::SingleLaneInfo> m_lanes;
|
||||
turns::lanes::LanesInfo m_lanes;
|
||||
RouteSegment::RoadNameInfo m_roadNameInfo;
|
||||
// double m_weight = 0.0; /*!< Time in seconds to pass the segment. */
|
||||
SegmentRange m_segmentRange;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
#include "routing/routing_options.hpp"
|
||||
#include "routing/routing_settings.hpp"
|
||||
#include "routing/segment.hpp"
|
||||
@@ -139,7 +140,7 @@ public:
|
||||
|
||||
void SetTurnExits(uint32_t exitNum) { m_turn.m_exitNum = exitNum; }
|
||||
|
||||
std::vector<turns::SingleLaneInfo> & GetTurnLanes() { return m_turn.m_lanes; }
|
||||
turns::lanes::LanesInfo & GetTurnLanes() { return m_turn.m_lanes; }
|
||||
|
||||
void SetDistancesAndTime(double distFromBeginningMeters, double distFromBeginningMerc, double timeFromBeginningS)
|
||||
{
|
||||
|
||||
@@ -422,15 +422,7 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const
|
||||
// Lane information
|
||||
info.m_lanes.clear();
|
||||
if (distanceToTurnMeters < kShowLanesMinDistInMeters || m_route->GetCurrentTimeToNearestTurnSec() < 60.0)
|
||||
{
|
||||
// There are two nested loops below. Outer one is for lanes and inner one (ctor of
|
||||
// SingleLaneInfo) is
|
||||
// for each lane's directions. The size of turn.m_lanes is relatively small. Less than 10 in
|
||||
// most cases.
|
||||
info.m_lanes.reserve(turn.m_lanes.size());
|
||||
for (size_t j = 0; j < turn.m_lanes.size(); ++j)
|
||||
info.m_lanes.emplace_back(turn.m_lanes[j]);
|
||||
}
|
||||
info.m_lanes = turn.m_lanes;
|
||||
|
||||
// Pedestrian info.
|
||||
info.m_pedestrianTurn =
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
project(routing_tests)
|
||||
|
||||
set(SRC
|
||||
lanes/lanes_parser_tests.cpp
|
||||
lanes/lanes_recommendation_tests.cpp
|
||||
applying_traffic_test.cpp
|
||||
astar_algorithm_test.cpp
|
||||
astar_progress_test.cpp
|
||||
|
||||
160
libs/routing/routing_tests/lanes/lanes_parser_tests.cpp
Normal file
160
libs/routing/routing_tests/lanes/lanes_parser_tests.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing/lanes/lanes_parser.hpp"
|
||||
|
||||
namespace routing::turns::lanes::test
|
||||
{
|
||||
UNIT_TEST(TestParseLaneWays)
|
||||
{
|
||||
std::vector<std::pair<std::string, LaneWays>> const testData = {
|
||||
{";", {LaneWay::None}},
|
||||
{"none", {LaneWay::None}},
|
||||
{"left", {LaneWay::Left}},
|
||||
{"right", {LaneWay::Right}},
|
||||
{"sharp_left", {LaneWay::SharpLeft}},
|
||||
{"slight_left", {LaneWay::SlightLeft}},
|
||||
{"merge_to_right", {LaneWay::MergeToRight}},
|
||||
{"merge_to_left", {LaneWay::MergeToLeft}},
|
||||
{"slight_right", {LaneWay::SlightRight}},
|
||||
{"sharp_right", {LaneWay::SharpRight}},
|
||||
{"reverse", {LaneWay::ReverseLeft, LaneWay::ReverseRight}},
|
||||
{"next_right", {LaneWay::Right}},
|
||||
{"slide_left", {LaneWay::Through}},
|
||||
{"slide_right", {LaneWay::Through}},
|
||||
};
|
||||
|
||||
for (auto const & [in, out] : testData)
|
||||
{
|
||||
LanesInfo const result = ParseLanes(in);
|
||||
LaneWays const expected = {out};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(TestParseSingleLane)
|
||||
{
|
||||
{
|
||||
LanesInfo const result = ParseLanes("through;right");
|
||||
LaneWays constexpr expected = {LaneWay::Through, LaneWay::Right};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("through;Right");
|
||||
LaneWays constexpr expected = {LaneWay::Through, LaneWay::Right};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("through ;Right");
|
||||
LaneWays constexpr expected = {LaneWay::Through, LaneWay::Right};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left;through");
|
||||
LaneWays constexpr expected = {LaneWay::Left, LaneWay::Through};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left");
|
||||
LaneWays constexpr expected = {LaneWay::Left};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left;");
|
||||
LaneWays constexpr expected = {LaneWay::Left, LaneWay::None};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes(";");
|
||||
LaneWays constexpr expected = {LaneWay::None};
|
||||
TEST_EQUAL(result.front().laneWays, expected, ());
|
||||
}
|
||||
|
||||
TEST_EQUAL(ParseLanes("SD32kk*887;;").empty(), true, ());
|
||||
TEST_EQUAL(ParseLanes("Что-то на кириллице").empty(), true, ());
|
||||
TEST_EQUAL(ParseLanes("משהו בעברית").empty(), true, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestParseLanes)
|
||||
{
|
||||
{
|
||||
LanesInfo const result = ParseLanes("through|through|through|through;right");
|
||||
LanesInfo const expected = {
|
||||
{{LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Through, LaneWay::Right}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|left;through|through|through");
|
||||
LanesInfo const expected = {
|
||||
{{LaneWay::Left}}, {{LaneWay::Left, LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Through}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|through|through");
|
||||
LanesInfo const expected = {{{LaneWay::Left}}, {{LaneWay::Through}}, {{LaneWay::Through}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|le ft| through|through | right");
|
||||
LanesInfo const expected = {
|
||||
{{LaneWay::Left}}, {{LaneWay::Left}}, {{LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Right}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|Left|through|througH|right");
|
||||
LanesInfo const expected = {
|
||||
{{LaneWay::Left}}, {{LaneWay::Left}}, {{LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Right}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|Left|through|througH|through;right;sharp_rIght");
|
||||
LanesInfo const expected = {{{LaneWay::Left}},
|
||||
{{LaneWay::Left}},
|
||||
{{LaneWay::Through}},
|
||||
{{LaneWay::Through}},
|
||||
{{LaneWay::Through, LaneWay::Right, LaneWay::SharpRight}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left |Left|through|througH|right");
|
||||
LanesInfo const expected = {
|
||||
{{LaneWay::Left}}, {{LaneWay::Left}}, {{LaneWay::Through}}, {{LaneWay::Through}}, {{LaneWay::Right}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("|||||slight_right");
|
||||
LanesInfo const expected = {{{LaneWay::None}}, {{LaneWay::None}}, {{LaneWay::None}},
|
||||
{{LaneWay::None}}, {{LaneWay::None}}, {{LaneWay::SlightRight}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("|");
|
||||
LanesInfo const expected = {{{LaneWay::None}}, {{LaneWay::None}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes(";|;;;");
|
||||
LanesInfo const expected = {{{LaneWay::None}}, {{LaneWay::None}}};
|
||||
TEST_EQUAL(result, expected, ());
|
||||
}
|
||||
|
||||
{
|
||||
LanesInfo const result = ParseLanes("left|Leftt|through|througH|right");
|
||||
TEST_EQUAL(result.empty(), true, ());
|
||||
}
|
||||
}
|
||||
} // namespace routing::turns::lanes::test
|
||||
221
libs/routing/routing_tests/lanes/lanes_recommendation_tests.cpp
Normal file
221
libs/routing/routing_tests/lanes/lanes_recommendation_tests.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
#include "routing/turns.hpp"
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "routing/lanes/lanes_recommendation.hpp"
|
||||
#include "routing/routing_tests/tools.hpp"
|
||||
|
||||
namespace routing::turns::lanes::test
|
||||
{
|
||||
UNIT_TEST(TestSetRecommendedLaneWays_Smoke)
|
||||
{
|
||||
using impl::SetRecommendedLaneWays;
|
||||
|
||||
struct CarDirectionToLaneWayMapping
|
||||
{
|
||||
CarDirection carDirection;
|
||||
LaneWay laneWay;
|
||||
bool shouldBeRecommended;
|
||||
};
|
||||
std::vector<CarDirectionToLaneWayMapping> const testData = {
|
||||
{CarDirection::GoStraight, LaneWay::Through, true},
|
||||
{CarDirection::TurnRight, LaneWay::Right, true},
|
||||
{CarDirection::TurnSharpRight, LaneWay::SharpRight, true},
|
||||
{CarDirection::TurnSlightRight, LaneWay::SlightRight, true},
|
||||
{CarDirection::TurnLeft, LaneWay::Left, true},
|
||||
{CarDirection::TurnSharpLeft, LaneWay::SharpLeft, true},
|
||||
{CarDirection::TurnSlightLeft, LaneWay::SlightLeft, true},
|
||||
{CarDirection::UTurnLeft, LaneWay::ReverseLeft, true},
|
||||
{CarDirection::UTurnRight, LaneWay::ReverseRight, true},
|
||||
{CarDirection::ExitHighwayToLeft, LaneWay::SlightLeft, true},
|
||||
{CarDirection::ExitHighwayToRight, LaneWay::SlightRight, true},
|
||||
// We do not recommend any lane way for these directions
|
||||
{CarDirection::None, LaneWay::None, false},
|
||||
{CarDirection::EnterRoundAbout, LaneWay::None, false},
|
||||
{CarDirection::LeaveRoundAbout, LaneWay::None, false},
|
||||
{CarDirection::StayOnRoundAbout, LaneWay::None, false},
|
||||
{CarDirection::StartAtEndOfStreet, LaneWay::None, false},
|
||||
{CarDirection::ReachedYourDestination, LaneWay::None, false},
|
||||
};
|
||||
TEST_EQUAL(testData.size(), static_cast<size_t>(CarDirection::Count), ("Not all CarDirection values are covered."));
|
||||
for (auto const & [carDirection, laneWay, shouldBeRecommended] : testData)
|
||||
{
|
||||
LanesInfo lanesInfo = {{{laneWay}}};
|
||||
bool const isRecommended = SetRecommendedLaneWays(carDirection, lanesInfo);
|
||||
TEST_EQUAL(isRecommended, shouldBeRecommended,
|
||||
("CarDirection:", DebugPrint(carDirection), "LaneWay:", DebugPrint(laneWay)));
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, shouldBeRecommended ? laneWay : LaneWay::None, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(TestSetRecommendedLaneWays)
|
||||
{
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::ReverseLeft, LaneWay::Left, LaneWay::Through}},
|
||||
{{LaneWay::Through}},
|
||||
{{LaneWay::Through}},
|
||||
{{LaneWay::Through, LaneWay::Right}},
|
||||
{{LaneWay::Right}},
|
||||
};
|
||||
TEST(impl::SetRecommendedLaneWays(CarDirection::GoStraight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::Through, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::Through, ());
|
||||
TEST_EQUAL(lanesInfo[2].recommendedWay, LaneWay::Through, ());
|
||||
TEST_EQUAL(lanesInfo[3].recommendedWay, LaneWay::Through, ());
|
||||
TEST_EQUAL(lanesInfo[4].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::ReverseLeft, LaneWay::Left}},
|
||||
{{LaneWay::Right}},
|
||||
};
|
||||
TEST(!impl::SetRecommendedLaneWays(CarDirection::GoStraight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::ReverseLeft, LaneWay::ReverseRight}},
|
||||
};
|
||||
TEST(impl::SetRecommendedLaneWays(CarDirection::UTurnLeft, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::ReverseLeft, ());
|
||||
TEST_EQUAL(lanesInfo[0].laneWays.Contains(LaneWay::ReverseRight), false, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(SetRecommendedLaneWaysApproximately_Smoke)
|
||||
{
|
||||
{
|
||||
struct CarDirectionToLaneWaysApproximateMapping
|
||||
{
|
||||
CarDirection carDirection;
|
||||
std::vector<LaneWay> laneWay;
|
||||
};
|
||||
std::vector<CarDirectionToLaneWaysApproximateMapping> const testData = {
|
||||
{CarDirection::UTurnLeft, {LaneWay::SharpLeft}},
|
||||
{CarDirection::TurnSharpLeft, {LaneWay::Left}},
|
||||
{CarDirection::TurnLeft, {LaneWay::SlightLeft, LaneWay::SharpLeft}},
|
||||
{CarDirection::TurnSlightLeft, {LaneWay::Left}},
|
||||
{CarDirection::ExitHighwayToLeft, {LaneWay::Left}},
|
||||
{CarDirection::GoStraight, {LaneWay::SlightRight, LaneWay::SlightLeft}},
|
||||
{CarDirection::ExitHighwayToRight, {LaneWay::Right}},
|
||||
{CarDirection::TurnSlightRight, {LaneWay::Right}},
|
||||
{CarDirection::TurnRight, {LaneWay::SlightRight, LaneWay::SharpRight}},
|
||||
{CarDirection::TurnSharpRight, {LaneWay::Right}},
|
||||
{CarDirection::UTurnRight, {LaneWay::SharpRight}},
|
||||
};
|
||||
for (auto const & [carDirection, laneWays] : testData)
|
||||
{
|
||||
for (auto const & laneWay : laneWays)
|
||||
{
|
||||
LanesInfo lanesInfo = {{{laneWay}}};
|
||||
bool const isRecommended = impl::SetRecommendedLaneWaysApproximately(carDirection, lanesInfo);
|
||||
TEST(isRecommended, ("CarDirection:", DebugPrint(carDirection), "LaneWay:", DebugPrint(laneWay)));
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, laneWay, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Those directions do not have any recommended lane ways.
|
||||
std::vector const carDirections = {CarDirection::None,
|
||||
CarDirection::EnterRoundAbout,
|
||||
CarDirection::LeaveRoundAbout,
|
||||
CarDirection::StayOnRoundAbout,
|
||||
CarDirection::StartAtEndOfStreet,
|
||||
CarDirection::ReachedYourDestination};
|
||||
for (auto const & carDirection : carDirections)
|
||||
{
|
||||
LanesInfo lanesInfo = {{{LaneWay::Through}}};
|
||||
TEST(!impl::SetRecommendedLaneWaysApproximately(carDirection, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(SetRecommendedLaneWaysApproximately)
|
||||
{
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::ReverseLeft, LaneWay::Left, LaneWay::SlightLeft}},
|
||||
{{LaneWay::SlightRight, LaneWay::Right}},
|
||||
{{LaneWay::Right}},
|
||||
};
|
||||
TEST(impl::SetRecommendedLaneWaysApproximately(CarDirection::GoStraight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::SlightLeft, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::SlightRight, ());
|
||||
TEST_EQUAL(lanesInfo[2].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::ReverseLeft, LaneWay::Left}},
|
||||
{{LaneWay::Right}},
|
||||
};
|
||||
TEST(!impl::SetRecommendedLaneWaysApproximately(CarDirection::GoStraight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {
|
||||
{{LaneWay::SharpLeft, LaneWay::SlightLeft}},
|
||||
};
|
||||
TEST(impl::SetRecommendedLaneWaysApproximately(CarDirection::TurnLeft, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::SlightLeft, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(SetUnrestrictedLaneAsRecommended)
|
||||
{
|
||||
LanesInfo const testData = {{{LaneWay::ReverseLeft}}, {{LaneWay::None}}, {{LaneWay::None}}, {{LaneWay::Right}}};
|
||||
{
|
||||
LanesInfo lanesInfo = testData;
|
||||
TEST(impl::SetUnrestrictedLaneAsRecommended(CarDirection::TurnLeft, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::Left, ());
|
||||
TEST_EQUAL(lanesInfo[2].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[3].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = testData;
|
||||
TEST(impl::SetUnrestrictedLaneAsRecommended(CarDirection::TurnRight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[1].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(lanesInfo[2].recommendedWay, LaneWay::Right, ());
|
||||
TEST_EQUAL(lanesInfo[3].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {};
|
||||
TEST(!impl::SetUnrestrictedLaneAsRecommended(CarDirection::TurnRight, lanesInfo), ());
|
||||
}
|
||||
{
|
||||
LanesInfo lanesInfo = {{{LaneWay::Right}}};
|
||||
TEST(!impl::SetUnrestrictedLaneAsRecommended(CarDirection::TurnRight, lanesInfo), ());
|
||||
TEST_EQUAL(lanesInfo[0].recommendedWay, LaneWay::None, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(SelectRecommendedLanes)
|
||||
{
|
||||
std::vector<TurnItem> turns = {{1, CarDirection::GoStraight},
|
||||
{2, CarDirection::TurnLeft},
|
||||
{3, CarDirection::TurnRight},
|
||||
{4, CarDirection::ReachedYourDestination}};
|
||||
turns[0].m_lanes.push_back({{LaneWay::Left, LaneWay::Through}});
|
||||
turns[0].m_lanes.push_back({{LaneWay::Right}});
|
||||
turns[1].m_lanes.push_back({{LaneWay::SlightLeft}});
|
||||
turns[1].m_lanes.push_back({{LaneWay::Through}});
|
||||
turns[1].m_lanes.push_back({{LaneWay::None}});
|
||||
turns[2].m_lanes.push_back({{LaneWay::Left, LaneWay::SharpLeft}});
|
||||
turns[2].m_lanes.push_back({{LaneWay::None}});
|
||||
std::vector<RouteSegment> routeSegments;
|
||||
RouteSegmentsFrom({}, {}, turns, {}, routeSegments);
|
||||
SelectRecommendedLanes(routeSegments);
|
||||
TEST_EQUAL(routeSegments[0].GetTurn().m_lanes[0].recommendedWay, LaneWay::Through, ());
|
||||
TEST_EQUAL(routeSegments[0].GetTurn().m_lanes[1].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(routeSegments[1].GetTurn().m_lanes[0].recommendedWay, LaneWay::SlightLeft, ());
|
||||
TEST_EQUAL(routeSegments[1].GetTurn().m_lanes[1].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(routeSegments[1].GetTurn().m_lanes[2].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(routeSegments[2].GetTurn().m_lanes[0].recommendedWay, LaneWay::None, ());
|
||||
TEST_EQUAL(routeSegments[2].GetTurn().m_lanes[1].recommendedWay, LaneWay::Right, ());
|
||||
}
|
||||
} // namespace routing::turns::lanes::test
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "base/macros.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -65,118 +64,6 @@ private:
|
||||
TUnpackedPathSegments m_segments;
|
||||
};
|
||||
|
||||
UNIT_TEST(TestSplitLanes)
|
||||
{
|
||||
vector<string> result;
|
||||
SplitLanes("through|through|through|through;right", '|', result);
|
||||
vector<string> const expected1 = {"through", "through", "through", "through;right"};
|
||||
TEST_EQUAL(result, expected1, ());
|
||||
|
||||
SplitLanes("adsjkddfasui8747&sxdsdlad8\"\'", '|', result);
|
||||
TEST_EQUAL(result, vector<string>({"adsjkddfasui8747&sxdsdlad8\"\'"}), ());
|
||||
|
||||
SplitLanes("|||||||", '|', result);
|
||||
vector<string> expected2 = {"", "", "", "", "", "", ""};
|
||||
TEST_EQUAL(result, expected2, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestParseSingleLane)
|
||||
{
|
||||
TSingleLane result;
|
||||
TEST(ParseSingleLane("through;right", ';', result), ());
|
||||
TSingleLane const expected1 = {LaneWay::Through, LaneWay::Right};
|
||||
TEST_EQUAL(result, expected1, ());
|
||||
|
||||
TEST(!ParseSingleLane("through;Right", ';', result), ());
|
||||
|
||||
TEST(!ParseSingleLane("through ;right", ';', result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(!ParseSingleLane("SD32kk*887;;", ';', result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(!ParseSingleLane("Что-то на кириллице", ';', result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(!ParseSingleLane("משהו בעברית", ';', result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(ParseSingleLane("left;through", ';', result), ());
|
||||
TSingleLane expected2 = {LaneWay::Left, LaneWay::Through};
|
||||
TEST_EQUAL(result, expected2, ());
|
||||
|
||||
TEST(ParseSingleLane("left", ';', result), ());
|
||||
TEST_EQUAL(result.size(), 1, ());
|
||||
TEST_EQUAL(result[0], LaneWay::Left, ());
|
||||
|
||||
TEST(ParseSingleLane("left;", ';', result), ());
|
||||
TSingleLane expected3 = {LaneWay::Left, LaneWay::None};
|
||||
TEST_EQUAL(result, expected3, ());
|
||||
|
||||
TEST(ParseSingleLane(";", ';', result), ());
|
||||
TSingleLane expected4 = {LaneWay::None, LaneWay::None};
|
||||
TEST_EQUAL(result, expected4, ());
|
||||
|
||||
TEST(ParseSingleLane("", ';', result), ());
|
||||
TSingleLane expected5 = {LaneWay::None};
|
||||
TEST_EQUAL(result, expected5, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestParseLanes)
|
||||
{
|
||||
vector<SingleLaneInfo> result;
|
||||
TEST(ParseLanes("through|through|through|through;right", result), ());
|
||||
vector<SingleLaneInfo> const expected1 = {
|
||||
{LaneWay::Through}, {LaneWay::Through}, {LaneWay::Through}, {LaneWay::Through, LaneWay::Right}};
|
||||
TEST_EQUAL(result, expected1, ());
|
||||
|
||||
TEST(ParseLanes("left|left;through|through|through", result), ());
|
||||
vector<SingleLaneInfo> const expected2 = {
|
||||
{LaneWay::Left}, {LaneWay::Left, LaneWay::Through}, {LaneWay::Through}, {LaneWay::Through}};
|
||||
TEST_EQUAL(result, expected2, ());
|
||||
|
||||
TEST(ParseLanes("left|through|through", result), ());
|
||||
vector<SingleLaneInfo> const expected3 = {{LaneWay::Left}, {LaneWay::Through}, {LaneWay::Through}};
|
||||
TEST_EQUAL(result, expected3, ());
|
||||
|
||||
TEST(ParseLanes("left|le ft| through|through | right", result), ());
|
||||
vector<SingleLaneInfo> const expected4 = {
|
||||
{LaneWay::Left}, {LaneWay::Left}, {LaneWay::Through}, {LaneWay::Through}, {LaneWay::Right}};
|
||||
TEST_EQUAL(result, expected4, ());
|
||||
|
||||
TEST(ParseLanes("left|Left|through|througH|right", result), ());
|
||||
vector<SingleLaneInfo> const expected5 = {
|
||||
{LaneWay::Left}, {LaneWay::Left}, {LaneWay::Through}, {LaneWay::Through}, {LaneWay::Right}};
|
||||
TEST_EQUAL(result, expected5, ());
|
||||
|
||||
TEST(ParseLanes("left|Left|through|througH|through;right;sharp_rIght", result), ());
|
||||
vector<SingleLaneInfo> const expected6 = {{LaneWay::Left},
|
||||
{LaneWay::Left},
|
||||
{LaneWay::Through},
|
||||
{LaneWay::Through},
|
||||
{LaneWay::Through, LaneWay::Right, LaneWay::SharpRight}};
|
||||
TEST_EQUAL(result, expected6, ());
|
||||
|
||||
TEST(!ParseLanes("left|Leftt|through|througH|right", result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(!ParseLanes("Что-то на кириллице", result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(!ParseLanes("משהו בעברית", result), ());
|
||||
TEST_EQUAL(result.size(), 0, ());
|
||||
|
||||
TEST(ParseLanes("left |Left|through|througH|right", result), ());
|
||||
vector<SingleLaneInfo> const expected7 = {
|
||||
{LaneWay::Left}, {LaneWay::Left}, {LaneWay::Through}, {LaneWay::Through}, {LaneWay::Right}};
|
||||
TEST_EQUAL(result, expected7, ());
|
||||
|
||||
TEST(ParseLanes("|||||slight_right", result), ());
|
||||
vector<SingleLaneInfo> const expected8 = {{LaneWay::None}, {LaneWay::None}, {LaneWay::None},
|
||||
{LaneWay::None}, {LaneWay::None}, {LaneWay::SlightRight}};
|
||||
TEST_EQUAL(result, expected8, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestFixupTurns)
|
||||
{
|
||||
double const kHalfSquareSideMeters = 10.;
|
||||
@@ -238,76 +125,6 @@ UNIT_TEST(TestFixupTurns)
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(TestIsLaneWayConformedTurnDirection)
|
||||
{
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::Left, CarDirection::TurnLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::Right, CarDirection::TurnRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::SlightLeft, CarDirection::TurnSlightLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::SharpRight, CarDirection::TurnSharpRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::Reverse, CarDirection::UTurnLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::Reverse, CarDirection::UTurnRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirection(LaneWay::Through, CarDirection::GoStraight), ());
|
||||
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::Left, CarDirection::TurnSlightLeft), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::Right, CarDirection::TurnSharpRight), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::SlightLeft, CarDirection::GoStraight), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::SharpRight, CarDirection::None), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::Reverse, CarDirection::TurnLeft), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::None, CarDirection::ReachedYourDestination), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestIsLaneWayConformedTurnDirectionApproximately)
|
||||
{
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Left, CarDirection::TurnSharpLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Left, CarDirection::TurnSlightLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Right, CarDirection::TurnSharpRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Right, CarDirection::TurnRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Reverse, CarDirection::UTurnLeft), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::Reverse, CarDirection::UTurnRight), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightLeft, CarDirection::GoStraight), ());
|
||||
TEST(IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightRight, CarDirection::GoStraight), ());
|
||||
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpLeft, CarDirection::UTurnLeft), ());
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpLeft, CarDirection::UTurnRight), ());
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpRight, CarDirection::UTurnLeft), ());
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SharpRight, CarDirection::UTurnRight), ());
|
||||
TEST(!IsLaneWayConformedTurnDirection(LaneWay::Through, CarDirection::ReachedYourDestination), ());
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::Through, CarDirection::TurnRight), ());
|
||||
TEST(!IsLaneWayConformedTurnDirectionApproximately(LaneWay::SlightRight, CarDirection::TurnSharpLeft), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestAddingActiveLaneInformation)
|
||||
{
|
||||
vector<turns::TurnItem> turns = {{1, CarDirection::GoStraight},
|
||||
{2, CarDirection::TurnLeft},
|
||||
{3, CarDirection::TurnRight},
|
||||
{4, CarDirection::ReachedYourDestination}};
|
||||
|
||||
turns[0].m_lanes.push_back({LaneWay::Left, LaneWay::Through});
|
||||
turns[0].m_lanes.push_back({LaneWay::Right});
|
||||
|
||||
turns[1].m_lanes.push_back({LaneWay::SlightLeft});
|
||||
turns[1].m_lanes.push_back({LaneWay::Through});
|
||||
turns[1].m_lanes.push_back({LaneWay::None});
|
||||
|
||||
turns[2].m_lanes.push_back({LaneWay::Left, LaneWay::SharpLeft});
|
||||
turns[2].m_lanes.push_back({LaneWay::None});
|
||||
|
||||
vector<RouteSegment> routeSegments;
|
||||
RouteSegmentsFrom({}, {}, turns, {}, routeSegments);
|
||||
SelectRecommendedLanes(routeSegments);
|
||||
|
||||
TEST(routeSegments[0].GetTurn().m_lanes[0].m_isRecommended, ());
|
||||
TEST(!routeSegments[0].GetTurn().m_lanes[1].m_isRecommended, ());
|
||||
|
||||
TEST(routeSegments[1].GetTurn().m_lanes[0].m_isRecommended, ());
|
||||
TEST(!routeSegments[1].GetTurn().m_lanes[1].m_isRecommended, ());
|
||||
TEST(!routeSegments[1].GetTurn().m_lanes[2].m_isRecommended, ());
|
||||
|
||||
TEST(!routeSegments[2].GetTurn().m_lanes[0].m_isRecommended, ());
|
||||
TEST(routeSegments[2].GetTurn().m_lanes[1].m_isRecommended, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TestGetRoundaboutDirection)
|
||||
{
|
||||
// The signature of GetRoundaboutDirection function is
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "platform/country_file.hpp"
|
||||
|
||||
#include "base/internal/message.hpp"
|
||||
#include "base/stl_helpers.hpp"
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -21,28 +19,6 @@ using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
/// The order is important. Starting with the most frequent tokens according to
|
||||
/// taginfo.openstreetmap.org we minimize the number of the comparisons in ParseSingleLane().
|
||||
///
|
||||
/// A `none` lane can be represented either as "none" or as "". That means both "none" and ""
|
||||
/// should be considered names, even though they refer to the same thing. As a result,
|
||||
/// `LaneWay::None` appears twice in this array, which is one longer than the number of
|
||||
/// enum values.
|
||||
array<pair<LaneWay, char const *>, static_cast<size_t>(LaneWay::Count) + 1> const g_laneWayNames = {
|
||||
{{LaneWay::None, ""},
|
||||
{LaneWay::Through, "through"},
|
||||
{LaneWay::Left, "left"},
|
||||
{LaneWay::Right, "right"},
|
||||
{LaneWay::None, "none"},
|
||||
{LaneWay::SharpLeft, "sharp_left"},
|
||||
{LaneWay::SlightLeft, "slight_left"},
|
||||
{LaneWay::MergeToRight, "merge_to_right"},
|
||||
{LaneWay::MergeToLeft, "merge_to_left"},
|
||||
{LaneWay::SlightRight, "slight_right"},
|
||||
{LaneWay::SharpRight, "sharp_right"},
|
||||
{LaneWay::Reverse, "reverse"}}};
|
||||
static_assert(g_laneWayNames.size() == static_cast<size_t>(LaneWay::Count) + 1, "Check the size of g_laneWayNames");
|
||||
|
||||
array<pair<CarDirection, char const *>, static_cast<size_t>(CarDirection::Count)> const g_turnNames = {
|
||||
{{CarDirection::None, "None"},
|
||||
{CarDirection::GoStraight, "GoStraight"},
|
||||
@@ -162,12 +138,6 @@ string DebugPrint(SegmentRange const & segmentRange)
|
||||
|
||||
namespace turns
|
||||
{
|
||||
// SingleLaneInfo ---------------------------------------------------------------------------------
|
||||
bool SingleLaneInfo::operator==(SingleLaneInfo const & other) const
|
||||
{
|
||||
return m_lane == other.m_lane && m_isRecommended == other.m_isRecommended;
|
||||
}
|
||||
|
||||
string DebugPrint(TurnItem const & turnItem)
|
||||
{
|
||||
stringstream out;
|
||||
@@ -232,118 +202,6 @@ bool IsGoStraightOrSlightTurn(CarDirection t)
|
||||
return (t == CarDirection::GoStraight || t == CarDirection::TurnSlightLeft || t == CarDirection::TurnSlightRight);
|
||||
}
|
||||
|
||||
bool IsLaneWayConformedTurnDirection(LaneWay l, CarDirection t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
default: return false;
|
||||
case CarDirection::GoStraight: return l == LaneWay::Through;
|
||||
case CarDirection::TurnRight: return l == LaneWay::Right;
|
||||
case CarDirection::TurnSharpRight: return l == LaneWay::SharpRight;
|
||||
case CarDirection::TurnSlightRight:
|
||||
case CarDirection::ExitHighwayToRight: return l == LaneWay::SlightRight;
|
||||
case CarDirection::TurnLeft: return l == LaneWay::Left;
|
||||
case CarDirection::TurnSharpLeft: return l == LaneWay::SharpLeft;
|
||||
case CarDirection::TurnSlightLeft:
|
||||
case CarDirection::ExitHighwayToLeft: return l == LaneWay::SlightLeft;
|
||||
case CarDirection::UTurnLeft:
|
||||
case CarDirection::UTurnRight: return l == LaneWay::Reverse;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, CarDirection t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
default: return false;
|
||||
case CarDirection::GoStraight: return l == LaneWay::Through || l == LaneWay::SlightRight || l == LaneWay::SlightLeft;
|
||||
case CarDirection::TurnRight: return l == LaneWay::Right || l == LaneWay::SharpRight || l == LaneWay::SlightRight;
|
||||
case CarDirection::TurnSharpRight: return l == LaneWay::SharpRight || l == LaneWay::Right;
|
||||
case CarDirection::TurnSlightRight: return l == LaneWay::SlightRight || l == LaneWay::Through || l == LaneWay::Right;
|
||||
case CarDirection::TurnLeft: return l == LaneWay::Left || l == LaneWay::SlightLeft || l == LaneWay::SharpLeft;
|
||||
case CarDirection::TurnSharpLeft: return l == LaneWay::SharpLeft || l == LaneWay::Left;
|
||||
case CarDirection::TurnSlightLeft: return l == LaneWay::SlightLeft || l == LaneWay::Through || l == LaneWay::Left;
|
||||
case CarDirection::UTurnLeft:
|
||||
case CarDirection::UTurnRight: return l == LaneWay::Reverse;
|
||||
case CarDirection::ExitHighwayToLeft: return l == LaneWay::SlightLeft || l == LaneWay::Left;
|
||||
case CarDirection::ExitHighwayToRight: return l == LaneWay::SlightRight || l == LaneWay::Right;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLaneUnrestricted(SingleLaneInfo const & lane)
|
||||
{
|
||||
/// @todo Is there any reason to store None single lane?
|
||||
return lane.m_lane.size() == 1 && lane.m_lane[0] == LaneWay::None;
|
||||
}
|
||||
|
||||
void SplitLanes(string const & lanesString, char delimiter, vector<string> & lanes)
|
||||
{
|
||||
lanes.clear();
|
||||
istringstream lanesStream(lanesString);
|
||||
string token;
|
||||
while (getline(lanesStream, token, delimiter))
|
||||
lanes.push_back(token);
|
||||
}
|
||||
|
||||
bool ParseSingleLane(string const & laneString, char delimiter, TSingleLane & lane)
|
||||
{
|
||||
lane.clear();
|
||||
// When `laneString` ends with "" representing none, for example, in "right;",
|
||||
// `getline` will not read any characters, so it exits the loop and does not
|
||||
// handle the "". So, we add a delimiter to the end of `laneString`. Nonempty
|
||||
// final tokens consume the delimiter and act as expected, and empty final tokens
|
||||
// read a the delimiter, so `getline` sets `token` to the empty string rather than
|
||||
// exiting the loop.
|
||||
istringstream laneStream(laneString + delimiter);
|
||||
string token;
|
||||
while (getline(laneStream, token, delimiter))
|
||||
{
|
||||
auto const it = find_if(g_laneWayNames.begin(), g_laneWayNames.end(),
|
||||
[&token](pair<LaneWay, string> const & p) { return p.second == token; });
|
||||
if (it == g_laneWayNames.end())
|
||||
return false;
|
||||
lane.push_back(it->first);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseLanes(string lanesString, vector<SingleLaneInfo> & lanes)
|
||||
{
|
||||
if (lanesString.empty())
|
||||
return false;
|
||||
lanes.clear();
|
||||
strings::AsciiToLower(lanesString);
|
||||
base::EraseIf(lanesString, strings::IsASCIISpace<std::string::value_type>);
|
||||
|
||||
vector<string> SplitLanesStrings;
|
||||
SingleLaneInfo lane;
|
||||
SplitLanes(lanesString, '|', SplitLanesStrings);
|
||||
for (string const & s : SplitLanesStrings)
|
||||
{
|
||||
if (!ParseSingleLane(s, ';', lane.m_lane))
|
||||
{
|
||||
lanes.clear();
|
||||
return false;
|
||||
}
|
||||
lanes.push_back(lane);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string DebugPrint(LaneWay const l)
|
||||
{
|
||||
auto const it = find_if(g_laneWayNames.begin(), g_laneWayNames.end(),
|
||||
[&l](pair<LaneWay, string> const & p) { return p.first == l; });
|
||||
|
||||
if (it == g_laneWayNames.end())
|
||||
{
|
||||
stringstream out;
|
||||
out << "unknown LaneWay (" << static_cast<int>(l) << ")";
|
||||
return out.str();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
string DebugPrint(CarDirection const turn)
|
||||
{
|
||||
return GetTurnString(turn);
|
||||
@@ -368,14 +226,6 @@ string DebugPrint(PedestrianDirection const l)
|
||||
return "unknown PedestrianDirection";
|
||||
}
|
||||
|
||||
string DebugPrint(SingleLaneInfo const & singleLaneInfo)
|
||||
{
|
||||
stringstream out;
|
||||
out << "SingleLaneInfo [ m_isRecommended == " << singleLaneInfo.m_isRecommended
|
||||
<< ", m_lane == " << ::DebugPrint(singleLaneInfo.m_lane) << " ]" << endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
double PiMinusTwoVectorsAngle(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint,
|
||||
m2::PointD const & outgoingPoint)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "routing/lanes/lane_info.hpp"
|
||||
#include "routing/segment.hpp"
|
||||
|
||||
#include "routing_common/num_mwm_id.hpp"
|
||||
@@ -8,7 +9,6 @@
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -118,41 +118,6 @@ enum class PedestrianDirection
|
||||
|
||||
std::string DebugPrint(PedestrianDirection const l);
|
||||
|
||||
/*!
|
||||
* \warning The values of LaneWay shall be synchronized with values of LaneWay enum in java.
|
||||
*/
|
||||
enum class LaneWay
|
||||
{
|
||||
None = 0,
|
||||
Reverse,
|
||||
SharpLeft,
|
||||
Left,
|
||||
SlightLeft,
|
||||
MergeToRight,
|
||||
Through,
|
||||
MergeToLeft,
|
||||
SlightRight,
|
||||
Right,
|
||||
SharpRight,
|
||||
Count /**< This value is used for internals only. */
|
||||
};
|
||||
|
||||
std::string DebugPrint(LaneWay const l);
|
||||
|
||||
typedef std::vector<LaneWay> TSingleLane;
|
||||
|
||||
struct SingleLaneInfo
|
||||
{
|
||||
TSingleLane m_lane;
|
||||
bool m_isRecommended = false;
|
||||
|
||||
SingleLaneInfo() = default;
|
||||
SingleLaneInfo(std::initializer_list<LaneWay> const & l) : m_lane(l) {}
|
||||
bool operator==(SingleLaneInfo const & other) const;
|
||||
};
|
||||
|
||||
std::string DebugPrint(SingleLaneInfo const & singleLaneInfo);
|
||||
|
||||
struct TurnItem
|
||||
{
|
||||
TurnItem()
|
||||
@@ -192,7 +157,7 @@ struct TurnItem
|
||||
|
||||
uint32_t m_index; /*!< Index of point on route polyline (Index of segment + 1). */
|
||||
CarDirection m_turn = CarDirection::None; /*!< The turn instruction of the TurnItem */
|
||||
std::vector<SingleLaneInfo> m_lanes; /*!< Lane information on the edge before the turn. */
|
||||
lanes::LanesInfo m_lanes; /*!< Lane information on the edge before the turn. */
|
||||
uint32_t m_exitNum; /*!< Number of exit on roundabout. */
|
||||
/*!
|
||||
* \brief m_pedestrianTurn is type of corresponding direction for a pedestrian, or None
|
||||
@@ -223,39 +188,6 @@ bool IsTurnMadeFromLeft(CarDirection t);
|
||||
bool IsTurnMadeFromRight(CarDirection t);
|
||||
bool IsStayOnRoad(CarDirection t);
|
||||
bool IsGoStraightOrSlightTurn(CarDirection t);
|
||||
|
||||
/*!
|
||||
* \param l A variant of going along a lane.
|
||||
* \param t A turn direction.
|
||||
* \return True if @l corresponds with @t exactly. For example it returns true
|
||||
* when @l equals to LaneWay::Right and @t equals to TurnDirection::TurnRight.
|
||||
* Otherwise it returns false.
|
||||
*/
|
||||
bool IsLaneWayConformedTurnDirection(LaneWay l, CarDirection t);
|
||||
|
||||
/*!
|
||||
* \param l A variant of going along a lane.
|
||||
* \param t A turn direction.
|
||||
* \return True if @l corresponds with @t approximately. For example it returns true
|
||||
* when @l equals to LaneWay::Right and @t equals to TurnDirection::TurnSlightRight.
|
||||
* Otherwise it returns false.
|
||||
*/
|
||||
bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, CarDirection t);
|
||||
|
||||
bool IsLaneUnrestricted(SingleLaneInfo const & lane);
|
||||
|
||||
/*!
|
||||
* \brief Parse lane information which comes from @lanesString
|
||||
* \param lanesString lane information. Example through|through|through|through;right
|
||||
* \param lanes the result of parsing.
|
||||
* \return true if @lanesString parsed successfully, false otherwise.
|
||||
* Note 1: if @lanesString is empty returns false.
|
||||
* Note 2: @laneString is passed by value on purpose. It'll be used(changed) in the method.
|
||||
*/
|
||||
bool ParseLanes(std::string lanesString, std::vector<SingleLaneInfo> & lanes);
|
||||
void SplitLanes(std::string const & lanesString, char delimiter, std::vector<std::string> & lanes);
|
||||
bool ParseSingleLane(std::string const & laneString, char delimiter, TSingleLane & lane);
|
||||
|
||||
/*!
|
||||
* \returns pi minus angle from vector [junctionPoint, ingoingPoint]
|
||||
* to vector [junctionPoint, outgoingPoint]. A counterclockwise rotation.
|
||||
|
||||
@@ -115,11 +115,16 @@ private:
|
||||
|
||||
static bool HouseNumbersMatch(FeatureType & feature, std::vector<house_numbers::Token> const & queryParse)
|
||||
{
|
||||
ASSERT(!queryParse.empty(), ());
|
||||
|
||||
auto const interpol = ftypes::IsAddressInterpolChecker::Instance().GetInterpolType(feature);
|
||||
if (interpol != feature::InterpolType::None)
|
||||
return house_numbers::HouseNumbersMatchRange(feature.GetRef(), queryParse, interpol);
|
||||
|
||||
auto const uniHouse = strings::MakeUniString(feature.GetHouseNumber());
|
||||
if (uniHouse.empty())
|
||||
return false;
|
||||
|
||||
if (feature.GetID().IsEqualCountry({"Czech", "Slovakia"}))
|
||||
return house_numbers::HouseNumbersMatchConscription(uniHouse, queryParse);
|
||||
|
||||
@@ -327,6 +332,9 @@ private:
|
||||
if (std::binary_search(buildings.begin(), buildings.end(), houseId))
|
||||
return true;
|
||||
|
||||
if (!child.m_hasDelayedFeatures || queryParse.empty())
|
||||
return false;
|
||||
|
||||
if (m_postcodes && !m_postcodes->HasBit(houseId) && !m_postcodes->HasBit(streetId))
|
||||
return false;
|
||||
|
||||
@@ -334,9 +342,6 @@ private:
|
||||
if (!feature)
|
||||
return false;
|
||||
|
||||
if (!child.m_hasDelayedFeatures)
|
||||
return false;
|
||||
|
||||
return HouseNumbersMatch(*feature, queryParse);
|
||||
};
|
||||
|
||||
@@ -384,6 +389,8 @@ private:
|
||||
|
||||
std::vector<house_numbers::Token> queryParse;
|
||||
ParseQuery(child.m_subQuery, child.m_lastTokenIsPrefix, queryParse);
|
||||
if (queryParse.empty())
|
||||
return;
|
||||
|
||||
uint32_t numFilterInvocations = 0;
|
||||
auto const houseNumberFilter = [&](uint32_t houseId)
|
||||
|
||||
@@ -47,9 +47,19 @@ void HighlightResult(QueryTokens const & tokens, strings::UniString const & pref
|
||||
CombinedIter beg(tokens.begin(), tokens.end(), prefix.empty() ? nullptr : &prefix);
|
||||
CombinedIter end(tokens.end() /* cur */, tokens.end() /* end */, nullptr);
|
||||
|
||||
// Highlight Title
|
||||
// Highlight Title (potentially including branch)
|
||||
std::string titleForHighlighting = res.GetString();
|
||||
std::string const & branch = res.GetBranch();
|
||||
|
||||
// If we have a branch that is not already in the title, create combined string for highlighting
|
||||
// This matches the iOS UI behavior where branch is appended as " branchText"
|
||||
if (!branch.empty() && titleForHighlighting.find(branch) == std::string::npos)
|
||||
{
|
||||
titleForHighlighting += " " + branch;
|
||||
}
|
||||
|
||||
SearchStringTokensIntersectionRanges(
|
||||
res.GetString(), beg, end, [&](std::pair<uint16_t, uint16_t> const & range) { res.AddHighlightRange(range); });
|
||||
titleForHighlighting, beg, end, [&](std::pair<uint16_t, uint16_t> const & range) { res.AddHighlightRange(range); });
|
||||
|
||||
// Highlight description.
|
||||
SearchStringTokensIntersectionRanges(res.GetAddress(), beg, end, [&](std::pair<uint16_t, uint16_t> const & range)
|
||||
|
||||
@@ -516,8 +516,7 @@ void ParseQuery(UniString const & query, bool queryIsPrefix, TokensT & parse)
|
||||
|
||||
bool HouseNumbersMatch(UniString const & houseNumber, TokensT const & queryParse)
|
||||
{
|
||||
if (houseNumber.empty() || queryParse.empty())
|
||||
return false;
|
||||
ASSERT(!houseNumber.empty() && !queryParse.empty(), ());
|
||||
|
||||
// Fast pre-check, helps to early exit without complex house number parsing.
|
||||
if (IsASCIIDigit(houseNumber[0]) && IsASCIIDigit(queryParse[0].m_value[0]) &&
|
||||
@@ -559,7 +558,7 @@ bool HouseNumbersMatchConscription(UniString const & houseNumber, TokensT const
|
||||
bool HouseNumbersMatchRange(std::string_view const & hnRange, TokensT const & queryParse,
|
||||
feature::InterpolType interpol)
|
||||
{
|
||||
ASSERT(interpol != feature::InterpolType::None, ());
|
||||
ASSERT(!queryParse.empty() && interpol != feature::InterpolType::None, ());
|
||||
|
||||
if (queryParse[0].m_type != Token::TYPE_NUMBER)
|
||||
return false;
|
||||
|
||||
@@ -19,17 +19,37 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
/// @todo Should process synonyms with errors like "blvrd" -> "blvd".
|
||||
/// @see HouseOnStreetSynonymsWithMisprints test.
|
||||
{"1", {"pierwszy", "pierwsza", "un", "una", "pierwsze", "primo"}},
|
||||
{"1st", {"first"}},
|
||||
{"1°", {"primo"}},
|
||||
{"20", {"venti"}},
|
||||
{"25", {"venticinque"}},
|
||||
{"2", {"due", "drugi", "drugie", "druga"}},
|
||||
{"2nd", {"second"}},
|
||||
{"3", {"trzecia", "trzecie", "tre", "trzeci"}},
|
||||
{"3rd", {"third"}},
|
||||
{"4", {"quattro"}},
|
||||
{"4th", {"fourth"}},
|
||||
{"5", {"cinque"}},
|
||||
{"5th", {"fifth"}},
|
||||
{"6", {"sei"}},
|
||||
{"6th", {"sixth"}},
|
||||
{"7", {"sette"}},
|
||||
{"7th", {"seventh"}},
|
||||
{"8", {"otto"}},
|
||||
{"8th", {"eighth"}},
|
||||
{"9", {"nove"}},
|
||||
{"9th", {"ninth"}},
|
||||
{"10th", {"tenth"}},
|
||||
{"11th", {"eleventh"}},
|
||||
{"12th", {"twelfth"}},
|
||||
{"13th", {"thirteenth"}},
|
||||
{"14th", {"fourteenth"}},
|
||||
{"15th", {"fifteenth"}},
|
||||
{"16th", {"sixteenth"}},
|
||||
{"17th", {"seventeenth"}},
|
||||
{"18th", {"eighteenth"}},
|
||||
{"19th", {"nineteenth"}},
|
||||
{"20th", {"twentieth"}},
|
||||
{"a", {"am", "auto-estrada"}},
|
||||
{"abe", {"abbaye"}},
|
||||
{"accs", {"access"}},
|
||||
@@ -108,7 +128,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"bast", {"baston"}},
|
||||
{"bat", {"batalionu", "batalion", "batalionów", "bataliony"}},
|
||||
{"bayer", {"bayerische", "bayerisch", "bayerischer", "bayerisches"}},
|
||||
{"b", {"berg", "barri", "bach", "barriada", "banda", "bairro", "bad"}},
|
||||
{"b", {"berg", "barri", "bach", "barriada", "banda", "bairro", "bad", "bei"}},
|
||||
{"bc", {"beco"}},
|
||||
{"bch", {"bas chemin", "beach"}},
|
||||
{"bcle", {"boucle"}},
|
||||
@@ -187,7 +207,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"cal", {"calea"}},
|
||||
{"cale", {"cale"}},
|
||||
{"callej", {"callejón"}},
|
||||
{"cam", {"caminho"}},
|
||||
{"cam", {"caminho", "camino"}},
|
||||
{"campg", {"camping"}},
|
||||
{"cant", {"cantón", "cantonada"}},
|
||||
{"canti", {"cantina"}},
|
||||
@@ -203,11 +223,13 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"cav", {"cavée"}},
|
||||
{"cbtiz", {"cobertizo"}},
|
||||
{"cc", {"calçada", "centro comercial"}},
|
||||
{"call", {"calleja", "callejón"}},
|
||||
{"c", {"cesta", "carrer", "calle", "centre"}},
|
||||
{"cckq", {"căn cứ không quân"}},
|
||||
{"ccnh", {"calçadinha"}},
|
||||
{"cct", {"circuit"}},
|
||||
{"ccvcn", {"circunvalación"}},
|
||||
{"cad", {"cadde"}},
|
||||
{"cd", {"cadde", "caddesi"}},
|
||||
{"cđ", {"cao đẳng"}},
|
||||
{"cds", {"cul-de-sac"}},
|
||||
@@ -318,6 +340,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"cstan", {"costanilla"}},
|
||||
{"cst", {"castel", "crest"}},
|
||||
{"cswy", {"causeway"}},
|
||||
{"cta", {"cuesta"}},
|
||||
{"ct", {"court", "công trường"}},
|
||||
{"ctcp", {"công ty cổ phần"}},
|
||||
{"ctra", {"carretera"}},
|
||||
@@ -395,7 +418,10 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"egl", {"église"}},
|
||||
{"égl", {"église"}},
|
||||
{"ehem", {"ehemalige", "ehemaliger", "ehemaliges"}},
|
||||
{"eighth", {"8th"}},
|
||||
{"eighteenth", {"18th"}},
|
||||
{"elb", {"elbow"}},
|
||||
{"eleventh", {"11th"}},
|
||||
{"emb", {"embaixador"}},
|
||||
{"em", {"estrada municipal"}},
|
||||
{"empr", {"empresa"}},
|
||||
@@ -456,6 +482,9 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"fg", {"faubourg"}},
|
||||
{"fh", {"fachhochschule", "forsthaus"}},
|
||||
{"fit", {"firetrail"}},
|
||||
{"fifth", {"5th"}},
|
||||
{"fifteenth", {"15th"}},
|
||||
{"first", {"1st"}},
|
||||
{"flat", {"flat"}},
|
||||
{"fl", {"flat"}},
|
||||
{"fnd", {"fundătura"}},
|
||||
@@ -463,6 +492,8 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"fon", {"fontaine"}},
|
||||
{"form", {"forum", "formation"}},
|
||||
{"fos", {"fosses", "fosse"}},
|
||||
{"fourth", {"4th"}},
|
||||
{"fourteenth", {"14th"}},
|
||||
{"foyr", {"foyer"}},
|
||||
{"fr", {"father", "frontage", "frei"}},
|
||||
{"frm", {"ferme", "fermes"}},
|
||||
@@ -735,6 +766,8 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"ne", {"northeast"}},
|
||||
{"nh", {"nhà hát"}},
|
||||
{"nhs", {"national high school"}},
|
||||
{"ninth", {"9th"}},
|
||||
{"nineteenth", {"19th"}},
|
||||
{"nk", {"nook"}},
|
||||
{"nms", {"neue mittelschule"}},
|
||||
{"n", {"nowy", "nowa", "nossa", "norra", "número", "north", "nosso", "nacional", "nowe"}},
|
||||
@@ -823,6 +856,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"pim", {"petite impasse"}},
|
||||
{"pi", {"polígon industrial"}},
|
||||
{"pj", {"polícia judiciária"}},
|
||||
{"pje", {"pasaje"}},
|
||||
{"pkg", {"parking"}},
|
||||
{"pkld", {"parklands"}},
|
||||
{"pko", {"puistikko"}},
|
||||
@@ -860,7 +894,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"port", {"port"}},
|
||||
{"pot", {"poterne"}},
|
||||
{"pour", {"pourtour"}},
|
||||
{"p", {"pfad", "polku", "phường", "pater"}},
|
||||
{"p", {"pfad", "polku", "phường", "pater", "paseo"}},
|
||||
{"pplk", {"podplukovníka"}},
|
||||
{"ppłk", {"ppułkownika", "podpułkownika", "podpułkownik"}},
|
||||
{"ppor", {"podporučíka"}},
|
||||
@@ -974,7 +1008,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"roc", {"roc", "rocade"}},
|
||||
{"roqt", {"roquet"}},
|
||||
{"rotm", {"rotmistrza", "rotmistrz"}},
|
||||
{"rot", {"rotunda"}},
|
||||
{"rot", {"rotunda", "rotonda"}},
|
||||
{"row", {"row"}},
|
||||
{"rowy", {"right of way"}},
|
||||
{"rpe", {"rampe"}},
|
||||
@@ -1016,11 +1050,14 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"sdn", {"sekolah dasar negeri"}},
|
||||
{"sdr", {"søndre", "sønder"}},
|
||||
{"sd", {"strand", "sekolah dasar"}},
|
||||
{"second", {"2nd"}},
|
||||
{"sect", {"sector"}},
|
||||
{"sedra", {"sendera"}},
|
||||
{"send", {"sendero"}},
|
||||
{"sen", {"sente", "senator", "sentiers", "sentier", "sentes"}},
|
||||
{"sent", {"sentier"}},
|
||||
{"seventh", {"7th"}},
|
||||
{"seventeenth", {"17th"}},
|
||||
{"se", {"southeast"}},
|
||||
{"sgda", {"sagrada"}},
|
||||
{"sg", {"schottergrube", "sungai", "sandgrube"}},
|
||||
@@ -1030,6 +1067,8 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"shun", {"shunt"}},
|
||||
{"shwy", {"state highway"}},
|
||||
{"sídl", {"sídlisko"}},
|
||||
{"sixth", {"6th"}},
|
||||
{"sixteenth", {"16th"}},
|
||||
{"sk", {"sokak", "sokağı"}},
|
||||
{"slj", {"sobre-loja"}},
|
||||
{"slov", {"slovenskih"}},
|
||||
@@ -1085,7 +1124,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
/// Remove "street" and "avenue" here, but should update GetNameScore.
|
||||
{"st",
|
||||
{"santo", "sant", "sint", "saint", "stara", "street", "stary", "stora", "sankt", "store", "stare", "stig",
|
||||
"stigen"}},
|
||||
"stigen", "sancta"}},
|
||||
{"št", {"šent"}},
|
||||
{"stwg", {"steenweg"}},
|
||||
{"subdiv", {"subdivision"}},
|
||||
@@ -1103,12 +1142,15 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"tct", {"tổng công ty"}},
|
||||
{"tcty", {"tổng công ty"}},
|
||||
{"ten", {"tenente"}},
|
||||
{"tenth", {"10th"}},
|
||||
{"term", {"terminal"}},
|
||||
{"terr", {"terrace"}},
|
||||
{"ter", {"terrace"}},
|
||||
{"tg", {"tanjong"}},
|
||||
{"thcs", {"trung học cơ sở"}},
|
||||
{"thfr", {"thoroughfare"}},
|
||||
{"third", {"3rd"}},
|
||||
{"thirteenth", {"13th"}},
|
||||
{"thor", {"thoroughfare"}},
|
||||
{"thpt", {"trung học phổ thông"}},
|
||||
{"th", {"tiểu học", "tienhaara"}},
|
||||
@@ -1150,6 +1192,8 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"tu", {"technische universität"}},
|
||||
{"tvl", {"taival"}},
|
||||
{"tv", {"travessa"}},
|
||||
{"twelfth", {"12th"}},
|
||||
{"twentieth", {"20th"}},
|
||||
{"twp", {"township"}},
|
||||
{"twrs", {"towers"}},
|
||||
{"twy", {"tollway"}},
|
||||
@@ -1256,7 +1300,7 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"yd", {"yard"}},
|
||||
{"zac", {"zone d'aménagement concerté"}},
|
||||
{"zad", {"zone d'aménagement différé"}},
|
||||
{"za", {"zone artisanale"}},
|
||||
{"za", {"zone artisanale", "zone d'activité"}},
|
||||
{"zd", {"zdravstveni dom"}},
|
||||
{"zg", {"zgornja", "zgornji", "zgornje"}},
|
||||
{"zi", {"zone industrielle"}},
|
||||
@@ -1358,7 +1402,9 @@ unordered_map<string, vector<string>> const kSynonyms = {
|
||||
{"高", {"高等学校"}},
|
||||
{"ش", {"شارع"}},
|
||||
{"ط", {"طريق"}},
|
||||
{"م", {"ميدان"}}
|
||||
{"م", {"ميدان"}},
|
||||
{"د", {"دكتور"}},
|
||||
{"ج", {"جامعة"}}
|
||||
/*
|
||||
These synonyms are currently unreachable per https://codeberg.org/comaps/comaps/issues/1242
|
||||
{"arm. gen", {"armádneho generála"}},
|
||||
|
||||
@@ -732,6 +732,16 @@ Result Ranker::MakeResult(RankerResult const & rankerResult, bool needAddress, b
|
||||
case RankerResult::Type::Building:
|
||||
res.FromFeature(rankerResult.GetID(), rankerResult.GetBestType(),
|
||||
rankerResult.GetBestType(&m_params.m_preferredTypes), rankerResult.m_details);
|
||||
|
||||
// Extract branch metadata if available
|
||||
if (rankerResult.GetID().IsValid())
|
||||
{
|
||||
m_dataSource.ReadFeature([&](FeatureType & ft) {
|
||||
auto const branch = ft.GetMetadata(feature::Metadata::FMD_BRANCH);
|
||||
if (!branch.empty())
|
||||
res.SetBranch(std::string(branch));
|
||||
}, rankerResult.GetID());
|
||||
}
|
||||
break;
|
||||
case RankerResult::Type::LatLon: res.SetType(Result::Type::LatLon); break;
|
||||
case RankerResult::Type::Postcode: res.SetType(Result::Type::Postcode); break;
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
void FromFeature(FeatureID const & id, uint32_t mainType, uint32_t matchedType, Details const & details);
|
||||
|
||||
void SetAddress(std::string && address) { m_address = std::move(address); }
|
||||
void SetBranch(std::string && branch) { m_branch = std::move(branch); }
|
||||
void SetType(Result::Type type) { m_resultType = type; }
|
||||
|
||||
// For Type::PureSuggest.
|
||||
@@ -75,6 +76,7 @@ public:
|
||||
std::string const & GetString() const { return m_str; }
|
||||
std::string const & GetAddress() const { return m_address; }
|
||||
std::string const & GetDescription() const { return m_details.m_description; }
|
||||
std::string const & GetBranch() const { return m_branch; }
|
||||
|
||||
osm::YesNoUnknown IsOpenNow() const { return m_details.m_isOpenNow; }
|
||||
uint16_t GetMinutesUntilOpen() const { return m_details.m_minutesUntilOpen; }
|
||||
@@ -152,6 +154,7 @@ private:
|
||||
m2::PointD m_center;
|
||||
std::string m_str;
|
||||
std::string m_address;
|
||||
std::string m_branch;
|
||||
uint32_t m_mainType = 0;
|
||||
uint32_t m_matchedType = 0;
|
||||
std::string m_suggestionStr;
|
||||
|
||||
@@ -26,6 +26,8 @@ set(shader_files
|
||||
GL/debug_rect.vsh.glsl
|
||||
GL/hatching_area.fsh.glsl
|
||||
GL/hatching_area.vsh.glsl
|
||||
GL/imgui.fsh.glsl
|
||||
GL/imgui.vsh.glsl
|
||||
GL/line.fsh.glsl
|
||||
GL/line.vsh.glsl
|
||||
GL/masked_texturing.fsh.glsl
|
||||
@@ -41,7 +43,9 @@ set(shader_files
|
||||
GL/route_dash.fsh.glsl
|
||||
GL/route_marker.fsh.glsl
|
||||
GL/route_marker.vsh.glsl
|
||||
GL/ruler.fsh.glsl
|
||||
GL/ruler.vsh.glsl
|
||||
GL/screen_quad.fsh.glsl
|
||||
GL/screen_quad.vsh.glsl
|
||||
GL/selection_line.fsh.glsl
|
||||
GL/selection_line.vsh.glsl
|
||||
@@ -58,12 +62,15 @@ set(shader_files
|
||||
GL/text_billboard.vsh.glsl
|
||||
GL/text_outlined.vsh.glsl
|
||||
GL/text_outlined_billboard.vsh.glsl
|
||||
GL/text_outlined_gui.fsh.glsl
|
||||
GL/text_outlined_gui.vsh.glsl
|
||||
GL/texturing.fsh.glsl
|
||||
GL/texturing.vsh.glsl
|
||||
GL/texturing3d.fsh.glsl
|
||||
GL/texturing_billboard.vsh.glsl
|
||||
GL/texturing_gui.fsh.glsl
|
||||
GL/texturing_gui.vsh.glsl
|
||||
GL/texturing_position.fsh.glsl
|
||||
GL/traffic.fsh.glsl
|
||||
GL/traffic.vsh.glsl
|
||||
GL/traffic_circle.fsh.glsl
|
||||
|
||||
@@ -50,12 +50,10 @@ class GLTypeWrapper;
|
||||
|
||||
BIND_GL_TYPE(float, gl_const::GLFloatType)
|
||||
BIND_GL_TYPE(glsl::vec2, gl_const::GLFloatVec2)
|
||||
BIND_GL_TYPE(glsl::vec3, gl_const::GLFloatVec4)
|
||||
BIND_GL_TYPE(glsl::vec4, gl_const::GLFloatVec4)
|
||||
BIND_GL_TYPE(glsl::mat4, gl_const::GLFloatMat4)
|
||||
BIND_GL_TYPE(int, gl_const::GLIntType)
|
||||
BIND_GL_TYPE(glsl::ivec2, gl_const::GLIntVec2)
|
||||
BIND_GL_TYPE(glsl::ivec3, gl_const::GLIntVec4)
|
||||
BIND_GL_TYPE(glsl::ivec4, gl_const::GLIntVec4)
|
||||
|
||||
class Parameter
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
project(shaders_tests)
|
||||
|
||||
execute_process(
|
||||
COMMAND rm -rf ${CMAKE_BINARY_DIR}/shaders_compiler
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND cp -r ${OMIM_ROOT}/tools/shaders_compiler ${CMAKE_BINARY_DIR}/shaders_compiler
|
||||
)
|
||||
|
||||
set(SRC
|
||||
gl_shaders_desktop_compile_tests.cpp
|
||||
gl_program_params_tests.cpp
|
||||
|
||||
Reference in New Issue
Block a user