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

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

نظرة عامة

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

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

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

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

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

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

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

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

دوال المسافة والمنطقة

المسافة بين نقطتين هي طول المسار الأقصر بينهما. يُطلق على هذا المسار الأقصر اسم جيوديسك. على الكرة، جميع الجيوديسية عبارة عن أجزاء من دائرة كبيرة. لحساب هذه المسافة، يجب استدعاء 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;
الاطّلاع على مثال

تجربة العينة

طرق الترميز

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

containsLocation(point:LatLng, polygon:Polygon)

لمعرفة ما إذا كانت نقطة معيّنة تقع ضمن مضلّع، مرِّر هذه النقطة والمضلّع إلى google.maps.geometry.poly.containsLocation(). ويكون ناتج الدوال صحيحًا إذا كانت النقطة داخل المضلّع أو عند حافته.

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