#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <iostream>
#include <cmath>
namespace bg = boost::geometry;
typedef bg::model::point<double, 2, bg::cs::geographic<bg::degree>> point_type;
typedef bg::model::linestring<point_type> linestring_type;
// Конвертация географических координат в ECEF (Earth-Centered, Earth-Fixed)
void geo_to_ecef(double lat, double lon, double& x, double& y, double& z) {
const double R = 6378137.0; // Радиус Земли в метрах
const double lat_rad = lat * M_PI / 180.0;
const double lon_rad = lon * M_PI / 180.0;
x = R * cos(lat_rad) * cos(lon_rad);
y = R * cos(lat_rad) * sin(lon_rad);
z = R * sin(lat_rad);
}
double calculate_angle(const linestring_type& line1, const linestring_type& line2) {
if (line1.size() < 2 || line2.size() < 2) {
return 0.0; // Неверные линии
}
// Получаем начальную и конечную точки каждой линии
const point_type& A = line1.front();
const point_type& B = line1.back();
const point_type& C = line2.front();
const point_type& D = line2.back();
// Конвертируем в ECEF координаты
double Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz, Dx, Dy, Dz;
geo_to_ecef(bg::get<0>(A), bg::get<1>(A), Ax, Ay, Az);
geo_to_ecef(bg::get<0>(B), bg::get<1>(B), Bx, By, Bz);
geo_to_ecef(bg::get<0>(C), bg::get<1>(C), Cx, Cy, Cz);
geo_to_ecef(bg::get<0>(D), bg::get<1>(D), Dx, Dy, Dz);
// Вычисляем векторы направлений
double ABx = Bx - Ax;
double ABy = By - Ay;
double ABz = Bz - Az;
double CDx = Dx - Cx;
double CDy = Dy - Cy;
double CDz = Dz - Cz;
// Нормализуем векторы
double len_AB = sqrt(ABx*ABx + ABy*ABy + ABz*ABz);
double len_CD = sqrt(CDx*CDx + CDy*CDy + CDz*CDz);
ABx /= len_AB; ABy /= len_AB; ABz /= len_AB;
CDx /= len_CD; CDy /= len_CD; CDz /= len_CD;
// Вычисляем скалярное произведение
double dot_product = ABx*CDx + ABy*CDy + ABz*CDz;
// Обеспечиваем, чтобы значение dot_product было в диапазоне [-1, 1]
dot_product = std::max(-1.0, std::min(1.0, dot_product));
// Вычисляем угол в радианах, затем конвертируем в градусы
double angle_rad = acos(dot_product);
double angle_deg = angle_rad * 180.0 / M_PI;
// Если угол больше 90 градусов, возвращаем острый угол
if (angle_deg > 90.0) {
angle_deg = 180.0 - angle_deg;
}
return angle_deg;
}
bool are_collinear(const linestring_type& line1, const linestring_type& line2) {
// Линии колинеарны, если угол между ними близок к 0 или 180 градусов
double angle = calculate_angle(line1, line2);
return angle < 1e-6;
}
int main() {
linestring_type line1, line2;
// Инициализация первой линии с заданными координатами
bg::append(line1, point_type(45.094734, 37.565922));
bg::append(line1, point_type(45.094696, 37.566153));
// Инициализация второй линии
// Пример другой линии, можно заменить на свою
bg::append(line2, point_type(45.094972, 37.565076));
bg::append(line2, point_type(45.194934, 37.565307));
// Вычисление угла между линиями
double angle = calculate_angle(line1, line2);
std::cout << "Угол между линиями: " << angle << " градусов" << std::endl;
// Проверка колинеарности
if (are_collinear(line1, line2)) {
std::cout << "Линии колинеарны." << std::endl;
} else {
std::cout << "Линии не колинеарны." << std::endl;
}
return 0;
}
I2luY2x1ZGUgPGJvb3N0L2dlb21ldHJ5LmhwcD4KI2luY2x1ZGUgPGJvb3N0L2dlb21ldHJ5L2dlb21ldHJpZXMvcG9pbnQuaHBwPgojaW5jbHVkZSA8Ym9vc3QvZ2VvbWV0cnkvZ2VvbWV0cmllcy9saW5lc3RyaW5nLmhwcD4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y21hdGg+CgpuYW1lc3BhY2UgYmcgPSBib29zdDo6Z2VvbWV0cnk7Cgp0eXBlZGVmIGJnOjptb2RlbDo6cG9pbnQ8ZG91YmxlLCAyLCBiZzo6Y3M6Omdlb2dyYXBoaWM8Ymc6OmRlZ3JlZT4+IHBvaW50X3R5cGU7CnR5cGVkZWYgYmc6Om1vZGVsOjpsaW5lc3RyaW5nPHBvaW50X3R5cGU+IGxpbmVzdHJpbmdfdHlwZTsKCi8vINCa0L7QvdCy0LXRgNGC0LDRhtC40Y8g0LPQtdC+0LPRgNCw0YTQuNGH0LXRgdC60LjRhSDQutC+0L7RgNC00LjQvdCw0YIg0LIgRUNFRiAoRWFydGgtQ2VudGVyZWQsIEVhcnRoLUZpeGVkKQp2b2lkIGdlb190b19lY2VmKGRvdWJsZSBsYXQsIGRvdWJsZSBsb24sIGRvdWJsZSYgeCwgZG91YmxlJiB5LCBkb3VibGUmIHopIHsKICAgIGNvbnN0IGRvdWJsZSBSID0gNjM3ODEzNy4wOyAvLyDQoNCw0LTQuNGD0YEg0JfQtdC80LvQuCDQsiDQvNC10YLRgNCw0YUKICAgIGNvbnN0IGRvdWJsZSBsYXRfcmFkID0gbGF0ICogTV9QSSAvIDE4MC4wOwogICAgY29uc3QgZG91YmxlIGxvbl9yYWQgPSBsb24gKiBNX1BJIC8gMTgwLjA7CiAgICAKICAgIHggPSBSICogY29zKGxhdF9yYWQpICogY29zKGxvbl9yYWQpOwogICAgeSA9IFIgKiBjb3MobGF0X3JhZCkgKiBzaW4obG9uX3JhZCk7CiAgICB6ID0gUiAqIHNpbihsYXRfcmFkKTsKfQoKZG91YmxlIGNhbGN1bGF0ZV9hbmdsZShjb25zdCBsaW5lc3RyaW5nX3R5cGUmIGxpbmUxLCBjb25zdCBsaW5lc3RyaW5nX3R5cGUmIGxpbmUyKSB7CiAgICBpZiAobGluZTEuc2l6ZSgpIDwgMiB8fCBsaW5lMi5zaXplKCkgPCAyKSB7CiAgICAgICAgcmV0dXJuIDAuMDsgLy8g0J3QtdCy0LXRgNC90YvQtSDQu9C40L3QuNC4CiAgICB9CgogICAgLy8g0J/QvtC70YPRh9Cw0LXQvCDQvdCw0YfQsNC70YzQvdGD0Y4g0Lgg0LrQvtC90LXRh9C90YPRjiDRgtC+0YfQutC4INC60LDQttC00L7QuSDQu9C40L3QuNC4CiAgICBjb25zdCBwb2ludF90eXBlJiBBID0gbGluZTEuZnJvbnQoKTsKICAgIGNvbnN0IHBvaW50X3R5cGUmIEIgPSBsaW5lMS5iYWNrKCk7CiAgICBjb25zdCBwb2ludF90eXBlJiBDID0gbGluZTIuZnJvbnQoKTsKICAgIGNvbnN0IHBvaW50X3R5cGUmIEQgPSBsaW5lMi5iYWNrKCk7CgogICAgLy8g0JrQvtC90LLQtdGA0YLQuNGA0YPQtdC8INCyIEVDRUYg0LrQvtC+0YDQtNC40L3QsNGC0YsKICAgIGRvdWJsZSBBeCwgQXksIEF6LCBCeCwgQnksIEJ6LCBDeCwgQ3ksIEN6LCBEeCwgRHksIER6OwogICAgZ2VvX3RvX2VjZWYoYmc6OmdldDwwPihBKSwgYmc6OmdldDwxPihBKSwgQXgsIEF5LCBBeik7CiAgICBnZW9fdG9fZWNlZihiZzo6Z2V0PDA+KEIpLCBiZzo6Z2V0PDE+KEIpLCBCeCwgQnksIEJ6KTsKICAgIGdlb190b19lY2VmKGJnOjpnZXQ8MD4oQyksIGJnOjpnZXQ8MT4oQyksIEN4LCBDeSwgQ3opOwogICAgZ2VvX3RvX2VjZWYoYmc6OmdldDwwPihEKSwgYmc6OmdldDwxPihEKSwgRHgsIER5LCBEeik7CgogICAgLy8g0JLRi9GH0LjRgdC70Y/QtdC8INCy0LXQutGC0L7RgNGLINC90LDQv9GA0LDQstC70LXQvdC40LkKICAgIGRvdWJsZSBBQnggPSBCeCAtIEF4OwogICAgZG91YmxlIEFCeSA9IEJ5IC0gQXk7CiAgICBkb3VibGUgQUJ6ID0gQnogLSBBejsKICAgIGRvdWJsZSBDRHggPSBEeCAtIEN4OwogICAgZG91YmxlIENEeSA9IER5IC0gQ3k7CiAgICBkb3VibGUgQ0R6ID0gRHogLSBDejsKCiAgICAvLyDQndC+0YDQvNCw0LvQuNC30YPQtdC8INCy0LXQutGC0L7RgNGLCiAgICBkb3VibGUgbGVuX0FCID0gc3FydChBQngqQUJ4ICsgQUJ5KkFCeSArIEFCeipBQnopOwogICAgZG91YmxlIGxlbl9DRCA9IHNxcnQoQ0R4KkNEeCArIENEeSpDRHkgKyBDRHoqQ0R6KTsKICAgIEFCeCAvPSBsZW5fQUI7IEFCeSAvPSBsZW5fQUI7IEFCeiAvPSBsZW5fQUI7CiAgICBDRHggLz0gbGVuX0NEOyBDRHkgLz0gbGVuX0NEOyBDRHogLz0gbGVuX0NEOwoKICAgIC8vINCS0YvRh9C40YHQu9GP0LXQvCDRgdC60LDQu9GP0YDQvdC+0LUg0L/RgNC+0LjQt9Cy0LXQtNC10L3QuNC1CiAgICBkb3VibGUgZG90X3Byb2R1Y3QgPSBBQngqQ0R4ICsgQUJ5KkNEeSArIEFCeipDRHo7CiAgICAKICAgIC8vINCe0LHQtdGB0L/QtdGH0LjQstCw0LXQvCwg0YfRgtC+0LHRiyDQt9C90LDRh9C10L3QuNC1IGRvdF9wcm9kdWN0INCx0YvQu9C+INCyINC00LjQsNC/0LDQt9C+0L3QtSBbLTEsIDFdCiAgICBkb3RfcHJvZHVjdCA9IHN0ZDo6bWF4KC0xLjAsIHN0ZDo6bWluKDEuMCwgZG90X3Byb2R1Y3QpKTsKICAgIAogICAgLy8g0JLRi9GH0LjRgdC70Y/QtdC8INGD0LPQvtC7INCyINGA0LDQtNC40LDQvdCw0YUsINC30LDRgtC10Lwg0LrQvtC90LLQtdGA0YLQuNGA0YPQtdC8INCyINCz0YDQsNC00YPRgdGLCiAgICBkb3VibGUgYW5nbGVfcmFkID0gYWNvcyhkb3RfcHJvZHVjdCk7CiAgICBkb3VibGUgYW5nbGVfZGVnID0gYW5nbGVfcmFkICogMTgwLjAgLyBNX1BJOwogICAgCiAgICAvLyDQldGB0LvQuCDRg9Cz0L7QuyDQsdC+0LvRjNGI0LUgOTAg0LPRgNCw0LTRg9GB0L7Qsiwg0LLQvtC30LLRgNCw0YnQsNC10Lwg0L7RgdGC0YDRi9C5INGD0LPQvtC7CiAgICBpZiAoYW5nbGVfZGVnID4gOTAuMCkgewogICAgICAgIGFuZ2xlX2RlZyA9IDE4MC4wIC0gYW5nbGVfZGVnOwogICAgfQogICAgCiAgICByZXR1cm4gYW5nbGVfZGVnOwp9Cgpib29sIGFyZV9jb2xsaW5lYXIoY29uc3QgbGluZXN0cmluZ190eXBlJiBsaW5lMSwgY29uc3QgbGluZXN0cmluZ190eXBlJiBsaW5lMikgewogICAgLy8g0JvQuNC90LjQuCDQutC+0LvQuNC90LXQsNGA0L3Riywg0LXRgdC70Lgg0YPQs9C+0Lsg0LzQtdC20LTRgyDQvdC40LzQuCDQsdC70LjQt9C+0Log0LogMCDQuNC70LggMTgwINCz0YDQsNC00YPRgdC+0LIKICAgIGRvdWJsZSBhbmdsZSA9IGNhbGN1bGF0ZV9hbmdsZShsaW5lMSwgbGluZTIpOwogICAgcmV0dXJuIGFuZ2xlIDwgMWUtNjsKfQoKaW50IG1haW4oKSB7CiAgICBsaW5lc3RyaW5nX3R5cGUgbGluZTEsIGxpbmUyOwoKICAgIC8vINCY0L3QuNGG0LjQsNC70LjQt9Cw0YbQuNGPINC/0LXRgNCy0L7QuSDQu9C40L3QuNC4INGBINC30LDQtNCw0L3QvdGL0LzQuCDQutC+0L7RgNC00LjQvdCw0YLQsNC80LgKICAgIGJnOjphcHBlbmQobGluZTEsIHBvaW50X3R5cGUoNDUuMDk0NzM0LCAzNy41NjU5MjIpKTsKICAgIGJnOjphcHBlbmQobGluZTEsIHBvaW50X3R5cGUoNDUuMDk0Njk2LCAzNy41NjYxNTMpKTsKCiAgICAvLyDQmNC90LjRhtC40LDQu9C40LfQsNGG0LjRjyDQstGC0L7RgNC+0Lkg0LvQuNC90LjQuAogICAgLy8g0J/RgNC40LzQtdGAINC00YDRg9Cz0L7QuSDQu9C40L3QuNC4LCDQvNC+0LbQvdC+INC30LDQvNC10L3QuNGC0Ywg0L3QsCDRgdCy0L7RjgogICAgYmc6OmFwcGVuZChsaW5lMiwgcG9pbnRfdHlwZSg0NS4wOTQ5NzIsIDM3LjU2NTA3NikpOwogICAgYmc6OmFwcGVuZChsaW5lMiwgcG9pbnRfdHlwZSg0NS4xOTQ5MzQsIDM3LjU2NTMwNykpOwogICAgLy8g0JLRi9GH0LjRgdC70LXQvdC40LUg0YPQs9C70LAg0LzQtdC20LTRgyDQu9C40L3QuNGP0LzQuAogICAgZG91YmxlIGFuZ2xlID0gY2FsY3VsYXRlX2FuZ2xlKGxpbmUxLCBsaW5lMik7CiAgICBzdGQ6OmNvdXQgPDwgItCj0LPQvtC7INC80LXQttC00YMg0LvQuNC90LjRj9C80Lg6ICIgPDwgYW5nbGUgPDwgIiDQs9GA0LDQtNGD0YHQvtCyIiA8PCBzdGQ6OmVuZGw7CgogICAgLy8g0J/RgNC+0LLQtdGA0LrQsCDQutC+0LvQuNC90LXQsNGA0L3QvtGB0YLQuAogICAgaWYgKGFyZV9jb2xsaW5lYXIobGluZTEsIGxpbmUyKSkgewogICAgICAgIHN0ZDo6Y291dCA8PCAi0JvQuNC90LjQuCDQutC+0LvQuNC90LXQsNGA0L3Riy4iIDw8IHN0ZDo6ZW5kbDsKICAgIH0gZWxzZSB7CiAgICAgICAgc3RkOjpjb3V0IDw8ICLQm9C40L3QuNC4INC90LUg0LrQvtC70LjQvdC10LDRgNC90YsuIiA8PCBzdGQ6OmVuZGw7CiAgICB9CgogICAgcmV0dXJuIDA7Cn0K