التوصيل في المرحلة الأخيرة هو أغلى جزء في أي سلسلة توريد. تضع المعايير الصناعية باستمرار تكاليف المرحلة الأخيرة عند 53% من إجمالي تكلفة الشحن. ضمن ذلك، المتغير الأكبر القابل للتحكم هو كفاءة المسار. سائق يُكمل 15 محطة بترتيب خاطئ قد يقطع 40% مسافة أكثر مما هو ضروري، محرقاً الوقود ومستهلكاً المركبة وفاتاً نوافذ وقت التسليم التي تُثير رسوم إعادة التوصيل.
تحسين المسارات لم يعد مشكلة صعبة في البرمجة. ما كان يتطلب سابقاً برامج لوجستية متخصصة مكلفة أصبح الآن مجرد استدعاء API. يبني هذا الدرس مُحسِّن مسار كامل متعدد المحطات باستخدام MapAtlas Routing API: سكريبت Python يُرسل قائمة محطات توصيل ويحصل على تسلسل مُحسَّن مع إجمالي المسافة والوقت، يُطبّق قيود نوافذ الوقت، ويتعامل مع قيود مناطق الانبعاثات المنخفضة في الاتحاد الأوروبي للتوصيل الحضري. ثم يرسم مقتطف JavaScript النتيجة على خريطة.
التطبيق بـ Python في أقل من 55 سطراً. عرض الخريطة بـ JavaScript إضافة 30 سطراً أخرى.
مشكلة تكلفة المرحلة الأخيرة
لفهم ما يوفّره التحسين فعلاً، احسب الأرقام لسيناريو توصيل واقعي:
- الأسطول: 10 شاحنات
- المحطات لكل شاحنة يومياً: 18
- المتوسط الحالي للمسافة: 210 كم/شاحنة/يوم
- تكلفة الوقود: 0.38 يورو/كم (ديزل، متوسط الاتحاد الأوروبي)
- تكلفة السائق: 22 يورو/ساعة
- متوسط وقت المسار الحالي: 7.5 ساعة/يوم
التكلفة اليومية الحالية لكل شاحنة: (210 × 0.38 يورو) + (7.5 × 22 يورو) = 79.80 يورو + 165 يورو = 244.80 يورو/شاحنة/يوم
تخفيض 30% في المسافة (قابل للتحقيق مع تحسين جيد على شبكة حضرية كثيفة) وتوفير 20% في الوقت يُنتج:
- المسافة المُحسَّنة: 147 كم، تكلفة الوقود: 55.86 يورو
- الوقت المُحسَّن: 6 ساعات، تكلفة السائق: 132 يورو
- التكلفة اليومية المُحسَّنة لكل شاحنة: 187.86 يورو/شاحنة/يوم
الوفر لكل شاحنة يومياً: 56.94 يورو. لـ 10 شاحنات على 250 يوم عمل: 142,350 يورو/سنة، من تكامل API واحد.
تعكس المعايير أعلاه أرقاماً حقيقية منشورة من دراسات لوجستيات المرحلة الأخيرة. أرقامك المحددة ستتفاوت حسب الجغرافيا ونوع المركبة وكثافة المحطات. المناطق الحضرية الكثيفة تحقق أكبر مكاسب لأن المسارات التسلسلية العشوائية تُهدر أكثر المسافة في التراجع غير الضروري.
مقارنة بصرية: المسار العشوائي مقابل المُحسَّن
الفرق بين المسار العشوائي (التسلسلي) والمُحسَّن واضح على الخريطة.
يحدث التوجيه العشوائي عندما تُغذّي المحطات بالترتيب الذي أُدخلت فيه، أول عميل طلب هو الأول في المسار، بغض النظر عن الجغرافيا. في مدينة كأمستردام أو برلين، يخلق هذا مشكلة "مسار السباغيتي": سائقك يتقاطع باستمرار مع مساره.
التحسين يحل مشكلة البائع المتجول (TSP) لمجموعة محطاتك. لـ 15-20 محطة هذا قابل للحساب في ميلي ثانية. للأساطيل الأكبر ذات مئات المحطات، تتعامل محلّلات مشكلة توجيه المركبات (VRP) مع القيود الإضافية للمركبات المتعددة وحدود الحمولة.
الخطوة 1: هيكلة بيانات التوصيل
تحتاج كل محطة إلى موقع، وللتوصيلات ذات النوافذ الزمنية، time_window يحدد متى يكون التوصيل مقبولاً.
import requests
import json
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.mapatlas.eu/v1"
# Depot (start and end point)
depot = {
"lat": 52.3402,
"lng": 4.8952,
"name": "Warehouse - Sloterdijk"
}
# Delivery stops with optional time windows
stops = [
{ "lat": 52.3726, "lng": 4.8971, "name": "Albert Heijn Jordaan",
"time_window": { "start": "09:00", "end": "12:00" } },
{ "lat": 52.3601, "lng": 4.9123, "name": "Café De Jaren",
"time_window": { "start": "08:00", "end": "11:00" } },
{ "lat": 52.3780, "lng": 4.8801, "name": "Westergasfabriek Events",
"time_window": { "start": "10:00", "end": "14:00" } },
{ "lat": 52.3545, "lng": 4.9041, "name": "Hotel V Nesplein",
"time_window": None },
{ "lat": 52.3620, "lng": 4.8820, "name": "Vondelpark Paviljoen",
"time_window": { "start": "07:00", "end": "10:00" } }
]
الخطوة 2: استدعاء نقطة نهاية تحسين المسار
أرسل POST للمستودع وقائمة المحطات إلى نقطة نهاية التوجيه المُحسَّن. يُعيد API المحطات بأكفأ ترتيب للزيارة مع إجمالي مسافة المسار ومدته.
def optimise_route(depot, stops, vehicle_profile="van-euro6"):
"""
Request an optimised multi-stop route from the MapAtlas Routing API.
vehicle_profile options: van-euro6, van-diesel-euro5, electric-van, bike
"""
waypoints = [
{
"lat": s["lat"],
"lng": s["lng"],
"name": s["name"],
**({"time_window": s["time_window"]} if s.get("time_window") else {})
}
for s in stops
]
payload = {
"origin": { "lat": depot["lat"], "lng": depot["lng"] },
"destination": { "lat": depot["lat"], "lng": depot["lng"] }, # return to depot
"waypoints": waypoints,
"optimise": True,
"vehicle_profile": vehicle_profile,
"avoid_low_emission_zones": True # auto-avoids LEZs for non-compliant profiles
}
response = requests.post(
f"{BASE_URL}/routing/optimise",
json=payload,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
)
response.raise_for_status()
return response.json()
result = optimise_route(depot, stops)
الخطوة 3: تحليل وعرض المسار المُحسَّن
يتضمن رد API المحطات بالترتيب المُحسَّن وأوقات الوصول التراكمية لكل محطة وإجمالي المسافة والمدة.
def display_route_summary(result):
route = result["route"]
print(f"\n--- Optimised Route Summary ---")
print(f"Total distance : {route['total_distance_km']:.1f} km")
print(f"Total duration : {route['total_duration_min']:.0f} min")
print(f"Stops : {len(route['waypoints'])}\n")
print(f" START {depot['name']}")
for i, stop in enumerate(route["waypoints"], 1):
eta = stop["eta"]
tw = stop.get("time_window")
on_time = "(on time)" if tw and tw["start"] <= eta <= tw["end"] else ""
print(f" {i:>2}. {stop['name']:<35} ETA {eta} {on_time}")
print(f" END {depot['name']}")
print(f"\nEstimated fuel saving vs sequential: "
f"{result.get('saving_vs_naive_km', 0):.1f} km "
f"({result.get('saving_pct', 0):.0f}%)")
display_route_summary(result)
مثال على المخرجات للمحطات الخمس أعلاه:
--- Optimised Route Summary ---
Total distance : 38.4 km
Total duration : 94 min
Stops : 5
START Warehouse - Sloterdijk
1. Vondelpark Paviljoen ETA 07:48 (on time)
2. Café De Jaren ETA 08:31 (on time)
3. Albert Heijn Jordaan ETA 09:15 (on time)
4. Hotel V Nesplein ETA 10:02
5. Westergasfabriek Events ETA 10:44 (on time)
END Warehouse - Sloterdijk
Estimated fuel saving vs sequential: 14.2 km (27%)
الخطوة 4: التعامل مع مناطق الانبعاثات المنخفضة في الاتحاد الأوروبي
تقيّد منطقة ZTL في أمستردام ونظام Crit'Air في باريس وUmweltzone في برلين أنواعاً معينة من المركبات في المناطق المركزية في أوقات محددة. قد يبدو المسار الكفء من حيث المسافة غير صالح لمركبتك.
يُوجّه معلمة avoid_low_emission_zones: true مع vehicle_profile تلقائياً حول المناطق المقيّدة للمركبات غير المتوافقة. للمركبات الكهربائية وEuro 6، يمكن عبور مناطق الانبعاثات المنخفضة والمعلمة ليس لها أثر.
# Example: diesel Euro 5 van, will be re-routed around Amsterdam ZTL
result_euro5 = optimise_route(depot, stops, vehicle_profile="van-diesel-euro5")
# Example: electric van, LEZ restrictions do not apply
result_electric = optimise_route(depot, stops, vehicle_profile="electric-van")
print(f"Euro 5 route distance : {result_euro5['route']['total_distance_km']:.1f} km")
print(f"Electric route distance: {result_electric['route']['total_distance_km']:.1f} km")
# Electric route will typically be shorter as it can use LEZ-restricted roads
لعمليات اللوجستيات التي تخطط للانتقال من الديزل إلى الكهرباء، توفر مقارنة هذين الناتجين لكل مسار تحديداً مباشراً لتحسين المدى المتاح من التحوّل الكهربائي.
الخطوة 5: عرض المسار المُحسَّن على خريطة
خذ هندسة المسار من رد API وارسمها كطبقة خط في JavaScript.
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
// routeResult is the parsed API JSON response passed to the frontend
function renderOptimisedRoute(map, routeResult) {
const { waypoints, geometry, total_distance_km, total_duration_min } = routeResult.route;
map.on('load', () => {
// Route line
map.addSource('optimised-route', { type: 'geojson', data: { type: 'Feature', geometry } });
map.addLayer({
id: 'route-line',
type: 'line',
source: 'optimised-route',
layout: { 'line-join': 'round', 'line-cap': 'round' },
paint: { 'line-color': '#2563EB', 'line-width': 4 }
});
// Stop markers with sequence numbers
waypoints.forEach((stop, i) => {
const el = document.createElement('div');
el.textContent = i + 1;
el.style.cssText = `
width:28px;height:28px;border-radius:50%;background:#2563EB;color:#fff;
display:flex;align-items:center;justify-content:center;font-weight:700;
font-size:13px;border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3)
`;
new mapmetricsgl.Marker({ element: el })
.setLngLat([stop.lng, stop.lat])
.setPopup(
new mapmetricsgl.Popup().setHTML(`
<strong>${i + 1}. ${stop.name}</strong>
<p>ETA: ${stop.eta}</p>
`)
)
.addTo(map);
});
// Fit map to route bounds
const coords = geometry.coordinates;
const bounds = coords.reduce(
(b, c) => b.extend(c),
new mapmetricsgl.LngLatBounds(coords[0], coords[0])
);
map.fitBounds(bounds, { padding: 48 });
// Summary panel
document.getElementById('route-summary').innerHTML = `
<strong>${total_distance_km.toFixed(1)} km</strong> ·
<strong>${total_duration_min.toFixed(0)} min</strong> ·
${waypoints.length} stops
`;
});
}
const map = new mapmetricsgl.Map({
container: 'route-map',
style: 'https://tiles.mapatlas.eu/styles/basic/style.json?key=YOUR_API_KEY',
center: [4.9041, 52.3676],
zoom: 12
});
renderOptimisedRoute(map, routeResult);
حساب وفوراتك الفعلية
بمجرد توفر رد API، حساب الوفر مباشر. يمنحك حقل saving_vs_naive_km في الرد المسافة الموفّرة مباشرة. من ذلك، اشتق وفورات التكلفة:
def calculate_savings(result, fuel_cost_per_km=0.38, driver_cost_per_hour=22.0,
days_per_year=250, fleet_size=10):
saving_km = result.get("saving_vs_naive_km", 0)
saving_hours = saving_km / 50 # assume 50 km/h average
daily_fuel_saving = saving_km * fuel_cost_per_km
daily_driver_saving = saving_hours * driver_cost_per_hour
daily_total = daily_fuel_saving + daily_driver_saving
annual_fleet_saving = daily_total * days_per_year * fleet_size
print(f"Distance saved per route : {saving_km:.1f} km")
print(f"Time saved per route : {saving_hours * 60:.0f} min")
print(f"Daily saving (1 vehicle) : €{daily_total:.2f}")
print(f"Annual saving ({fleet_size} vehicles): €{annual_fleet_saving:,.0f}")
calculate_savings(result)
تحسين نوافذ الوقت
التوصيل إلى مخبز في 06:00 ومطعم في 14:00 مع تقليل إجمالي مسافة المسار هي مشكلة تحسين مقيّدة. يتعامل API مع هذا تلقائياً، تحتاج فقط توفير النوافذ:
# Time-sensitive stops, the API will schedule these within their windows
stops_with_windows = [
{ "lat": 52.3726, "lng": 4.8971, "name": "Bakery",
"time_window": { "start": "05:30", "end": "07:00" } },
{ "lat": 52.3620, "lng": 4.8820, "name": "Café",
"time_window": { "start": "07:00", "end": "09:00" } },
{ "lat": 52.3545, "lng": 4.9041, "name": "Restaurant",
"time_window": { "start": "13:00", "end": "15:00" } }
]
إذا لم يكن بالإمكان تلبية قيد أي نافذة وقت بالنظر إلى وقت مغادرة المستودع ونموذج حركة المرور الحالي، يُعيد API مصفوفة constraint_violations تُدرج المحطات التي لم يمكن الوصول إليها في الوقت المناسب. يمكن لبرنامج الإرسال تنبيه السائق أو اقتراح مغادرة أبكر.
ما يمكن بناؤه فوق هذا
تحسين المسارات هو الأساس. بمجرد تشغيله، التوسعات الطبيعية هي:
- تتبع السائق المباشر: أغذِ إحداثيات المسار المُحسَّن إلى درس Live Driver Tracking Map وأظهر للعملاء تحديثات ETA في الوقت الفعلي.
- تخطيط التغطية القائم على Isochrone: استخدم Travel Time API لتصوير الرموز البريدية التي يمكن لأسطولك الوصول إليها ضمن نافذة التوصيل. تُظهر مقالة Isochrone Maps Explained كيف.
- التحقق من العناوين بالجملة: قبل تشغيل التحسين، تحقق من جميع عناوين التوصيل مع Geocoding API لاكتشاف الأخطاء المطبعية والرموز البريدية القديمة. انظر كيفية استخدام Geocoding API للتحقق من 10,000 عنوان بالجملة.
تغطي صفحة صناعة اللوجستيات والتوصيل وصفحة صناعة إدارة الأسطول ميزات MapAtlas الإضافية ذات الصلة ببرامج الإرسال، بما في ذلك VRP متعدد المركبات والتحسين العائد إلى المستودع.
البدء
- سجّل للحصول على مفتاح MapAtlas API مجاناً، الطبقة المجانية تشمل استدعاءات التوجيه والتحسين، لا يلزم بطاقة ائتمان
- راجع توثيق Routing API للقائمة الكاملة لملفات تعريف المركبات ومعلمات نوافذ الوقت وخيارات المتعدد المركبات
- استكشف صفحة قدرات التخطيط والملاحة للحصول على نظرة عامة على المنتج
الأسئلة الشائعة
كيف يُخفّض تحسين المسارات تكاليف التوصيل؟
يُعيد تحسين المسارات ترتيب تسلسلات التوصيل متعددة المحطات لتقليل إجمالي المسافة ووقت القيادة. تُظهر الدراسات باستمرار تخفيضات بنسبة 20-35% في المسافة المقطوعة مقارنةً بالمسار التسلسلي العشوائي. لمركبة تقطع 200 كم يومياً بتكلفة وقود 0.35 يورو/كم، يوفر تخفيض 30% حوالي 21 يورو لكل مركبة يومياً، أي ما يعادل 5000 يورو سنوياً لكل مركبة.
ما هي نوافذ الوقت في تحسين المسارات؟
نوافذ الوقت هي قيود توصيل تتطلب زيارة محطة ضمن نطاق زمني محدد، مثل شركة تقبل التسليمات فقط بين 09:00 و12:00. يجب أن يحترم المُحسِّن جميع نوافذ الوقت مع تقليل إجمالي مسافة المسار، وهي مشكلة حسابية أصعب بكثير من التحسين غير المقيّد.
هل تتعامل MapAtlas Routing API مع مناطق الانبعاثات المنخفضة في الاتحاد الأوروبي؟
نعم. تتضمن MapAtlas Routing API بيانات قيود الطرق لمناطق الانبعاثات المنخفضة في الاتحاد الأوروبي بما فيها منطقة ZTL في أمستردام ومنطقة Crit'Air في باريس وUmweltzone في برلين. مرّر ملف تعريف المركبة (ديزل Euro 5، بنزين، كهربائي) كمعلمة وسيتجنب الموجّه تلقائياً المناطق المقيّدة للمركبات غير المتوافقة.
الأسئلة الشائعة
كيف يُخفّض تحسين المسارات تكاليف التوصيل؟
يُعيد تحسين المسارات ترتيب تسلسلات التوصيل متعددة المحطات لتقليل إجمالي المسافة ووقت القيادة. تُظهر الدراسات باستمرار تخفيضات بنسبة 20-35% في المسافة المقطوعة مقارنةً بالمسار التسلسلي العشوائي. لمركبة تقطع 200 كم يومياً بتكلفة وقود 0.35 يورو/كم، يوفر تخفيض 30% حوالي 21 يورو لكل مركبة يومياً، أي ما يعادل 5000 يورو سنوياً لكل مركبة.
ما هي نوافذ الوقت في تحسين المسارات؟
نوافذ الوقت هي قيود توصيل تتطلب زيارة محطة ضمن نطاق زمني محدد، مثل شركة تقبل التسليمات فقط بين 09:00 و12:00. يجب أن يحترم المُحسِّن جميع نوافذ الوقت مع تقليل إجمالي مسافة المسار، وهي مشكلة حسابية أصعب بكثير من التحسين غير المقيّد.
هل تتعامل MapAtlas Routing API مع مناطق الانبعاثات المنخفضة في الاتحاد الأوروبي؟
نعم. تتضمن MapAtlas Routing API بيانات قيود الطرق لمناطق الانبعاثات المنخفضة في الاتحاد الأوروبي بما فيها منطقة ZTL في أمستردام ومنطقة Crit'Air في باريس وUmweltzone في برلين. مرّر ملف تعريف المركبة (ديزل Euro 5، بنزين، كهربائي) كمعلمة وسيتجنب الموجّه تلقائياً المناطق المقيّدة للمركبات غير المتوافقة.

