ספריית Geometry

  1. סקירה כללית
  2. מושגים של גיאומטריה כדורית
    1. פונקציות של מרחק ושטח
    2. פונקציות ניווט
  3. קידוד גיאומטרי
  4. פונקציות של פוליגונים וקווים פוליגוניים
    1. containsLocation()
    2. isLocationOnEdge()
    3. בדיקות של גבולות וירטואליים ורדיוס של אזור בטוח

סקירה כללית

המושגים במסמך הזה מתייחסים לתכונות שזמינות רק בספרייה google.maps.geometry. הספרייה הזו לא נטענת כברירת מחדל כשאתם טוענים את Maps JavaScript API, אלא צריך לציין אותה באופן מפורש באמצעות פרמטר ה-bootstrap‏ libraries. מידע נוסף זמין במאמר סקירה כללית על ספריות.

ספריית הגיאומטריה של Maps JavaScript API מספקת פונקציות בסיסיות לחישוב נתונים גיאומטריים על פני כדור הארץ. הספרייה כוללת שלושה מרחבי שמות:

  • spherical מכילה כלי עזר לגיאומטריה כדורית שמאפשרים לחשב זוויות, מרחקים ושטחים מקווי רוחב וקווי אורך.
  • encoding מכיל כלי עזר לקידוד ולפענוח של נתיבי קווים פוליגוניים בהתאם לאלגוריתם של קו פוליגון מקודד.
  • poly מכילה פונקציות בסיסיות לחישובים שכוללים פוליגונים וקווים פוליגוניים.

הספרייה google.maps.geometry לא מכילה מחלקות, אלא שיטות סטטיות במרחבי השמות שלמעלה.

מושגים בגיאומטריה כדורית

התמונות ב-Maps JavaScript API הן דו-ממדיות ו "שטוחות". אבל כדור הארץ הוא תלת-ממדי, ולרוב מתייחסים אליו כאל ספרואיד פחוס או כאל כדור. ב-Maps API אנחנו משתמשים בכדור, וכדי לייצג את כדור הארץ על משטח שטוח דו-ממדי – כמו מסך המחשב – Maps API משתמש ב היטל.

בהיטלים דו-ממדיים, לפעמים המראה יכול להטעות. מכיוון שההיטל של המפה דורש בהכרח עיוות מסוים, לעיתים קרובות אי אפשר להשתמש בגיאומטריה אוקלידית פשוטה. לדוגמה, המרחק הקצר ביותר בין שתי נקודות על כדור הוא לא קו ישר, אלא מעגל גדול (סוג של גאודזיה), והזוויות שמרכיבות משולש על פני השטח של כדור מסתכמות ביותר מ-180 מעלות.

בגלל ההבדלים האלה, פונקציות גיאומטריות על כדור (או על ההיטל שלו) מחייבות שימוש בגיאומטריה כדורית כדי לחשב מבנים כמו מרחק, כיוון ושטח. כלי העזר לחישוב המבנים הגיאומטריים הכדוריים האלה כלולים במרחב השמות google.maps.geometry.spherical של Maps API. מרחב השמות הזה מספק שיטות סטטיות לחישוב ערכים סקלריים מקואורדינטות כדוריות (קווי רוחב וקווי אורך).

פונקציות מרחק ושטח

המרחק בין שתי נקודות הוא אורך המסלול הקצר ביותר ביניהן. הנתיב הקצר ביותר הזה נקרא קו גיאודזי. על כדור, כל הקווים הגיאודזיים הם מקטעים של מעגל גדול. כדי לחשב את המרחק הזה, קוראים ל-computeDistanceBetween() ומעבירים לו שני אובייקטים מסוג LatLng.

אם יש לכם כמה מיקומים, אתם יכולים להשתמש ב- computeLength() כדי לחשב את האורך של נתיב מסוים.

תוצאות המרחק מוצגות במטרים.

כדי לחשב את השטח (במטרים רבועים) של אזור פוליגוני, קוראים ל-computeArea() ומעבירים את מערך האובייקטים מסוג LatLng שמגדירים לולאה סגורה.

כשמנווטים על כדור, הכיוון הוא זווית הכיוון מנקודת ייחוס קבועה, בדרך כלל הצפון האמיתי. ב-Google Maps API, כיוון מוגדר במעלות מהצפון האמיתי, כאשר הכיוונים נמדדים בכיוון השעון מהצפון האמיתי (0 מעלות). אפשר לחשב את הכיוון הזה בין שני מיקומים באמצעות ה-method‏ computeHeading(), ולהעביר לה שני אובייקטים של from ו-to LatLng.

אם יש לכם כיוון מסוים, מיקום מוצא ומרחק נסיעה (במטרים), אתם יכולים לחשב את הקואורדינטות של היעד באמצעות 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()).

כדי לפענח מסלול מקודד, צריך להפעיל את decodePath() ולהעביר ל-method את המחרוזת המקודדת.

בדוגמה הבאה מוצגת מפה של אוקספורד, מיסיסיפי. לחיצה על המפה מוסיפה נקודה לקו פוליגוני. בזמן שיוצרים את הקו הפוליגוני, הקידוד שלו מופיע מתחתיו.

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|LatLngLiteral, polygon:Polygon|Circle|CircleLiteral)

כדי לבדוק אם נקודה מסוימת נמצאת בתוך פוליגון או מעגל, מעבירים את הנקודה ואת google.maps.Polygon,‏ google.maps.Circle או google.maps.CircleLiteral אל 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);

בדיקות של רדיוס הגבול הווירטואלי והאזור הבטוח

כדי לבדוק אם קואורדינטה בזמן אמת (כמו מיקום של רכב, נכס או משתמש) נמצאת בתוך גבולות וירטואליים או אזור בטוח במפה, משלבים צורות במפה עם הספרייה geometry: