Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Viktor Govako
382385a7ec [routing] Alternative routes after GSoC 2022.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2024-05-10 12:47:51 -03:00
20 changed files with 427 additions and 13 deletions

View file

@ -10,6 +10,12 @@ routing::RoutingOptions::Road makeValue(jint option)
return static_cast<routing::RoutingOptions::Road>(road);
}
routing::EdgeEstimator::Strategy makeStrategyValue(jint strategy)
{
int convertedStrat = static_cast<int>(strategy);
return static_cast<routing::EdgeEstimator::Strategy>(convertedStrat);
}
extern "C"
{
@ -22,6 +28,14 @@ Java_app_organicmaps_routing_RoutingOptions_nativeHasOption(JNIEnv * env, jclass
return static_cast<jboolean>(routingOptions.Has(road));
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_routing_RoutingOptions_nativeGetStrategy(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
routing::EdgeEstimator::Strategy routingStrategy = routing::EdgeEstimator::LoadRoutingStrategyFromSettings();
return static_cast<jint>(routingStrategy);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_routing_RoutingOptions_nativeAddOption(JNIEnv * env, jclass clazz, jint option)
{
@ -32,7 +46,6 @@ Java_app_organicmaps_routing_RoutingOptions_nativeAddOption(JNIEnv * env, jclass
routing::RoutingOptions::SaveCarOptionsToSettings(routingOptions);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_routing_RoutingOptions_nativeRemoveOption(JNIEnv * env, jclass clazz, jint option)
{
@ -42,4 +55,11 @@ Java_app_organicmaps_routing_RoutingOptions_nativeRemoveOption(JNIEnv * env, jcl
routingOptions.Remove(road);
routing::RoutingOptions::SaveCarOptionsToSettings(routingOptions);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_routing_RoutingOptions_nativeSetStrategy(JNIEnv * env, jclass clazz, jint strategy)
{
CHECK(g_framework, ("Framework isn't created yet!"));
routing::EdgeEstimator::SaveRoutingStrategyToSettings(makeStrategyValue(strategy));
}
}

View file

@ -3,6 +3,7 @@ package app.organicmaps.routing;
import androidx.annotation.NonNull;
import app.organicmaps.settings.RoadType;
import app.organicmaps.settings.RoutingStrategyType;
import java.util.HashSet;
import java.util.Set;
@ -24,9 +25,21 @@ public class RoutingOptions
return nativeHasOption(roadType.ordinal());
}
public static int getStrategy()
{
return nativeGetStrategy();
}
public static void setStrategy(@NonNull RoutingStrategyType routingStrategyType)
{
nativeSetStrategy(routingStrategyType.ordinal());
}
private static native void nativeAddOption(int option);
private static native void nativeRemoveOption(int option);
private static native boolean nativeHasOption(int option);
private static native int nativeGetStrategy();
private static native void nativeSetStrategy(int strategy);
public static boolean hasAnyOptions()
{
@ -49,4 +62,10 @@ public class RoutingOptions
}
return roadTypes;
}
public static RoutingStrategyType getActiveRoutingStrategyType()
{
int strategyType = getStrategy();
return RoutingStrategyType.values()[strategyType];
}
}

View file

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -25,8 +26,11 @@ import java.util.Set;
public class DrivingOptionsFragment extends BaseMwmToolbarFragment
{
public static final String BUNDLE_ROAD_TYPES = "road_types";
public static final String BUNDLE_ROUTING_STRATEGY_TYPE = "routing_strategy_type";
@NonNull
private Set<RoadType> mRoadTypes = Collections.emptySet();
@NonNull
private RoutingStrategyType mStrategy = RoutingStrategyType.Fastest;
@Nullable
@Override
@ -38,6 +42,9 @@ public class DrivingOptionsFragment extends BaseMwmToolbarFragment
mRoadTypes = savedInstanceState != null && savedInstanceState.containsKey(BUNDLE_ROAD_TYPES)
? makeRouteTypes(savedInstanceState)
: RoutingOptions.getActiveRoadTypes();
mStrategy = savedInstanceState != null && savedInstanceState.containsKey(BUNDLE_ROUTING_STRATEGY_TYPE)
? makeRoutingStrategyType(savedInstanceState)
: RoutingOptions.getActiveRoutingStrategyType();
return root;
}
@ -53,6 +60,13 @@ public class DrivingOptionsFragment extends BaseMwmToolbarFragment
return result;
}
@NonNull
private RoutingStrategyType makeRoutingStrategyType(@NonNull Bundle bundle)
{
RoutingStrategyType result = Objects.requireNonNull((RoutingStrategyType)bundle.getSerializable(BUNDLE_ROUTING_STRATEGY_TYPE));
return result;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState)
{
@ -63,12 +77,15 @@ public class DrivingOptionsFragment extends BaseMwmToolbarFragment
savedRoadTypes.add(each.ordinal());
}
outState.putIntegerArrayList(BUNDLE_ROAD_TYPES, savedRoadTypes);
outState.putSerializable(BUNDLE_ROUTING_STRATEGY_TYPE, mStrategy);
}
private boolean areSettingsNotChanged()
{
Set<RoadType> lastActiveRoadTypes = RoutingOptions.getActiveRoadTypes();
return mRoadTypes.equals(lastActiveRoadTypes);
RoutingStrategyType lastActiveStrategyType = RoutingOptions.getActiveRoutingStrategyType();
return mRoadTypes.equals(lastActiveRoadTypes) && mStrategy.equals(lastActiveStrategyType);
}
@Override
@ -104,6 +121,26 @@ public class DrivingOptionsFragment extends BaseMwmToolbarFragment
CompoundButton.OnCheckedChangeListener dirtyBtnListener =
new ToggleRoutingOptionListener(RoadType.Dirty);
dirtyRoadsBtn.setOnCheckedChangeListener(dirtyBtnListener);
RadioGroup strategyRadioGroup = root.findViewById(R.id.routing_strategy_types);
RoutingStrategyType currentStrategy = RoutingOptions.getActiveRoutingStrategyType();
int currentCheckedStrategyId;
switch (currentStrategy)
{
case Shortest:
currentCheckedStrategyId = R.id.use_strategy_shortest;
break;
case FewerTurns:
currentCheckedStrategyId = R.id.use_strategy_fewerTurns;
break;
default:
currentCheckedStrategyId = R.id.use_strategy_fastest;
break;
}
strategyRadioGroup.check(currentCheckedStrategyId);
RadioGroup.OnCheckedChangeListener strategyRadioGroupListener =
new ToggleRoutingStrategyListener();
strategyRadioGroup.setOnCheckedChangeListener(strategyRadioGroupListener);
}
private static class ToggleRoutingOptionListener implements CompoundButton.OnCheckedChangeListener
@ -125,4 +162,26 @@ public class DrivingOptionsFragment extends BaseMwmToolbarFragment
RoutingOptions.removeOption(mRoadType);
}
}
private static class ToggleRoutingStrategyListener implements RadioGroup.OnCheckedChangeListener
{
private ToggleRoutingStrategyListener() {}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId)
{
switch (checkedId)
{
case R.id.use_strategy_fastest:
RoutingOptions.setStrategy(RoutingStrategyType.Fastest);
break;
case R.id.use_strategy_shortest:
RoutingOptions.setStrategy(RoutingStrategyType.Shortest);
break;
case R.id.use_strategy_fewerTurns:
RoutingOptions.setStrategy(RoutingStrategyType.FewerTurns);
break;
}
}
}
}

View file

@ -0,0 +1,8 @@
package app.organicmaps.settings;
public enum RoutingStrategyType
{
Fastest,
Shortest,
FewerTurns
}

View file

@ -104,4 +104,46 @@
android:padding="@dimen/margin_half_double_plus"
android:layout_height="match_parent"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="@android:color/darker_gray"/>
<TextView
android:text="@string/driving_options_subheader2"
android:textAppearance="?android:attr/textAppearance"
android:textColor="?colorAccent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/margin_half_double_plus"
android:paddingEnd="@dimen/margin_base"
android:paddingStart="@dimen/margin_base"/>
<RadioGroup
android:id="@+id/routing_strategy_types"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base">
<RadioButton
android:id="@+id/use_strategy_fastest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/margin_half_plus"
android:checked="true"
android:text="@string/use_strategy_fastest"/>
<RadioButton
android:id="@+id/use_strategy_shortest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/margin_half_plus"
android:checked="false"
android:text="@string/use_strategy_shortest"/>
<RadioButton
android:id="@+id/use_strategy_fewerTurns"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/margin_half_plus"
android:checked="false"
android:text="@string/use_strategy_fewerTurns"/>
</RadioGroup>
</LinearLayout>

View file

@ -687,12 +687,16 @@
<string name="access_rules_author_only">Online editing</string>
<string name="driving_options_title">Routing options</string>
<!-- Recommended length for CarPlay and Android Auto is around 25-27 characters -->
<string name="driving_options_subheader2">Routing Strategy</string>
<string name="avoid_tolls">Avoid tolls</string>
<!-- Recommended length for CarPlay and Android Auto is around 25-27 characters -->
<string name="avoid_unpaved">Avoid unpaved roads</string>
<!-- Recommended length for CarPlay and Android Auto is around 25-27 characters -->
<string name="avoid_ferry">Avoid ferries</string>
<string name="avoid_motorways">Avoid freeways</string>
<string name="use_strategy_fastest">Fastest</string>
<string name="use_strategy_shortest">Shortest</string>
<string name="use_strategy_fewerTurns">Fewer turns</string>
<string name="unable_to_calc_alert_title">Unable to calculate route</string>
<string name="unable_to_calc_alert_subtitle">A route could not be found. This may be caused by your routing options or incomplete OpenStreetMap data. Please change your routing options and retry.</string>
<string name="define_to_avoid_btn">Define roads to avoid</string>

View file

@ -3,6 +3,7 @@
#include "map/framework.hpp"
#include "routing/router.hpp"
#include "routing/edge_estimator.hpp"
#include "platform/settings.hpp"
@ -24,12 +25,26 @@ std::string const kUseCachedRoutingSettings = "use_cached_settings_desktop";
std::string const kStartCoordsCachedSettings = "start_coords_desktop";
std::string const kFinishCoordsCachedSettings = "finish_coords_desktop";
std::string const kRouterTypeCachedSettings = "router_type_desktop";
std::string const kRouterStrategyCachedSettings = "router_strategy";
std::string const kAvoidRoutingOptionSettings = "avoid_routing_options_car";
int constexpr DefaultRouterIndex()
{
// Car router by default.
return static_cast<int>(routing::RouterType::Vehicle);
}
int constexpr DefaultStrategyIndex()
{
// Routing strategy by default
return static_cast<int>(routing::EdgeEstimator::Strategy::Fastest);
}
int constexpr DefaultAvoidOptionIndex()
{
// Avoid routing option by default
return static_cast<int>(routing::RoutingOptions::Road::Usual);
}
} // namespace
// static
@ -93,6 +108,8 @@ void RoutingSettings::LoadSession(Framework & framework)
settings::Delete(kStartCoordsCachedSettings);
settings::Delete(kFinishCoordsCachedSettings);
settings::Delete(kRouterTypeCachedSettings);
settings::Delete(kRouterStrategyCachedSettings);
settings::Delete(kAvoidRoutingOptionSettings);
}
}
@ -134,6 +151,20 @@ RoutingSettings::RoutingSettings(QWidget * parent, Framework & framework)
m_routerType->insertItem(static_cast<int>(RouterType::Ruler), "ruler");
form->addRow("Choose router:", m_routerType);
m_routerStrategy = new QComboBox(frame);
m_routerStrategy->insertItem(static_cast<int>(EdgeEstimator::Strategy::Fastest), "fastest");
m_routerStrategy->insertItem(static_cast<int>(EdgeEstimator::Strategy::Shortest), "shortest");
m_routerStrategy->insertItem(static_cast<int>(EdgeEstimator::Strategy::FewerTurns), "fewer turns");
form->addRow("Choose strategy:", m_routerStrategy);
m_avoidRoutingOptions = new QComboBox(frame);
m_avoidRoutingOptions->insertItem(static_cast<int>(RoutingOptions::Road::Dirty), "dirty");
m_avoidRoutingOptions->insertItem(static_cast<int>(RoutingOptions::Road::Ferry), "ferry");
m_avoidRoutingOptions->insertItem(static_cast<int>(RoutingOptions::Road::Motorway), "motorway");
m_avoidRoutingOptions->insertItem(static_cast<int>(RoutingOptions::Road::Toll), "toll");
m_avoidRoutingOptions->insertItem(static_cast<int>(RoutingOptions::Road::Usual), "usual");
form->addRow("Choose avoid option:", m_avoidRoutingOptions);
m_showTurnsCheckbox = new QCheckBox({}, frame);
form->addRow("Show turns:", m_showTurnsCheckbox);
@ -190,6 +221,8 @@ bool RoutingSettings::SaveSettings()
settings::Set(kUseDebugGuideSettings, m_useDebugGuideCheckbox->isChecked());
settings::Set(kUseCachedRoutingSettings, m_saveSessionCheckbox->isChecked());
settings::Set(kRouterTypeCachedSettings, m_routerType->currentIndex());
settings::Set(kRouterStrategyCachedSettings, m_routerStrategy->currentIndex());
settings::Set(kAvoidRoutingOptionSettings, m_avoidRoutingOptions->currentIndex());
return ValidateAndSaveCoordsFromInput();
}
@ -207,6 +240,14 @@ void RoutingSettings::LoadSettings()
settings::TryGet(kRouterTypeCachedSettings, routerType);
m_routerType->setCurrentIndex(routerType);
int routerStrategy = DefaultStrategyIndex();
settings::TryGet(kRouterStrategyCachedSettings, routerStrategy);
m_routerStrategy->setCurrentIndex(routerStrategy);
int avoidRoutingOption = DefaultAvoidOptionIndex();
settings::TryGet(kAvoidRoutingOptionSettings, avoidRoutingOption);
m_avoidRoutingOptions->setCurrentIndex(avoidRoutingOption);
bool showTurns = false;
settings::TryGet(kShowTurnsSettings, showTurns);
m_showTurnsCheckbox->setChecked(showTurns);

View file

@ -40,6 +40,8 @@ private:
QLineEdit * m_finishInput;
QComboBox * m_routerType;
QComboBox * m_routerStrategy;
QComboBox * m_avoidRoutingOptions;
QCheckBox * m_showTurnsCheckbox;
QCheckBox * m_useDebugGuideCheckbox;
QCheckBox * m_saveSessionCheckbox;

View file

@ -1,4 +1,5 @@
#include "routing/async_router.hpp"
#include "routing/routing_options.hpp"
#include "geometry/mercator.hpp"
@ -343,6 +344,12 @@ void AsyncRouter::CalculateRoute()
if (absentRegionsFinder)
absentRegionsFinder->GenerateAbsentRegions(checkpoints, delegateProxy->GetDelegate());
RoutingOptions const routingOptions = RoutingOptions::LoadCarOptionsFromSettings();
router->SetEstimatorOptions(routingOptions.GetOptions());
EdgeEstimator::Strategy routingStrategy = EdgeEstimator::LoadRoutingStrategyFromSettings();
router->SetEstimatorStrategy(routingStrategy);
// Run basic request.
code = router->CalculateRoute(checkpoints, startDirection, adjustToPrevRoute,
delegateProxy->GetDelegate(), *route);

View file

@ -1,8 +1,11 @@
#include "routing/edge_estimator.hpp"
#include "platform/settings.hpp"
#include "routing/geometry.hpp"
#include "routing/latlon_with_altitude.hpp"
#include "routing/routing_helpers.hpp"
#include "routing/routing_options.hpp"
#include "routing/traffic_stash.hpp"
#include "traffic/speed_groups.hpp"
@ -60,12 +63,15 @@ bool IsTransit(std::optional<HighwayType> type)
}
template <class CalcSpeed>
double CalcClimbSegment(EdgeEstimator::Purpose purpose, Segment const & segment,
RoadGeometry const & road, CalcSpeed && calcSpeed)
double CalcClimbSegment(EdgeEstimator::Purpose purpose, EdgeEstimator::Strategy strategy,
Segment const & segment, RoadGeometry const & road, CalcSpeed && calcSpeed)
{
double const distance = road.GetDistance(segment.GetSegmentIdx());
double speedMpS = GetSpeedMpS(purpose, segment, road);
if (strategy == EdgeEstimator::Strategy::Shortest && purpose == EdgeEstimator::Purpose::Weight)
speedMpS = 1.0;
static double constexpr kSmallDistanceM = 1; // we have altitude threshold is 0.5m
if (distance > kSmallDistanceM && !IsTransit(road.GetHighwayType()))
{
@ -167,6 +173,26 @@ double GetCarClimbPenalty(EdgeEstimator::Purpose, double, geometry::Altitude)
}
// EdgeEstimator -----------------------------------------------------------------------------------
string const EdgeEstimator::kRoutingStrategySettings = "router_strategy";
// static
EdgeEstimator::Strategy EdgeEstimator::LoadRoutingStrategyFromSettings()
{
int mode = 0;
if (!settings::Get(kRoutingStrategySettings, mode))
mode = 0;
return (EdgeEstimator::Strategy) mode;
}
// static
void EdgeEstimator::SaveRoutingStrategyToSettings(Strategy strategy)
{
settings::Set(kRoutingStrategySettings,
strings::to_string(static_cast<int>(strategy)));
}
EdgeEstimator::EdgeEstimator(double maxWeightSpeedKMpH, SpeedKMpH const & offroadSpeedKMpH,
DataSource * /*dataSourcePtr*/, std::shared_ptr<NumMwmIds> /*numMwmIds*/)
: m_maxWeightSpeedMpS(KmphToMps(maxWeightSpeedKMpH))
@ -180,6 +206,9 @@ EdgeEstimator::EdgeEstimator(double maxWeightSpeedKMpH, SpeedKMpH const & offroa
if (m_offroadSpeedKMpH.m_eta != kNotUsed)
CHECK_GREATER_OR_EQUAL(m_maxWeightSpeedMpS, KmphToMps(m_offroadSpeedKMpH.m_eta), ());
m_avoidRoutingOptions = RoutingOptions();
m_strategy = EdgeEstimator::Strategy::Fastest;
}
double EdgeEstimator::CalcHeuristic(ms::LatLon const & from, ms::LatLon const & to) const
@ -260,6 +289,26 @@ double EdgeEstimator::CalcOffroad(ms::LatLon const & from, ms::LatLon const & to
return TimeBetweenSec(from, to, KmphToMps(offroadSpeedKMpH));
}
RoutingOptions EdgeEstimator::GetAvoidRoutingOptions() const
{
return m_avoidRoutingOptions;
}
void EdgeEstimator::SetAvoidRoutingOptions(RoutingOptions::RoadType options)
{
m_avoidRoutingOptions.SetOptions(options);
}
EdgeEstimator::Strategy EdgeEstimator::GetStrategy() const
{
return m_strategy;
}
void EdgeEstimator::SetStrategy(EdgeEstimator::Strategy strategy)
{
m_strategy = strategy;
}
// PedestrianEstimator -----------------------------------------------------------------------------
class PedestrianEstimator final : public EdgeEstimator
{
@ -270,7 +319,20 @@ public:
}
// EdgeEstimator overrides:
double GetUTurnPenalty(Purpose /* purpose */) const override { return 0.0 /* seconds */; }
double GetUTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight && GetStrategy() == EdgeEstimator::Strategy::FewerTurns)
return 60 * 60;
return 0.0;
}
double GetTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight && GetStrategy() == EdgeEstimator::Strategy::FewerTurns)
return 60 * 60;
return 0.0;
}
double GetFerryLandingPenalty(Purpose purpose) const override
{
switch (purpose)
@ -283,11 +345,16 @@ public:
double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, Purpose purpose) const override
{
return CalcClimbSegment(purpose, segment, road,
double result = CalcClimbSegment(purpose, GetStrategy(), segment, road,
[purpose](double speedMpS, double tangent, geometry::Altitude altitude)
{
return speedMpS / GetPedestrianClimbPenalty(purpose, tangent, altitude);
});
if (purpose == EdgeEstimator::Purpose::Weight && !road.SuitableForOptions(EdgeEstimator::GetAvoidRoutingOptions()))
result += (24 * 60 * 60);
return result;
}
};
@ -301,7 +368,20 @@ public:
}
// EdgeEstimator overrides:
double GetUTurnPenalty(Purpose /* purpose */) const override { return 20.0 /* seconds */; }
double GetUTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight && GetStrategy() == EdgeEstimator::Strategy::FewerTurns)
return 60 * 60;
return 20.0;
}
double GetTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight && GetStrategy() == EdgeEstimator::Strategy::FewerTurns)
return 60 * 60;
return 0.0;
}
double GetFerryLandingPenalty(Purpose purpose) const override
{
switch (purpose)
@ -314,7 +394,7 @@ public:
double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, Purpose purpose) const override
{
return CalcClimbSegment(purpose, segment, road,
double result = CalcClimbSegment(purpose, GetStrategy(), segment, road,
[purpose, this](double speedMpS, double tangent, geometry::Altitude altitude)
{
auto const factor = GetBicycleClimbPenalty(purpose, tangent, altitude);
@ -347,6 +427,12 @@ public:
return std::min(speedMpS, GetMaxWeightSpeedMpS());
});
if (purpose == EdgeEstimator::Purpose::Weight && !road.SuitableForOptions(EdgeEstimator::GetAvoidRoutingOptions()))
result += (24 * 60 * 60);
return result;
}
};
@ -364,14 +450,24 @@ public:
// EdgeEstimator overrides:
double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, Purpose purpose) const override;
double GetUTurnPenalty(Purpose /* purpose */) const override
double GetUTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight && GetStrategy() == EdgeEstimator::Strategy::FewerTurns)
return 60 * 60;
// Adds 2 minutes penalty for U-turn. The value is quite arbitrary
// and needs to be properly selected after a number of real-world
// experiments.
return 2 * 60; // seconds
}
double GetTurnPenalty(Purpose purpose) const override
{
if (purpose == EdgeEstimator::Purpose::Weight)
return 60 * 60;
return 0;
}
double GetFerryLandingPenalty(Purpose purpose) const override
{
switch (purpose)
@ -390,6 +486,9 @@ double CarEstimator::CalcSegmentWeight(Segment const & segment, RoadGeometry con
{
double result = road.GetDistance(segment.GetSegmentIdx()) / GetSpeedMpS(purpose, segment, road);
if (purpose == EdgeEstimator::Purpose::Weight && !road.SuitableForOptions(EdgeEstimator::GetAvoidRoutingOptions()))
result += (24 * 60 * 60);
if (m_trafficStash)
{
SpeedGroup const speedGroup = m_trafficStash->GetSpeedGroup(segment);

View file

@ -1,5 +1,6 @@
#pragma once
#include "routing/routing_options.hpp"
#include "routing/segment.hpp"
#include "routing/vehicle_mask.hpp"
@ -27,10 +28,22 @@ public:
ETA
};
static std::string const kRoutingStrategySettings;
enum class Strategy
{
Fastest,
Shortest,
FewerTurns
};
EdgeEstimator(double maxWeightSpeedKMpH, SpeedKMpH const & offroadSpeedKMpH,
DataSource * dataSourcePtr = nullptr, std::shared_ptr<NumMwmIds> numMwmIds = nullptr);
virtual ~EdgeEstimator() = default;
static Strategy LoadRoutingStrategyFromSettings();
static void SaveRoutingStrategyToSettings(Strategy strategy);
double CalcHeuristic(ms::LatLon const & from, ms::LatLon const & to) const;
// Estimates time in seconds it takes to go from point |from| to point |to| along a leap (fake)
// edge |from|-|to| using real features.
@ -45,9 +58,16 @@ public:
// Estimates time in seconds it takes to go from point |from| to point |to| along direct fake edge.
double CalcOffroad(ms::LatLon const & from, ms::LatLon const & to, Purpose purpose) const;
RoutingOptions GetAvoidRoutingOptions() const;
void SetAvoidRoutingOptions(RoutingOptions::RoadType options);
Strategy GetStrategy() const;
void SetStrategy(Strategy strategy);
virtual double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road,
Purpose purpose) const = 0;
virtual double GetUTurnPenalty(Purpose purpose) const = 0;
virtual double GetTurnPenalty(Purpose purpose) const = 0;
virtual double GetFerryLandingPenalty(Purpose purpose) const = 0;
static std::shared_ptr<EdgeEstimator> Create(VehicleType vehicleType, double maxWeighSpeedKMpH,
@ -65,6 +85,8 @@ public:
private:
double const m_maxWeightSpeedMpS;
SpeedKMpH const m_offroadSpeedKMpH;
RoutingOptions m_avoidRoutingOptions;
Strategy m_strategy;
//DataSource * m_dataSourcePtr;
//std::shared_ptr<NumMwmIds> m_numMwmIds;

View file

@ -12,6 +12,7 @@
#include "base/timer.hpp"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iterator>
#include <limits>
@ -254,8 +255,8 @@ void IndexGraph::GetNeighboringEdges(astar::VertexData<Segment, RouteWeight> con
if (!road.IsValid())
return;
if (useRoutingOptions && !road.SuitableForOptions(m_avoidRoutingOptions))
return;
// if (useRoutingOptions && !road.SuitableForOptions(m_avoidRoutingOptions))
// return;
bool const bidirectional = !road.IsOneWay();
auto const & from = fromVertexData.m_vertex;
@ -282,8 +283,8 @@ void IndexGraph::GetSegmentCandidateForRoadPoint(RoadPoint const & rp, NumMwmId
if (!road.IsValid())
return;
if (!road.SuitableForOptions(m_avoidRoutingOptions))
return;
// if (!road.SuitableForOptions(m_avoidRoutingOptions))
// return;
bool const bidirectional = !road.IsOneWay();
auto const pointId = rp.GetPointId();
@ -514,6 +515,9 @@ RouteWeight IndexGraph::GetPenalties(EdgeEstimator::Purpose purpose, Segment con
if (IsUTurn(u, v))
weightPenalty += m_estimator->GetUTurnPenalty(purpose);
if (IsTurn(u, v))
weightPenalty += m_estimator->GetTurnPenalty(purpose);
if (IsBoarding(fromPenaltyData.m_isFerry, toPenaltyData.m_isFerry))
weightPenalty += m_estimator->GetFerryLandingPenalty(purpose);
@ -549,6 +553,57 @@ bool IndexGraph::IsUTurnAndRestricted(Segment const & parent, Segment const & ch
return uTurn.m_atTheEnd && turnPoint == n - 1;
}
bool IndexGraph::IsTurn(Segment const & u, Segment const & v) const
{
// Boundary check for segmentIdx
if (u.GetSegmentIdx() == 0 && !(u.IsForward()))
{
return false;
}
if (v.GetSegmentIdx() == 0 && !(v.IsForward()))
{
return false;
}
auto geoU = GetRoadGeometry(u.GetFeatureId());
auto startPointU = geoU.GetPoint(u.GetSegmentIdx());
auto endPointU = geoU.GetPoint(u.IsForward() ? u.GetSegmentIdx() + 1: u.GetSegmentIdx() - 1);
auto geoV = GetRoadGeometry(v.GetFeatureId());
auto startPointV = geoV.GetPoint(v.GetSegmentIdx());
auto endPointV = geoV.GetPoint(v.IsForward() ? v.GetSegmentIdx() + 1: v.GetSegmentIdx() - 1);
if (!(endPointU == startPointV))
{
return false;
}
double vectorU[2] = {endPointU.m_lat - startPointU.m_lat, endPointU.m_lon - startPointU.m_lon};
double vectorV[2] = {endPointV.m_lat - startPointV.m_lat, endPointV.m_lon - startPointV.m_lon};
//dot product
double dot = vectorU[0] * vectorV[0] + vectorU[1] * vectorV[1];
//determinant
double det = vectorU[0] * vectorV[1] - vectorU[1] * vectorV[0];
//calculate the anlge
double angle = atan2(det, dot);
//convert to degree value
angle = angle * 180 / 3.141592;
if (abs(angle) >= 15)
{
return true;
}
else
{
return false;
}
}
RouteWeight IndexGraph::CalculateEdgeWeight(EdgeEstimator::Purpose purpose, bool isOutgoing,
Segment const & from, Segment const & to,
std::optional<RouteWeight const> const & prevWeight) const
@ -556,7 +611,18 @@ RouteWeight IndexGraph::CalculateEdgeWeight(EdgeEstimator::Purpose purpose, bool
auto const & segment = isOutgoing ? to : from;
auto const & road = GetRoadGeometry(segment.GetFeatureId());
// m_estimator->SetAvoidRoutingOptions(this->m_avoidRoutingOptions.GetOptions());
auto const weight = RouteWeight(m_estimator->CalcSegmentWeight(segment, road, purpose));
if (purpose == EdgeEstimator::Purpose::Weight)
{
if(m_estimator->GetStrategy() == EdgeEstimator::Strategy::Shortest)
{
return weight;
}
}
auto const penalties = GetPenalties(purpose, isOutgoing ? from : to, isOutgoing ? to : from, prevWeight);
return weight + penalties;

View file

@ -133,6 +133,8 @@ public:
bool IsUTurnAndRestricted(Segment const & parent, Segment const & child, bool isOutgoing) const;
bool IsTurn(Segment const & u, Segment const & v) const;
/// @param[in] isOutgoing true, when movig from -> to, false otherwise.
/// @param[in] prevWeight used for fetching access:conditional.
/// I suppose :) its time when user will be at the end of |from| (|to| if \a isOutgoing == false) segment.

View file

@ -326,6 +326,10 @@ bool IndexRouter::FindClosestProjectionToRoad(m2::PointD const & point,
return true;
}
void IndexRouter::SetEstimatorOptions(RoutingOptions::RoadType options) {m_estimator ->SetAvoidRoutingOptions(options);}
void IndexRouter::SetEstimatorStrategy(EdgeEstimator::Strategy strategy) {m_estimator ->SetStrategy(strategy);}
void IndexRouter::SetGuides(GuidesTracks && guides) { m_guides = GuidesConnections(guides); }
RouterResultCode IndexRouter::CalculateRoute(Checkpoints const & checkpoints,

View file

@ -14,6 +14,7 @@
#include "routing/regions_decl.hpp"
#include "routing/router.hpp"
#include "routing/routing_callbacks.hpp"
#include "routing/routing_options.hpp"
#include "routing/segment.hpp"
#include "routing/segmented_route.hpp"
@ -77,6 +78,10 @@ public:
std::string GetName() const override { return m_name; }
void ClearState() override;
void SetEstimatorOptions(RoutingOptions::RoadType options) override;
void SetEstimatorStrategy(EdgeEstimator::Strategy strategy) override;
void SetGuides(GuidesTracks && guides) override;
RouterResultCode CalculateRoute(Checkpoints const & checkpoints,
m2::PointD const & startDirection, bool adjustToPrevRoute,

View file

@ -1,9 +1,11 @@
#pragma once
#include "routing/checkpoints.hpp"
#include "routing/edge_estimator.hpp"
#include "routing/road_graph.hpp"
#include "routing/router_delegate.hpp"
#include "routing/routing_callbacks.hpp"
#include "routing/routing_options.hpp"
#include "kml/type_utils.hpp"
@ -62,6 +64,10 @@ public:
/// Clear all temporary buffers.
virtual void ClearState() {}
virtual void SetEstimatorOptions(RoutingOptions::RoadType options) {}
virtual void SetEstimatorStrategy(EdgeEstimator::Strategy strategy) {}
virtual void SetGuides(GuidesTracks && guides) = 0;
/// Override this function with routing implementation.

View file

@ -50,6 +50,11 @@ bool RoutingOptions::Has(RoutingOptions::Road type) const
return (m_options & static_cast<RoadType>(type)) != 0;
}
void RoutingOptions::SetOptions(RoadType options)
{
m_options = options;
}
// RoutingOptionsClassifier ---------------------------------------------------------------------------
RoutingOptionsClassifier::RoutingOptionsClassifier()

View file

@ -37,6 +37,7 @@ public:
bool Has(Road type) const;
RoadType GetOptions() const { return m_options; }
void SetOptions(RoadType options);
private:
RoadType m_options = 0;

View file

@ -146,6 +146,7 @@ double WeightedEdgeEstimator::CalcSegmentWeight(Segment const & segment,
}
double WeightedEdgeEstimator::GetUTurnPenalty(Purpose purpose) const { return 0.0; }
double WeightedEdgeEstimator::GetTurnPenalty(Purpose purpose) const { return 0.0; }
double WeightedEdgeEstimator::GetFerryLandingPenalty(Purpose purpose) const { return 0.0; }
// TestIndexGraphTopology --------------------------------------------------------------------------

View file

@ -181,6 +181,7 @@ public:
EdgeEstimator::Purpose purpose) const override;
double GetUTurnPenalty(Purpose purpose) const override;
double GetTurnPenalty(Purpose purpose) const override;
double GetFerryLandingPenalty(Purpose purpose) const override;
private: