مكتبة الهندسة

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

نظرة عامة

تشير المفاهيم الواردة في هذا المستند إلى الميزات المتوفّرة فقط في مكتبة google.maps.geometry. لا يتم تحميل هذه المكتبة تلقائيًا عند تحميل واجهة برمجة تطبيقات JavaScript للخرائط، ولكن يجب تحديدها بشكل واضح من خلال استخدام معلَمة التشغيل libraries. لمزيد من المعلومات، يُرجى الاطّلاع على نظرة عامة على المكتبات.

توفّر مكتبة الهندسة الخاصة بواجهة برمجة تطبيقات JavaScript في "خرائط Google" دوال مفيدة لحساب البيانات الهندسية على سطح الأرض. تتضمن المكتبة ثلاث مساحات اسم:

  • يحتوي spherical على أدوات هندسية كروية تسمح لك بحساب الزوايا والمسافات والمناطق من خطوط العرض وخطوط الطول.
  • يحتوي encoding على أدوات لترميز المسارات المتعددة الخطوط وفك ترميزها وفقًا للخوارزمية المتعددة الأسطر المشفَّرة.
  • يحتوي poly على دوال الخدمات الحسابية التي تتضمّن المضلّعات والخطوط المتعددة.

لا تحتوي مكتبة google.maps.geometry على أي فئات، بل تحتوي بدلاً من ذلك على طرق ثابتة في مساحات الأسماء أعلاه.

مفاهيم الهندسة الكروي

تُعد الصور داخل واجهة برمجة تطبيقات JavaScript للخرائط ثنائية الأبعاد و "مسطّحة". في المقابل، إنّ الأرض ثلاثية الأبعاد وغالبًا ما تكون قريبة من شكل كروي كروي أو كروية. في واجهة برمجة التطبيقات للخرائط نستخدم كرة، ولتمثيل الأرض على سطح مستوٍ ثنائي الأبعاد، مثل شاشة الكمبيوتر، تستخدم واجهة برمجة تطبيقات الخرائط عرضًا.

ضمن الإسقاطات الثنائية الأبعاد، يمكن أن تكون المظاهر خادعة في بعض الأحيان. نظرًا لأن إسقاط الخريطة يتطلب بالضرورة بعض التشويه، فإن الهندسة الإقليدية البسيطة لا تنطبق غالبًا. على سبيل المثال، أقصر مسافة بين نقطتين على الكرة ليست خطًا مستقيمًا، ولكنها دائرة كبيرة (نوع من الجيوديسية)، ويصل مجموع الزوايا التي يتكون منها المثلث على سطح الكرة إلى أكثر من 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;
الاطّلاع على مثال

تجربة "عيّنة"

الدوال المضلّعة والمتعددة الخطوط

إنّ مساحة الاسم 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);