مكتبة الأشكال الهندسية

  1. نظرة عامة
  2. مفاهيم الهندسة الكروية
    1. دوال المسافة والمساحة
    2. دوال التنقّل
  3. ترميز الهندسة
  4. دوال المضلّعات والخطوط المتعدّدة
    1. containsLocation()
    2. isLocationOnEdge()
    3. التحقّق من الحدود الجغرافية ونطاق المنطقة الآمنة

نظرة عامة

تشير المفاهيم الواردة في هذا المستند إلى الميزات المتوفّرة فقط في مكتبة google.maps.geometry. لا يتم تحميل هذه المكتبة تلقائيًا عند تحميل واجهة برمجة التطبيقات Maps JavaScript API، ولكن يجب تحديدها بشكل صريح من خلال استخدام مَعلمة الإعداد 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 درجة). يمكنك حساب هذا الاتجاه بين موقعَين جغرافيَين باستخدام طريقة 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() وتمرير السلسلة المرمّزة إلى الطريقة.

يعرض المثال التالي خريطة لمدينة أكسفورد في ولاية ميسيسيبي. يؤدي النقر على الخريطة إلى إضافة نقطة إلى خط متعدّد. أثناء إنشاء الخطوط المتعدّدة، يظهر ترميزها في الأسفل.

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;
الاطّلاع على مثال

دالتا Polygon وPolyline

تحتوي مساحة الاسم 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 إذا كانت النقطة داخل الشكل أو على حافته.

يكتب الرمز التالي "صحيح" في وحدة تحكّم المتصفّح إذا كانت نقرة المستخدم تقع ضمن المثلث المحدّد، وإلا يكتب "خطأ".

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(). تعرض الدالة القيمة "صحيح" إذا كانت المسافة بين النقطة وأقرب نقطة على الخط أو الحافة تقع ضمن نطاق التفاوت المسموح به. القيمة التلقائية للتفاوت المسموح به هي 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: