From 4c63dd98851aa0f350ccfbf95ced96b2a0efe640 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Thu, 20 Jul 2017 18:15:14 +0300 Subject: [PATCH] Added route points transactions --- android/jni/com/mapswithme/maps/Framework.cpp | 26 ++++++++ .../src/com/mapswithme/maps/Framework.java | 5 ++ .../maps/routing/RoutingController.java | 54 ++++++++++++++-- iphone/Maps/Core/Routing/MWMRouter.h | 1 + iphone/Maps/Core/Routing/MWMRouter.mm | 44 +++++++++++-- map/routing_manager.cpp | 63 +++++++++++++++++++ map/routing_manager.hpp | 13 ++++ 7 files changed, 197 insertions(+), 9 deletions(-) diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 46f238c979..bdc34ce5da 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1406,4 +1406,30 @@ Java_com_mapswithme_maps_Framework_nativeRunFirstLaunchAnimation(JNIEnv * env, j { frm()->RunFirstLaunchAnimation(); } + +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_Framework_nativeOpenRoutePointsTransaction(JNIEnv * env, jclass) +{ + return frm()->GetRoutingManager().OpenRoutePointsTransaction(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_Framework_nativeApplyRoutePointsTransaction(JNIEnv * env, jclass, + jint transactionId) +{ + frm()->GetRoutingManager().ApplyRoutePointsTransaction(transactionId); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_Framework_nativeCancelRoutePointsTransaction(JNIEnv * env, jclass, + jint transactionId) +{ + frm()->GetRoutingManager().CancelRoutePointsTransaction(transactionId); +} + +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_Framework_nativeInvalidRoutePointsTransactionId(JNIEnv * env, jclass) +{ + return frm()->GetRoutingManager().InvalidRoutePointsTransactionId(); +} } // extern "C" diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java index 0c20cd4396..e3105df1f1 100644 --- a/android/src/com/mapswithme/maps/Framework.java +++ b/android/src/com/mapswithme/maps/Framework.java @@ -343,4 +343,9 @@ public class Framework double lat, double lon, int accuracy); public static native void nativeRunFirstLaunchAnimation(); + + public static native int nativeOpenRoutePointsTransaction(); + public static native void nativeApplyRoutePointsTransaction(int transactionId); + public static native void nativeCancelRoutePointsTransaction(int transactionId); + public static native int nativeInvalidRoutePointsTransactionId(); } diff --git a/android/src/com/mapswithme/maps/routing/RoutingController.java b/android/src/com/mapswithme/maps/routing/RoutingController.java index 40dee3a4f0..891317b491 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingController.java +++ b/android/src/com/mapswithme/maps/routing/RoutingController.java @@ -95,7 +95,7 @@ public class RoutingController implements TaxiManager.TaxiListener private int mWaitingPoiPickType = NO_WAITING_POI_PICK; private int mLastBuildProgress; @Framework.RouterType - private int mLastRouterType = Framework.nativeGetLastUsedRouter(); + private int mLastRouterType; private boolean mHasContainerSavedState; private boolean mContainsCachedResult; @@ -107,6 +107,9 @@ public class RoutingController implements TaxiManager.TaxiListener private boolean mTaxiPlanning; private boolean mInternetConnected; + private int mInvalidRoutePointsTransactionId; + private int mRemovingIntermediatePointsTransactionId; + @SuppressWarnings("FieldCanBeLocal") private final Framework.RoutingListener mRoutingListener = new Framework.RoutingListener() { @@ -246,6 +249,10 @@ public class RoutingController implements TaxiManager.TaxiListener public void initialize() { + mLastRouterType = Framework.nativeGetLastUsedRouter(); + mInvalidRoutePointsTransactionId = Framework.nativeInvalidRoutePointsTransactionId(); + mRemovingIntermediatePointsTransactionId = mInvalidRoutePointsTransactionId; + Framework.nativeSetRoutingListener(mRoutingListener); Framework.nativeSetRouteProgressListener(mRoutingProgressListener); TaxiManager.INSTANCE.setTaxiListener(this); @@ -288,10 +295,6 @@ public class RoutingController implements TaxiManager.TaxiListener mLastBuildProgress = 0; mInternetConnected = ConnectionState.isConnected(); - // Now only car routing supports intermediate points. - if (!isVehicleRouterType()) - removeIntermediatePoints(); - if (isTaxiRouterType()) { if (!mInternetConnected) @@ -491,6 +494,7 @@ public class RoutingController implements TaxiManager.TaxiListener if (info == null) throw new AssertionError("A stop point must have the route point info!"); + applyRemovingIntermediatePointsTransaction(); Framework.nativeRemoveRoutePoint(info.mMarkType, info.mIntermediateIndex); build(); if (mContainer != null) @@ -596,6 +600,7 @@ public class RoutingController implements TaxiManager.TaxiListener setBuildState(BuildState.NONE); setState(State.NONE); + applyRemovingIntermediatePointsTransaction(); Framework.nativeCloseRouting(); } @@ -754,6 +759,7 @@ public class RoutingController implements TaxiManager.TaxiListener { if (startPoint != null) { + applyRemovingIntermediatePointsTransaction(); // TODO(@alexzatsepin): set correct title and subtitle. Framework.nativeAddRoutePoint(""/* title */, ""/* subtitle */, RoutePointInfo.ROUTE_MARK_START, 0/* intermediateIndex */, @@ -765,6 +771,7 @@ public class RoutingController implements TaxiManager.TaxiListener if (endPoint != null) { + applyRemovingIntermediatePointsTransaction(); // TODO(@alexzatsepin): set correct title and subtitle. Framework.nativeAddRoutePoint(""/* title */, ""/* subtitle */, RoutePointInfo.ROUTE_MARK_FINISH, 0/* intermediateIndex */, @@ -817,6 +824,7 @@ public class RoutingController implements TaxiManager.TaxiListener boolean isSamePoint = MapObject.same(startPoint, point); if (point != null) { + applyRemovingIntermediatePointsTransaction(); // TODO(@alexzatsepin): set correct title and subtitle. Framework.nativeAddRoutePoint(""/* title */, ""/* subtitle */, RoutePointInfo.ROUTE_MARK_START, 0/* intermediateIndex */, @@ -871,6 +879,7 @@ public class RoutingController implements TaxiManager.TaxiListener boolean isSamePoint = MapObject.same(endPoint, point); if (point != null) { + applyRemovingIntermediatePointsTransaction(); // TODO(@alexzatsepin): set correct title and subtitle. Framework.nativeAddRoutePoint(""/* title */, ""/* subtitle */, RoutePointInfo.ROUTE_MARK_FINISH, 0/* intermediateIndex */, @@ -946,10 +955,45 @@ public class RoutingController implements TaxiManager.TaxiListener mLastRouterType = router; Framework.nativeSetRouter(router); + // Taxi routing does not support intermediate points. + if (isTaxiRouterType()) + { + openRemovingIntermediatePointsTransaction(); + removeIntermediatePoints(); + } + else + { + cancelRemovingIntermediatePointsTransaction(); + } + if (getStartPoint() != null && getEndPoint() != null) build(); } + private void openRemovingIntermediatePointsTransaction() + { + if (mRemovingIntermediatePointsTransactionId == mInvalidRoutePointsTransactionId) + mRemovingIntermediatePointsTransactionId = Framework.nativeOpenRoutePointsTransaction(); + } + + private void cancelRemovingIntermediatePointsTransaction() + { + if (mRemovingIntermediatePointsTransactionId == mInvalidRoutePointsTransactionId) + return; + Framework.nativeCancelRoutePointsTransaction(mRemovingIntermediatePointsTransactionId); + mRemovingIntermediatePointsTransactionId = mInvalidRoutePointsTransactionId; + } + + private void applyRemovingIntermediatePointsTransaction() + { + // We have to apply removing intermediate points transaction each time + // we add/remove route points in the taxi mode. + if (mRemovingIntermediatePointsTransactionId == mInvalidRoutePointsTransactionId) + return; + Framework.nativeApplyRoutePointsTransaction(mRemovingIntermediatePointsTransactionId); + mRemovingIntermediatePointsTransactionId = mInvalidRoutePointsTransactionId; + } + public void onPoiSelected(@Nullable MapObject point) { if (!isWaitingPoiPick()) diff --git a/iphone/Maps/Core/Routing/MWMRouter.h b/iphone/Maps/Core/Routing/MWMRouter.h index 297e391347..27a2ad759e 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.h +++ b/iphone/Maps/Core/Routing/MWMRouter.h @@ -23,6 +23,7 @@ typedef void (^MWMImageHeightBlock)(UIImage *, NSString *); + (void)setType:(MWMRouterType)type; + (MWMRouterType)type; +- (uint32_t)taxiRoutePointTransactionId; + (void)disableFollowMode; diff --git a/iphone/Maps/Core/Routing/MWMRouter.mm b/iphone/Maps/Core/Routing/MWMRouter.mm index 7606259911..f6ead432a4 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.mm +++ b/iphone/Maps/Core/Routing/MWMRouter.mm @@ -41,6 +41,7 @@ char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeI @property(nonatomic) NSMutableDictionary * altitudeImagesData; @property(nonatomic) NSString * altitudeElevation; @property(nonatomic) dispatch_queue_t renderAltitudeImagesQueue; +@property(nonatomic) uint32_t taxiRoutePointTransactionId; @end @@ -167,6 +168,7 @@ char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeI self.altitudeImagesData = [@{} mutableCopy]; self.renderAltitudeImagesQueue = dispatch_queue_create(kRenderAltitudeImagesQueueLabel, DISPATCH_QUEUE_SERIAL); + self.taxiRoutePointTransactionId = RoutingManager::InvalidRoutePointsTransactionId(); [MWMLocationManager addObserver:self]; [MWMFrameworkListener addObserver:self]; } @@ -177,11 +179,42 @@ char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeI { if (type == self.type) return; - // Now only car routing supports intermediate points. - if (type != MWMRouterTypeVehicle) - GetFramework().GetRoutingManager().RemoveIntermediateRoutePoints(); + + // Try to cancel transaction if we switched router type back. + [self cancelTaxiTransaction]; + + // Taxi routing does not support intermediate points. + auto & rm = GetFramework().GetRoutingManager(); + if (type == MWMRouterTypeTaxi) + { + auto router = [MWMRouter router]; + router.taxiRoutePointTransactionId = rm.OpenRoutePointsTransaction(); + rm.RemoveIntermediateRoutePoints(); + } + [self doStop:NO]; - GetFramework().GetRoutingManager().SetRouter(coreRouterType(type)); + rm.SetRouter(coreRouterType(type)); +} + ++ (void)cancelTaxiTransaction +{ + auto router = [MWMRouter router]; + if (router.taxiRoutePointTransactionId != RoutingManager::InvalidRoutePointsTransactionId()) + { + GetFramework().GetRoutingManager().CancelRoutePointsTransaction(router.taxiRoutePointTransactionId); + router.taxiRoutePointTransactionId = RoutingManager::InvalidRoutePointsTransactionId(); + } +} + ++ (void)applyTaxiTransaction +{ + // We have to apply taxi transaction each time we add/remove points after switch to taxi mode. + auto router = [MWMRouter router]; + if (router.taxiRoutePointTransactionId != RoutingManager::InvalidRoutePointsTransactionId()) + { + GetFramework().GetRoutingManager().ApplyRoutePointsTransaction(router.taxiRoutePointTransactionId); + router.taxiRoutePointTransactionId = RoutingManager::InvalidRoutePointsTransactionId(); + } } + (MWMRouterType)type { return routerType(GetFramework().GetRoutingManager().GetRouter()); } @@ -213,12 +246,14 @@ char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeI + (void)removePoint:(RouteMarkType)type intermediateIndex:(int8_t)intermediateIndex { + [self applyTaxiTransaction]; GetFramework().GetRoutingManager().RemoveRoutePoint(type, intermediateIndex); [[MWMMapViewControlsManager manager] onRoutePointsUpdated]; } + (void)addPoint:(MWMRoutePoint *)point intermediateIndex:(int8_t)intermediateIndex { + [self applyTaxiTransaction]; RouteMarkData pt = point.routeMarkData; pt.m_intermediateIndex = intermediateIndex; GetFramework().GetRoutingManager().AddRoutePoint(std::move(pt)); @@ -232,6 +267,7 @@ char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeI NSAssert(NO, @"Point can not be nil"); return; } + [self applyTaxiTransaction]; RouteMarkData pt = point.routeMarkData; GetFramework().GetRoutingManager().AddRoutePoint(std::move(pt)); [[MWMMapViewControlsManager manager] onRoutePointsUpdated]; diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 5098ea7bab..95fcc68621 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -41,6 +41,8 @@ char const kRouterTypeKey[] = "router"; double const kRouteScaleMultiplier = 1.5; +uint32_t constexpr kInvalidTransactionId = 0; + void FillTurnsDistancesForRendering(std::vector const & segments, std::vector & turns) { @@ -750,3 +752,64 @@ void RoutingManager::SetRouter(RouterType type) SetLastUsedRouter(type); SetRouterImpl(type); } + +// static +uint32_t RoutingManager::InvalidRoutePointsTransactionId() +{ + return kInvalidTransactionId; +} + +uint32_t RoutingManager::GenerateRoutePointsTransactionId() const +{ + static uint32_t id = kInvalidTransactionId + 1; + return id++; +} + +uint32_t RoutingManager::OpenRoutePointsTransaction() +{ + auto const id = GenerateRoutePointsTransactionId(); + m_routePointsTransactions[id].m_routeMarks = std::move(GetRoutePoints()); + return id; +} + +void RoutingManager::ApplyRoutePointsTransaction(uint32_t transactionId) +{ + if (m_routePointsTransactions.find(transactionId) == m_routePointsTransactions.end()) + return; + + // If we apply a transaction we can remove all earlier transactions. + // All older transactions must be kept since they can be applied or cancelled later. + for (auto it = m_routePointsTransactions.begin(); it != m_routePointsTransactions.end();) + { + if (it->first <= transactionId) + it = m_routePointsTransactions.erase(it); + else + ++it; + } +} + +void RoutingManager::CancelRoutePointsTransaction(uint32_t transactionId) +{ + auto const it = m_routePointsTransactions.find(transactionId); + if (it == m_routePointsTransactions.end()) + return; + auto routeMarks = it->second.m_routeMarks; + + // If we cancel a transaction we must remove all later transactions. + for (auto it = m_routePointsTransactions.begin(); it != m_routePointsTransactions.end();) + { + if (it->first >= transactionId) + it = m_routePointsTransactions.erase(it); + else + ++it; + } + + // Revert route points. + ASSERT(m_bmManager != nullptr, ()); + auto & controller = m_bmManager->GetUserMarksController(UserMarkType::ROUTING_MARK); + controller.Clear(); + RoutePointsLayout routePoints(controller); + for (auto & markData : routeMarks) + routePoints.AddRoutePoint(std::move(markData)); + routePoints.NotifyChanges(); +} diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 7bef0a7146..0842a4e6ee 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -15,6 +15,7 @@ #include "base/thread_checker.hpp" #include +#include #include #include #include @@ -215,12 +216,18 @@ public: int32_t & minRouteAltitude, int32_t & maxRouteAltitude, measurement_utils::Units & altitudeUnits) const; + uint32_t OpenRoutePointsTransaction(); + void ApplyRoutePointsTransaction(uint32_t transactionId); + void CancelRoutePointsTransaction(uint32_t transactionId); + static uint32_t InvalidRoutePointsTransactionId(); + private: void InsertRoute(routing::Route const & route); bool IsTrackingReporterEnabled() const; void MatchLocationToRoute(location::GpsInfo & info, location::RouteMatchingInfo & routeMatchingInfo) const; location::RouteMatchingInfo GetRouteMatchingInfo(location::GpsInfo & info); + uint32_t GenerateRoutePointsTransactionId() const; RouteBuildingCallback m_routingCallback = nullptr; Callbacks m_callbacks; @@ -236,5 +243,11 @@ private: std::unique_ptr m_gpsInfoCache; + struct RoutePointsTransaction + { + std::vector m_routeMarks; + }; + std::map m_routePointsTransactions; + DECLARE_THREAD_CHECKER(m_threadChecker); };