ספרייה גיאומטרית

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

סקירה כללית

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

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

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

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

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

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

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

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

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

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

רוצה לנסות דוגמה?

שיטות קידוד

נתיבים בתוך ה-API של JavaScript במפות Google מצוינים בדרך כלל כ-Array מתוך LatLng אובייקטים. עם זאת, העברה של מערך כזה היא לעיתים קרובות מגוונת. במקום זאת, אפשר להשתמש באלגוריתם של קידוד הפוליגונים של Google כדי לדחוס נתיב נתון, ולאחר מכן לפענח אותו באמצעות פענוח הקוד.

הספרייה geometry מכילה מרחב שמות של encoding לתוכניות שמיועדות לקודד ולפענח פוליגונים.

השיטה הסטטית encodePath() מקודדת את הנתיב הנתון. אפשר להעביר מערך של LatLng או מערך של MVCArray (שמוחזר על ידי Polyline.getPath()).

כדי לפענח נתיב מקודד, צריך לבצע קריאה ל-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);