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

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

نظرة عامة

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

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

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

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

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

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

في الإسقاطات ثنائية الأبعاد، قد تكون المظاهر خادعة في بعض الأحيان. ونظرًا لأن إسقاط الخريطة يتطلب بالضرورة بعض التشويه، فإن الهندسة الإقليدية البسيطة لا تنطبق غالبًا. على سبيل المثال، أقصر مسافة بين نقطتين على الكرة الأرضية ليست خطًا مستقيمًا، بل هي دائرة رائعة (نوع من الجيوديسية)، والزوايا التي تتكوّن منها مثلثًا على سطح الكرة الأرضية يصل مجموعها إلى أكثر من 180 درجة.

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

دوال المسافة والمساحة

المسافة بين نقطتين هي طول أقصر مسار بينهما. ويسمى هذا المسار الأقصر جيوديسي. في عالم ما، جميع الجيوديسك عبارة عن أجزاء من دائرة كبيرة. لحساب هذه المسافة، يمكنك استدعاء computeDistanceBetween()، مع تمرير LatLng كائنين منها.

يمكنك بدلاً من ذلك استخدام computeLength() لحساب طول مسار إذا كنت تمتلك عدة مواقع جغرافية.

يتم التعبير عن نتائج المسافة بالأمتار.

لحساب مساحة (بالأمتار المربّعة) لمنطقة مضلعة، استخدِم computeArea()، مع تمرير مصفوفة العناصر LatLng التي تحدّد حلقة مغلقة.

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

تجربة النموذج

طرق التشفير

غالبًا ما يتم تحديد المسارات ضمن واجهة برمجة تطبيقات JavaScript للخرائط على أنها 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(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);