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

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

סקירה

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

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

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

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

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

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

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

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

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

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

במקום זאת, אם יש כמה מיקומים, אפשר להשתמש בפונקציה computeLength() כדי לחשב את האורך של נתיב נתון.

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

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

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