Các tuyến đường trên một bề mặt hình cầu - Tìm trắc địa?


8

Tôi đang làm việc với một số người bạn trên một trò chơi dựa trên trình duyệt nơi mọi người có thể di chuyển trên bản đồ 2D. Đã gần 7 năm và mọi người vẫn chơi trò chơi này, vì vậy chúng tôi đang nghĩ cách để cung cấp cho họ một cái gì đó mới. Kể từ đó, bản đồ trò chơi là một mặt phẳng giới hạn và mọi người có thể di chuyển từ (0, 0) đến (MAX_X, MAX_Y) theo gia số X và Y được lượng tử hóa (chỉ cần tưởng tượng nó như một bàn cờ lớn).
Chúng tôi tin rằng đã đến lúc cung cấp cho nó một chiều không gian khác, vì vậy chỉ một vài tuần trước, chúng tôi bắt đầu tự hỏi làm thế nào trò chơi có thể nhìn với các ánh xạ khác:

  • Máy bay không giới hạn với chuyển động liên tục: đây có thể là một bước tiến nhưng tôi vẫn không bị thuyết phục.
  • Thế giới hình xuyến (chuyển động liên tục hoặc lượng tử hóa): chân thành tôi đã làm việc với hình xuyến trước đây nhưng lần này tôi muốn một cái gì đó nhiều hơn ...
  • Thế giới hình cầu với sự chuyển động liên tục: điều này sẽ rất tuyệt!

Những gì chúng tôi muốn Trình duyệt người dùng được cung cấp một danh sách các tọa độ như (vĩ độ, kinh độ) cho từng đối tượng trên bản đồ bề mặt hình cầu; Các trình duyệt sau đó phải hiển thị điều này trong màn hình của người dùng hiển thị chúng bên trong một thành phần web (có thể là canvas? đây không phải là vấn đề). Khi mọi người nhấp vào mặt phẳng, chúng tôi chuyển đổi (mouseX, mouseY) thành (lat, lng) và gửi nó đến máy chủ để tính toán tuyến đường giữa vị trí của người dùng hiện tại đến điểm được nhấp.

Những gì chúng tôi có Chúng tôi đã bắt đầu viết một thư viện Java với nhiều toán học hữu ích để làm việc với Ma trận Xoay, Đệ tứ, Euler Angles, Dịch thuật, v.v. Chúng tôi kết hợp tất cả lại và tạo ra một chương trình tạo các điểm hình cầu, hiển thị chúng và hiển thị cho người dùng bên trong một JPanel. Chúng tôi đã quản lý để bắt các nhấp chuột và dịch chúng sang các hợp đồng hình cầu và cung cấp một số tính năng hữu ích khác như xoay chế độ xem, tỷ lệ, dịch, v.v. Những gì chúng tôi có bây giờ giống như một công cụ nhỏ (thực sự rất nhỏ) mô phỏng tương tác giữa máy khách và máy chủ. Phía máy khách hiển thị các điểm trên màn hình và bắt các tương tác khác, phía máy chủ hiển thị chế độ xem và thực hiện các phép tính khác như nội suy tuyến đường giữa vị trí hiện tại và điểm được nhấp.

Vấn đề ở đâu? Rõ ràng chúng ta muốn có con đường ngắn nhất để nội suy giữa hai điểm tuyến . Chúng tôi sử dụng tứ phương để nội suy giữa hai điểm trên bề mặt của hình cầu và điều này dường như hoạt động tốt cho đến khi tôi nhận thấy rằng chúng tôi không đi được con đường ngắn nhất trên bề mặt hình cầu:

Vòng tròn sai

Chúng tôi mặc dù vấn đề là tuyến đường được tính bằng tổng hai lần quay quanh trục X và Y. Vì vậy, chúng tôi đã thay đổi cách tính toán bậc bốn đích: Chúng ta có góc thứ ba (thứ nhất là vĩ độ, thứ hai là kinh độ, thứ ba là xoay quanh vectơ chỉ về vị trí hiện tại của chúng ta) mà chúng ta gọi là định hướng. Bây giờ chúng ta có góc "định hướng", chúng ta xoay trục Z và sau đó sử dụng vectơ kết quả làm trục xoay cho phần tư đích (bạn có thể thấy trục xoay có màu xám):

Tuyến đường chính xác bắt đầu từ 0, 0

Những gì chúng ta có là tuyến đường chính xác (bạn có thể thấy nó nằm trên một vòng tròn lớn), nhưng chúng ta chỉ có CHỈ này nếu điểm tuyến đường bắt đầu ở vĩ độ, kinh độ (0, 0) có nghĩa là vectơ bắt đầu là (sphereRadius, 0 , 0). Với phiên bản trước (hình 1), chúng tôi không có kết quả tốt ngay cả khi điểm bắt đầu là 0, 0, vì vậy tôi nghĩ rằng chúng tôi đang hướng tới một giải pháp, nhưng quy trình chúng tôi thực hiện để có lộ trình này hơi "lạ" " có lẽ?

Trong hình ảnh sau, bạn có được cái nhìn về vấn đề chúng ta gặp phải khi điểm bắt đầu không phải là (0, 0), vì bạn có thể thấy điểm bắt đầu không phải là vectơ (sphereRadius, 0, 0) và như bạn có thể thấy điểm đích (được vẽ chính xác!) không nằm trên tuyến đường.

Tuyến đường không chính xác!

Điểm màu đỏ tươi (điểm nằm trên tuyến đường) là điểm kết thúc của tuyến đường xoay quanh tâm của hình cầu (-startLatitude, 0, -startLongitude). Điều này có nghĩa là nếu tôi tính toán một ma trận xoay và áp dụng nó cho mọi điểm trên tuyến đường thì có thể tôi sẽ có được tuyến đường thực sự, nhưng tôi bắt đầu nghĩ rằng có một cách tốt hơn để làm điều này.

Có lẽ tôi nên cố gắng đưa máy bay qua tâm của quả cầu và các điểm tuyến đường, giao nó với quả cầu và lấy trắc địa? Nhưng bằng cách nào?

Xin lỗi vì cách quá dài dòng và có thể vì tiếng Anh không chính xác nhưng điều này đang thổi vào tâm trí của tôi!

EDIT: Mã dưới đây hoạt động tốt! Cảm ơn tất cả mọi người:

public void setRouteStart(double srcLat, double srcLng, double destLat, destLng) {
    //all angles are in radians
    u = Choords.sphericalToNormalized3D(srcLat, srcLng);
    v = Choords.sphericalToNormalized3D(destLat, destLng);
    double cos = u.dotProduct(v);
    angle = Math.acos(cos);
    if (Math.abs(cos) >= 0.999999) {
        u = new V3D(Math.cos(srcLat), -Math.sin(srcLng), 0);
    } else {
        v.subtract(u.scale(cos));
        v.normalize();
    }
}

public static V3D sphericalToNormalized3D( double radLat, double radLng) {
    //angles in radians
    V3D p = new V3D();
    double cosLat = Math.cos(radLat);
    p.x = cosLat*Math.cos(radLng);
    p.y = cosLat*Math.sin(radLng);
    p.z = Math.sin(radLat);
    return p;
}

public void setRouteDest(double lat, double lng) {
    EulerAngles tmp = new AngoliEulero(
       Math.toRadians(lat), 0, -Math.toRadians(lng));
    qtEnd.setInertialToObject(tmp);
    //do other stuff like drawing dest point...
}

public V3D interpolate(double totalTime, double t) {
    double _t = angle * t/totalTime;
    double cosA = Math.cos(_t);
    double sinA = Math.sin(_t);
    V3D pR = u.scale(cosA);
    pR.sum(
       v.scale(sinA)
    );
    return pR;
}

1
Vui lòng hiển thị mã slerp / nội suy bậc bốn của bạn.
Maik

1
Một lưu ý phụ: ngay cả những cuốn sách cũng có thể gây ra những lỗi không quan sát được, nhưng những lỗi nghiêm trọng. Trước khi sao chép bất cứ điều gì, hãy chắc chắn rằng bạn tự hiểu nó .. chỉ khi đó bạn mới có thể coi đó là hợp lệ (tốt, trừ khi bạn tự hiểu nhầm - nhưng điều này ít có khả năng hơn).
teodron

@MaikSemder đã thêm chức năng trong đó RotationMatrix được biên dịch bắt đầu từ lớp
Quancyion

Có thể vấn đề nằm bên trong setRouteDest (double lat, double lng) và setRouteStart (double lat, double lng). Tôi nghĩ rằng tôi đang thiếu một góc khi tôi tạo đối tượng EulerAngles như thế này: EulerAngles tmp = new EulerAngles (Math.toRadians (lat), ???, -Math.toRadians (lng))
CaNNaDaRk

Tôi không thấy nơi bạn sử dụng "RotationMatrix" để tạo điểm xoay "p" được trả về từ "nội suy". Bạn chỉ cần đặt "RotationMatrix" từ bộ
tứ được

Câu trả lời:


5

Vấn đề của bạn hoàn toàn là hai chiều, trong mặt phẳng được hình thành bởi tâm hình cầu và các điểm nguồn và đích của bạn. Sử dụng tứ phương thực sự làm cho mọi thứ trở nên phức tạp hơn, bởi vì ngoài một vị trí trên quả cầu 3D, một bộ tứ mã hóa một định hướng.

Bạn có thể đã có một cái gì đó để nội suy trên một vòng tròn, nhưng chỉ trong trường hợp, đây là một số mã nên hoạt động.

V3D u, v;
double angle;

public V3D geographicTo3D(double lat, double long)
{
    return V3D(sin(Math.toRadians(long)) * cos(Math.toRadians(lat)),
               cos(Math.toRadians(long)) * cos(Math.toRadians(lat)),
               sin(Math.toRadians(lat)));
}

public V3D setSourceAndDest(double srcLat, double srcLong,
                            double dstLat, double dstLong)
{
    u = geographicTo3D(srcLat, srcLong);
    V3D tmp = geographicTo3D(dstLat, dstLong);
    angle = acos(dot(u, tmp));
    /* If there are an infinite number of routes, choose
     * one arbitrarily. */
    if (abs(dot(u, tmp)) >= 0.999999)
        v = V3D(cos(srcLong), -sin(srcLong), 0);
    else
        v = normalize(tmp - dot(u, tmp) * u);
}

public V3D interpolate(double totalTime, double t)
{
    double a = t / totalTime * angle;
    return cos(a) * u + sin(a) * v;
}

Đúng! Đó là những gì tôi đang tìm kiếm, đây là vấn đề thực sự của tôi, tôi phải làm việc trên máy bay cắt ngang C, đích và nguồn! Vấn đề duy nhất là tôi vẫn không thể làm cho nó hoạt động ... Tôi sẽ dán mã và kết quả tôi nhận được từ mã của bạn!
CaNNaDaRk

chỉnh sửa câu hỏi. Có một vấn đề ... có lẽ tôi đã dịch sai mã ???
CaNNaDaRk

@CaNNaDaRk Tôi không thấy điều gì có thể sai. Việc sử dụng chuẩn hóa (), trừ (), scale (), v.v ... có đúng với các tác dụng phụ không? Và có tđạt totalTime? Ngoài ra nếu bạn muốn có được vòng tròn đầy đủ, hãy tạo tgiá trị tối đa 2 * pi / angle * totalTimethay vì chỉ totalTime.
sam hocevar

Hoàn hảo! Ở đó tôi đã thêm một lỗi ngu ngốc vào hàm chuẩn hóa và do đó có độ lớn sai trong vectơ "v". Bây giờ mọi thứ hoạt động tốt! Cảm ơn một lần nữa;)
CaNNaDaRk

3

Hãy chắc chắn rằng cả hai bậc bốn nằm trên cùng một bán cầu trên siêu cầu. Nếu sản phẩm chấm của họ nhỏ hơn 0, thì không. Trong trường hợp đó, phủ định một trong số chúng (phủ định từng số của nó), vì vậy chúng nằm trên cùng một bán cầu và sẽ cho bạn con đường ngắn nhất. Mã giả:

quaternion from, to;

// is "from" and "to" on the same hemisphere=
if(dot(from, to) < 0.0)
{
    // put "from" to the other hemisphere, so its on the same as "to"
    from.x = -from.x;
    from.y = -from.y;
    from.z = -from.z;
    from.w = -from.w;
}

// now simply slerp them

Câu trả lời của tôi ở đây giải thích chi tiết những gì phủ định từng thuật ngữ của tứ phương làm gì và tại sao nó vẫn cùng một định hướng, chỉ ở phía bên kia của siêu cầu.


EDIT chức năng nội suy sẽ trông như thế này:

public V3D interpolate(double totalTime, double t) {
    double _t = t/totalTime;    
    Quaternion tmp;
    if(dot(qtStart, qtEnd) < 0.0)
    {
        tmp.x = -qtEnd.x;
        tmp.y = -qtEnd.y;
        tmp.z = -qtEnd.z;
        tmp.w = -qtEnd.w;
    }
    else
    {
        tmp = qtEnd;
    }
    Quaternion q = Quaternion.Slerp(qtStart, tmp, _t);
    RotationMatrix.inertialQuatToIObject(q);
    V3D p = matInt.inertialToObject(V3D.Xaxis.scale(sphereRadius));
    //other stuff, like drawing point ...
    return p;
}

Tôi đã thử mã của bạn nhưng tôi nhận được kết quả tương tự. Trong chế độ gỡ lỗi, tôi xem sản phẩm chấm và tôi chắc chắn rằng hai phần tử nằm trên cùng một bán cầu trên siêu cầu. Xin lỗi, có lẽ câu hỏi của tôi không đủ rõ ràng?
CaNNaDaRk

Ý bạn là gì "bạn chắc chắn họ ở cùng một bán cầu"? nếu chấm> = 0 thì chúng, nếu không thì không.
Maik

Nó không phải là về bán cầu của hình cầu bình thường của bạn, mà là về bán cầu trong không gian siêu âm, không gian 4D của tứ phương. Hãy dành thời gian để đọc liên kết, thật khó để giải thích trong một hộp bình luận.
Maik

Đó là những gì tôi đang nói, tôi đặt mã của bạn và tính toán dấu chấm. Ngay cả khi nó> = 0 (vì vậy tôi chắc chắn rằng chúng nằm trên cùng một bán cầu), vấn đề luôn giống nhau: tuyến đường tôi đi không nằm trên một vòng tròn lớn. Tôi nghĩ vấn đề là ở một nơi khác ..? Có lẽ tôi nên thêm một số mã cho câu hỏi ...? Chỉnh sửa: tôi đọc liên kết của bạn, tôi vẫn không nghĩ rằng vấn đề là ở đó. Tôi cũng đã thử mã bạn đưa cho tôi nhưng tôi vẫn nhận được một tuyến đường trên một vòng tròn nhỏ.
CaNNaDaRk

Vui lòng hiển thị mã nội suy của bạn
Maik Semder

0

Vì bạn muốn V3Dquay trở lại từ bộ nội suy của mình, cách tiếp cận đơn giản nhất là bỏ qua hoàn toàn các quan điểm. Chuyển đổi điểm bắt đầu và điểm kết thúc thành V3Dvà trượt giữa chúng.

Nếu bạn khăng khăng sử dụng tứ phương thì tứ phương đại diện cho phép quay từ Pđến Qcó hướng P x Qwcủa P . Q.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.