סקירה כללית
המושגים במסמך הזה מתייחסים לתכונות שזמינות רק בספרייה google.maps.geometry
. הספרייה הזו לא נטענת כברירת מחדל כשאתם טוענים את Maps JavaScript API, אבל צריך לציין אותה במפורש באמצעות פרמטר libraries
של Bootstrap. מידע נוסף זמין במאמר סקירה כללית על ספריות.
ספריית הגיאומטריה של Maps JavaScript API מספקת פונקציות שימושיות לחישוב נתונים גיאומטריים על פני כדור הארץ. הספרייה כוללת שלושה מרחבי שמות:
spherical
מכיל כלי גיאומטריה ספרית שמאפשרים לחשב זוויות, מרחקים ואזורים לפי קוי רוחב ואורך.encoding
מכיל כלי שירות לקידוד ולפענוח של נתיבים של קווים פוליגונליים בהתאם לאלגוריתם של קווים פוליגונליים מקודדים.poly
מכיל פונקציות שירות לחישוב של פוליגונים וקווים פוליגוניים.
הספרייה google.maps.geometry
לא מכילה שום כיתות, אלא שיטות סטטיות במרחבי השמות שלמעלה.
מושגים של גיאומטריה ספרית
התמונות בממשק API של JavaScript במפות Google הן דו-ממדיות ו'שטוחות'. עם זאת, כדור הארץ הוא תלת-ממדי, ולרוב הוא מוצג כאליפסואיד מעוגל או ככדור. ב-Maps API אנחנו משתמשים בספירה, וכדי לייצג את כדור הארץ על משטח שטוח דו-מימדי – כמו מסך המחשב – אנחנו משתמשים ב-Maps API ב הקרנה.
בהקרנות דו-ממדיות, לפעמים המראה מטעה. מכיוון שהקרנה של המפה מחייבת בהכרח עיוות מסוים, לרוב לא ניתן להשתמש בגיאומטריה אוקלידית פשוטה. לדוגמה, המרחק הקצר ביותר בין שתי נקודות על פני ספירה הוא לא קו ישר, אלא מעגל גדול (סוג של גיאודזית), והזווית שמרכיבת משולש על פני ספירה היא יותר מ-180 מעלות.
בגלל ההבדלים האלה, כדי לחשב פונקציות גיאומטריות על פני כדור (או על ההקרנה שלו) צריך להשתמש בגיאומטריה כדורית. כך אפשר לחשב מבנים כמו מרחק, כיוון ושטח. כלי השירות לחישוב המבנים הגיאומטריים הכדוריים האלה נכללים במרחב השמות google.maps.geometry.spherical
של Maps API. במרחב השמות הזה יש שיטות סטטיות לחישוב ערכים סקלריים מקואורדינטות כדוריות (קוי רוחב ואורך).
פונקציות מרחק ושטח
המרחק בין שתי נקודות הוא אורך הדרך הקצרה ביותר ביניהן. הנתיב הקצר ביותר נקרא נתיב גיאודטי. בכדור, כל הקווים הגיאודטיים הם קטעים של מעגל גדול. כדי לחשב את המרחק הזה, צריך להפעיל את computeDistanceBetween()
ולהעביר אליה שני אובייקטים מסוג LatLng
.
אם יש לכם כמה מיקומים, תוכלו להשתמש במקום זאת ב-
computeLength()
כדי לחשב את האורך של נתיב נתון.
תוצאות המרחק מוצגות במטרים.
כדי לחשב את השטח (במטרים רבועים) של אזור פוליגונלי, צריך להפעיל את הפונקציה computeArea()
ולהעביר את המערך של אובייקטים מסוג LatLng
שמגדירים לולאה סגורה.
פונקציות ניווט
כשמנווטים בספירה, כיוון הוא הזווית של כיוון מנקודה קבועה של עיון, בדרך כלל הצפון האמיתי. ב-Google Maps API, כיוון מוגדר בזוויות מצפון אמיתי, כאשר הכיוונים נמדדים בכיוון השעון מצפון אמיתי (0 מעלות). אפשר לחשב את הכיוון הזה בין שני מיקומים באמצעות השיטה computeHeading()
, ולהעביר לה שני אובייקטים מסוג LatLng
של from
ו-to
.
אם נתונים כיוון מסוים, מיקום מוצא והמרחק לנסיעה (במטרים), אפשר לחשב את קואורדינטות היעד באמצעות computeOffset()
.
אם נתונים שני אובייקטים מסוג LatLng
וערך בין 0 ל-1, אפשר גם לחשב יעד ביניהן באמצעות השיטה interpolate()
, שמבצעת אינטרפולציה לינארית ספרית בין שני המיקומים, כאשר הערך מציין את המרחק החלקי שצריך לעבור לאורך הנתיב מהמקור ליעד.
בדוגמה הבאה נוצרות שתי קווים פוליגונים כשלוחצים על שתי נקודות במפה – קו גיאודטי אחד וקו "ישר" אחד שמחבר בין שני המיקומים – ומחושבת כיוון הנסיעה בין שתי הנקודות:
TypeScript
// This example requires the Geometry library. Include the libraries=geometry // parameter when you first load the API. For example: // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"> let marker1: google.maps.Marker, marker2: google.maps.Marker; let poly: google.maps.Polyline, geodesicPoly: google.maps.Polyline; function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 4, center: { lat: 34, lng: -40.605 }, } ); map.controls[google.maps.ControlPosition.TOP_CENTER].push( document.getElementById("info") as HTMLElement ); marker1 = new google.maps.Marker({ map, draggable: true, position: { lat: 40.714, lng: -74.006 }, }); marker2 = new google.maps.Marker({ map, draggable: true, position: { lat: 48.857, lng: 2.352 }, }); const bounds = new google.maps.LatLngBounds( marker1.getPosition() as google.maps.LatLng, marker2.getPosition() as google.maps.LatLng ); map.fitBounds(bounds); google.maps.event.addListener(marker1, "position_changed", update); google.maps.event.addListener(marker2, "position_changed", update); poly = new google.maps.Polyline({ strokeColor: "#FF0000", strokeOpacity: 1.0, strokeWeight: 3, map: map, }); geodesicPoly = new google.maps.Polyline({ strokeColor: "#CC0099", strokeOpacity: 1.0, strokeWeight: 3, geodesic: true, map: map, }); update(); } function update() { const path = [ marker1.getPosition() as google.maps.LatLng, marker2.getPosition() as google.maps.LatLng, ]; poly.setPath(path); geodesicPoly.setPath(path); const heading = google.maps.geometry.spherical.computeHeading( path[0], path[1] ); (document.getElementById("heading") as HTMLInputElement).value = String(heading); (document.getElementById("origin") as HTMLInputElement).value = String( path[0] ); (document.getElementById("destination") as HTMLInputElement).value = String( path[1] ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
// This example requires the Geometry library. Include the libraries=geometry // parameter when you first load the API. For example: // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"> let marker1, marker2; let poly, geodesicPoly; function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 4, center: { lat: 34, lng: -40.605 }, }); map.controls[google.maps.ControlPosition.TOP_CENTER].push( document.getElementById("info"), ); marker1 = new google.maps.Marker({ map, draggable: true, position: { lat: 40.714, lng: -74.006 }, }); marker2 = new google.maps.Marker({ map, draggable: true, position: { lat: 48.857, lng: 2.352 }, }); const bounds = new google.maps.LatLngBounds( marker1.getPosition(), marker2.getPosition(), ); map.fitBounds(bounds); google.maps.event.addListener(marker1, "position_changed", update); google.maps.event.addListener(marker2, "position_changed", update); poly = new google.maps.Polyline({ strokeColor: "#FF0000", strokeOpacity: 1.0, strokeWeight: 3, map: map, }); geodesicPoly = new google.maps.Polyline({ strokeColor: "#CC0099", strokeOpacity: 1.0, strokeWeight: 3, geodesic: true, map: map, }); update(); } function update() { const path = [marker1.getPosition(), marker2.getPosition()]; poly.setPath(path); geodesicPoly.setPath(path); const heading = google.maps.geometry.spherical.computeHeading( path[0], path[1], ); document.getElementById("heading").value = String(heading); document.getElementById("origin").value = String(path[0]); document.getElementById("destination").value = String(path[1]); } window.initMap = initMap;
ניסיון של דוגמה
שיטות קידוד
לרוב, נתיבים ב-Maps JavaScript API מצוינים בתור Array
של אובייקטים מסוג LatLng
. עם זאת, העברת מערך כזה לעיתים קרובות מכבידה על הקוד. במקום זאת, אפשר להשתמש באלגוריתם של Google לקידוד קווים פוליגונליים כדי לדחוס נתיב נתון, שאפשר לבצע לו לאחר מכן דחיסה חוזרת באמצעות פענוח.
הספרייה geometry
מכילה מרחב שמות encoding
לשירותים לקודד ולפענח קווים פוליגונליים.
השיטה הסטטית encodePath()
מקודדת את הנתיב שצוין.
אפשר להעביר מערך של LatLng
או MVCArray
(שחוזר על ידי Polyline.getPath()
).
כדי לפענח נתיב מוצפן, צריך לבצע קריאה ל-method decodePath()
ולהעביר לו את המחרוזת המוצפנת.
בדוגמה הבאה מוצגת מפה של אוקספורד, מיסיסיפי. לחיצה על המפה מוסיפה נקודה לקו פוליגון. בזמן היצירה של קו הפוליגון, הקידוד שלו מופיע מתחתיו.
TypeScript
// This example requires the Geometry library. Include the libraries=geometry // parameter when you first load the API. For example: // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"> function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 14, center: { lat: 34.366, lng: -89.519 }, } ); const poly = new google.maps.Polyline({ strokeColor: "#000000", strokeOpacity: 1, strokeWeight: 3, map: map, }); // Add a listener for the click event google.maps.event.addListener(map, "click", (event) => { addLatLngToPoly(event.latLng, poly); }); } /** * Handles click events on a map, and adds a new point to the Polyline. * Updates the encoding text area with the path's encoded values. */ function addLatLngToPoly( latLng: google.maps.LatLng, poly: google.maps.Polyline ) { const path = poly.getPath(); // Because path is an MVCArray, we can simply append a new coordinate // and it will automatically appear path.push(latLng); // Update the text field to display the polyline encodings const encodeString = google.maps.geometry.encoding.encodePath(path); if (encodeString) { (document.getElementById("encoded-polyline") as HTMLInputElement).value = encodeString; } } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
// This example requires the Geometry library. Include the libraries=geometry // parameter when you first load the API. For example: // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"> function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 14, center: { lat: 34.366, lng: -89.519 }, }); const poly = new google.maps.Polyline({ strokeColor: "#000000", strokeOpacity: 1, strokeWeight: 3, map: map, }); // Add a listener for the click event google.maps.event.addListener(map, "click", (event) => { addLatLngToPoly(event.latLng, poly); }); } /** * Handles click events on a map, and adds a new point to the Polyline. * Updates the encoding text area with the path's encoded values. */ function addLatLngToPoly(latLng, poly) { const path = poly.getPath(); // Because path is an MVCArray, we can simply append a new coordinate // and it will automatically appear path.push(latLng); // Update the text field to display the polyline encodings const encodeString = google.maps.geometry.encoding.encodePath(path); if (encodeString) { document.getElementById("encoded-polyline").value = encodeString; } } window.initMap = initMap;
ניסיון של דוגמה
פונקציות של פוליגונים וקווים פוליגונים
מרחב השמות poly
של ספריית הגיאומטריה מכיל פונקציות שירות שמאפשרות לקבוע אם נקודה מסוימת נמצאת בתוך פוליגון או קו פוליגון, או ליד אחד מהם.
containsLocation()
containsLocation(point:LatLng, polygon:Polygon)
כדי לבדוק אם נקודה מסוימת נמצאת בתוך פוליגון, מעבירים את הנקודה ואת הפוליגון ל-google.maps.geometry.poly.containsLocation()
. הפונקציות מחזירות את הערך true אם הנקודה נמצאת בתוך הפוליגון או על הקצה שלו.
הקוד הבא כותב 'true' למסוף הדפדפן אם הלחיצה של המשתמש נמצאת בתוך המשולש המוגדר, אחרת הוא כותב 'false'.
function initialize() { var mapOptions = { zoom: 5, center: new google.maps.LatLng(24.886, -70.269), mapTypeId: 'terrain' }; var map = new google.maps.Map(document.getElementById('map'), mapOptions); var bermudaTriangle = new google.maps.Polygon({ paths: [ new google.maps.LatLng(25.774, -80.190), new google.maps.LatLng(18.466, -66.118), new google.maps.LatLng(32.321, -64.757) ] }); google.maps.event.addListener(map, 'click', function(event) { console.log(google.maps.geometry.poly.containsLocation(event.latLng, bermudaTriangle)); }); } google.maps.event.addDomListener(window, 'load', initialize);
גרסה אחרת של הקוד הזה גורמת לציור של משולש כחול במפה אם הלחיצה נמצאת בתוך משולש ברמודה, ושל עיגול אדום אחרת:
isLocationOnEdge()
isLocationOnEdge(point:LatLng, poly:Polygon|Polyline, tolerance?:number)
כדי לקבוע אם נקודה נמצאת על קו פוליגון או לידו, או על קצה של פוליגון או לידו, מעבירים את הנקודה, את קו הפוליגון או את הפוליגון, ואם רוצים גם ערך סבילות בדרגות, ל-google.maps.geometry.poly.isLocationOnEdge()
. הפונקציה מחזירה את הערך true אם המרחק בין הנקודה לנקודה הקרובה ביותר על הקו או על הקצה נמצא בטווח הסף שצוין. ערך ברירת המחדל של הסובלנות הוא 10-9 מעלות.
function initialize() { var myPosition = new google.maps.LatLng(46.0, -125.9); var mapOptions = { zoom: 5, center: myPosition, mapTypeId: 'terrain' }; var map = new google.maps.Map(document.getElementById('map'), mapOptions); var cascadiaFault = new google.maps.Polyline({ path: [ new google.maps.LatLng(49.95, -128.1), new google.maps.LatLng(46.26, -126.3), new google.maps.LatLng(40.3, -125.4) ] }); cascadiaFault.setMap(map); if (google.maps.geometry.poly.isLocationOnEdge(myPosition, cascadiaFault, 10e-1)) { alert("Relocate!"); } } google.maps.event.addDomListener(window, 'load', initialize);