2010-04-17 21 views
20

Có một cách đặc biệt của ánh xạ một khối lập phương để một quả cầu được mô tả ở đây: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.htmlMapping Một Sphere Để A Cube

Nó không phải là cơ bản "bình thường hóa quan điểm và bạn đã hoàn tất" cách tiếp cận của bạn và đưa ra một nhiều bản đồ có khoảng cách đều hơn.

Tôi đã cố gắng thực hiện phép đảo ngược của ánh xạ đi từ hình cầu coords thành coords khối lập phương và không thể đưa ra phương trình hoạt động. Đó là một hệ phương trình khá phức tạp với rất nhiều rễ vuông.

Bất kỳ thiên tài toán học nào cũng muốn giải quyết vấn đề này?

Dưới đây là các phương trình trong C++ mã:

sx = x * sqrtf(1.0f - y * y * 0.5f - z * z * 0.5f + y * y * z * z/3.0f); 

sy = y * sqrtf(1.0f - z * z * 0.5f - x * x * 0.5f + z * z * x * x/3.0f); 

sz = z * sqrtf(1.0f - x * x * 0.5f - y * y * 0.5f + x * x * y * y/3.0f); 

sx, sy, sz là coords cầu và x, y, z là các coords khối lập phương.

+1

Có thể là một câu hỏi cho MathOverflow (http://mathoverflow.net/)? –

+9

@James: Có thể là không. Với cộng đồng, tôi đặt cược họ sẽ tìm thấy điều này cả tầm thường lẫn chủ đề. –

+0

Chỉ trong trường hợp, tôi cũng đăng ở đó. Điều này thực sự quan trọng đối với chương trình hành tinh của tôi: http://petrocket.blogspot.com Tôi cần nó để tạo bản đồ ánh sáng và phát hiện va chạm cơ bản với địa hình. – petrocket

Trả lời

13

Tôi muốn cung cấp tín dụng gmatt cho điều này bởi vì anh ấy đã thực hiện rất nhiều công việc. Sự khác biệt duy nhất trong câu trả lời của chúng tôi là phương trình cho x.

Để thực hiện ánh xạ ngược từ hình cầu đến khối lập phương đầu tiên, hãy xác định khối lập phương đối diện với các điểm hình cầu.Bước này rất đơn giản - chỉ cần tìm ra thành phần của vector hình cầu với chiều dài lớn nhất như sau:

// map the given unit sphere position to a unit cube position 
void cubizePoint(Vector3& position) { 
    double x,y,z; 
    x = position.x; 
    y = position.y; 
    z = position.z; 

    double fx, fy, fz; 
    fx = fabsf(x); 
    fy = fabsf(y); 
    fz = fabsf(z); 

    if (fy >= fx && fy >= fz) { 
     if (y > 0) { 
      // top face 
      position.y = 1.0; 
     } 
     else { 
      // bottom face 
      position.y = -1.0; 
     } 
    } 
    else if (fx >= fy && fx >= fz) { 
     if (x > 0) { 
      // right face 
      position.x = 1.0; 
     } 
     else { 
      // left face 
      position.x = -1.0; 
     } 
    } 
    else { 
     if (z > 0) { 
      // front face 
      position.z = 1.0; 
     } 
     else { 
      // back face 
      position.z = -1.0; 
     } 
    } 
} 

Đối với mỗi khuôn mặt - mất các thành phần vector khối còn lại ký hiệu là s và t và giải quyết cho họ sử dụng các phương trình, mà là dựa trên các thành phần vector lĩnh vực còn lại ký hiệu là a và b:

s = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)+2 a^2-2 b^2+3)/sqrt(2) 
t = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)-2 a^2+2 b^2+3)/sqrt(2) 

Bạn sẽ thấy rằng căn bậc hai bên trong được sử dụng trong cả hai phương trình như vậy chỉ làm phần việc đó một lần.

Đây là hàm cuối cùng với các phương trình được ném vào và kiểm tra 0.0 và -0.0 và mã để đặt đúng dấu của thành phần khối - nó phải bằng dấu của thành phần hình cầu.

void cubizePoint2(Vector3& position) 
{ 
    double x,y,z; 
    x = position.x; 
    y = position.y; 
    z = position.z; 

    double fx, fy, fz; 
    fx = fabsf(x); 
    fy = fabsf(y); 
    fz = fabsf(z); 

    const double inverseSqrt2 = 0.70710676908493042; 

    if (fy >= fx && fy >= fz) { 
     double a2 = x * x * 2.0; 
     double b2 = z * z * 2.0; 
     double inner = -a2 + b2 -3; 
     double innersqrt = -sqrtf((inner * inner) - 12.0 * a2); 

     if(x == 0.0 || x == -0.0) { 
      position.x = 0.0; 
     } 
     else { 
      position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2; 
     } 

     if(z == 0.0 || z == -0.0) { 
      position.z = 0.0; 
     } 
     else { 
      position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2; 
     } 

     if(position.x > 1.0) position.x = 1.0; 
     if(position.z > 1.0) position.z = 1.0; 

     if(x < 0) position.x = -position.x; 
     if(z < 0) position.z = -position.z; 

     if (y > 0) { 
      // top face 
      position.y = 1.0; 
     } 
     else { 
      // bottom face 
      position.y = -1.0; 
     } 
    } 
    else if (fx >= fy && fx >= fz) { 
     double a2 = y * y * 2.0; 
     double b2 = z * z * 2.0; 
     double inner = -a2 + b2 -3; 
     double innersqrt = -sqrtf((inner * inner) - 12.0 * a2); 

     if(y == 0.0 || y == -0.0) { 
      position.y = 0.0; 
     } 
     else { 
      position.y = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2; 
     } 

     if(z == 0.0 || z == -0.0) { 
      position.z = 0.0; 
     } 
     else { 
      position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2; 
     } 

     if(position.y > 1.0) position.y = 1.0; 
     if(position.z > 1.0) position.z = 1.0; 

     if(y < 0) position.y = -position.y; 
     if(z < 0) position.z = -position.z; 

     if (x > 0) { 
      // right face 
      position.x = 1.0; 
     } 
     else { 
      // left face 
      position.x = -1.0; 
     } 
    } 
    else { 
     double a2 = x * x * 2.0; 
     double b2 = y * y * 2.0; 
     double inner = -a2 + b2 -3; 
     double innersqrt = -sqrtf((inner * inner) - 12.0 * a2); 

     if(x == 0.0 || x == -0.0) { 
      position.x = 0.0; 
     } 
     else { 
      position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2; 
     } 

     if(y == 0.0 || y == -0.0) { 
      position.y = 0.0; 
     } 
     else { 
      position.y = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2; 
     } 

     if(position.x > 1.0) position.x = 1.0; 
     if(position.y > 1.0) position.y = 1.0; 

     if(x < 0) position.x = -position.x; 
     if(y < 0) position.y = -position.y; 

     if (z > 0) { 
      // front face 
      position.z = 1.0; 
     } 
     else { 
      // back face 
      position.z = -1.0; 
     } 
    } 

Vì vậy, giải pháp này không gần như lập bản đồ khối lập phương, nhưng nó hoàn thành công việc!

Bất kỳ đề xuất nào để cải thiện hiệu quả hoặc khả năng đọc của mã ở trên đều được đánh giá cao!

--- chỉnh sửa --- Tôi nên đề cập đến rằng tôi đã thử nghiệm điều này và cho đến nay trong các thử nghiệm của tôi mã xuất hiện chính xác với kết quả chính xác đến ít nhất là số thập phân thứ 7. Và đó là từ khi tôi đang sử dụng phao nổi, nó có lẽ chính xác hơn bây giờ với đôi.

--- chỉnh sửa --- Đây là phiên bản trình đổ bóng phân đoạn được tối ưu hóa bởi Daniel để cho thấy rằng nó không phải là một chức năng đáng sợ lớn như vậy. Daniel sử dụng điều này để lọc lấy mẫu trên bản đồ khối lập phương! Ý tưởng tuyệt vời!

const float isqrt2 = 0.70710676908493042; 

vec3 cubify(const in vec3 s) 
{ 
float xx2 = s.x * s.x * 2.0; 
float yy2 = s.y * s.y * 2.0; 

vec2 v = vec2(xx2 – yy2, yy2 – xx2); 

float ii = v.y – 3.0; 
ii *= ii; 

float isqrt = -sqrt(ii – 12.0 * xx2) + 3.0; 

v = sqrt(v + isqrt); 
v *= isqrt2; 

return sign(s) * vec3(v, 1.0); 
} 

vec3 sphere2cube(const in vec3 sphere) 
{ 
vec3 f = abs(sphere); 

bool a = f.y >= f.x && f.y >= f.z; 
bool b = f.x >= f.z; 

return a ? cubify(sphere.xzy).xzy : b ? cubify(sphere.yzx).zxy : cubify(sphere); 
} 
+0

rất đẹp, rất hay khi thấy bạn làm việc đó :) – ldog

+0

btw, công thức cho 'x' bạn có đoán nó hoạt động và thử không? Bởi vì Wolfram alpha phun ra thứ xấu xí mà tôi đã đăng ở trên. – ldog

+0

thực sự, khi tôi nhập vào hệ thống của 2 phương trình vào wolfram alpha nó đã cho tôi hai giải pháp cho x và y mà tôi đăng. tôi cũng có thể nhận ra rằng công thức nhìn chính xác bởi vì tôi lần đầu tiên giải quyết các phiên bản hai chiều của bản đồ vì vậy tôi đã có một ý tưởng cho những gì cần tìm trong phiên bản 3d. Cảm ơn một lần nữa vì sự giúp đỡ của bạn! Tôi đang sử dụng nó để tạo bản đồ ánh sáng cho hành tinh của tôi và phát hiện va chạm (vids tại đây: http://www.youtube.com/user/petrocket) – petrocket

7

Sau khi một số sắp xếp lại bạn có thể nhận được "thoải mái" hình thức

(1) 1/2 z^2 = (alpha)/(y^2 - x^2) + 1 
(2) 1/2 y^2 = (beta)/(z^2 - x^2) + 1 
(3) 1/2 x^2 = (gamma)/(y^2 - z^2) + 1 

nơi alpha = sx^2-sy^2, beta = sx^2 - sz^2gamma = sz^2 - sy^2. Tự mình xác nhận điều này.

Bây giờ tôi không có động lực và cũng không thời gian nhưng từ lúc này trở đi của nó khá đơn giản để giải quyết:

  1. thay thế (1) vào (2). Sắp xếp lại (2) cho đến khi bạn nhận được một đa thức (root) phương trình có dạng

    (4) a(x) * y^4 + b(x) * y^2 + c(x) = 0 
    

    này có thể được giải quyết bằng cách sử dụng công thức bậc hai cho y^2. Lưu ý rằng a(x),b(x),c(x) là một số chức năng của x. Công thức bậc hai tạo ra 2 rễ cho (4) mà bạn sẽ phải ghi nhớ.

  2. Sử dụng (1), (2), (4) tìm ra một biểu thức cho z^2 chỉ với điều kiện x^2.

  3. Sử dụng (3) viết ra một phương trình gốc đa thức có dạng:

    (5) a * x^4 + b * x^2 + c = 0 
    

    nơi a,b,c không chức năng nhưng hằng số. Giải quyết điều này bằng cách sử dụng công thức bậc hai. Tổng cộng bạn sẽ có 2 * 2 = 4 giải pháp khả thi cho cặp x^2,y^2,z^2 nghĩa là bạn sẽ có 4 * 2 = 8 tổng số giải pháp cho các cặp có thể x,y,z thỏa mãn các phương trình này. Kiểm tra điều kiện trên mỗi x,y,z cặp và (hy vọng) loại bỏ tất cả nhưng một (nếu không một bản đồ nghịch đảo không tồn tại.)

Chúc may mắn.

PS. Nó rất tốt có thể là bản đồ nghịch đảo không tồn tại, suy nghĩ về hình học: hình cầu có diện tích bề mặt 4*pi*r^2 trong khi khối lập phương có diện tích bề mặt 6*d^2=6*(2r)^2=24r^2 do đó bạn có nhiều điểm hơn trên khối lập phương được ánh xạ tới hình cầu. Điều này có nghĩa là ánh xạ nhiều đến một, và bất kỳ ánh xạ nào như vậy không phải là tiêm và do đó không phải là tính từ (tức là ánh xạ không có nghịch đảo.) Xin lỗi nhưng tôi nghĩ bạn không may mắn.

----- chỉnh sửa --------------

nếu bạn làm theo những lời khuyên từ MO, thiết z=1 có nghĩa là bạn đang nhìn vào vuông vững chắc trên mặt phẳng z=1 .

Sử dụng hai phương trình đầu tiên của mình để giải quyết cho x, y, Wolfram Alpha cho kết quả:

x = (sqrt(6) s^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(6) t^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(3/2) sqrt((2 s^2-2 t^2-3)^2-24 t^2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)+3 sqrt(3/2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3))/(6 s)

y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)

nơi trên tôi sử dụng s=sxt=sy, và Tôi sẽ sử dụng u=sz. Sau đó, bạn có thể sử dụng phương trình thứ ba mà bạn có cho u=sz. Điều đó cho phép nói rằng bạn muốn ánh xạ phần trên cùng của hình cầu tới khối lập phương. Sau đó, đối với bất kỳ 0 <= s,t <= 1 nào (trong đó s,t nằm trong khung tọa độ của hình cầu) thì tuple (s,t,u) bản đồ đến (x,y,1) (ở đây x,y nằm trong khung tọa độ khối.) Điều duy nhất còn lại là để tìm hiểu xem u là gì. Bạn có thể tìm ra điều này bằng cách sử dụng s,t để giải quyết cho x,y sau đó sử dụng x,y để giải quyết cho u.

Lưu ý rằng điều này sẽ chỉ ánh xạ phần trên cùng của khối lập phương đến chỉ mặt phẳng trên cùng của khối lập phương z=1. Bạn sẽ phải làm điều này cho tất cả 6 mặt (x=1, y=1, z=0 ... v.v ...). Tôi đề nghị sử dụng ma trận alpha để giải các phương trình mà bạn nhận được cho từng trường hợp phụ, bởi vì chúng sẽ xấu xí hoặc xấu hơn như những phương thức trên.

+1

Tôi không biết liệu ánh xạ ngược tồn tại hay không, nhưng ý tưởng rằng có nhiều điểm hơn trên bề mặt của một quả cầu hơn là trên bề mặt của một khối lập phương là kỳ lạ không chính xác. –

+0

Cảm ơn gmatt đầu vào - khi tôi cố gắng nhập các phương trình vào wolframalpha.com nó đã trả về một số giải pháp (không chính xác nó có vẻ) và câu trả lời của bạn mang lại cho tôi hy vọng! – petrocket

+0

@ HPM: không chắc bạn đã hiểu tôi đúng không, trong phản hồi tôi chưa bao giờ nói mặt cầu có nhiều điểm hơn, tôi nói ngược lại. Tôi nghĩ OP muốn tìm bản đồ từ hình cầu đến khối lập phương. – ldog

1

Dưới đây là một cách bạn có thể nghĩ về nó: cho một điểm P cho trước trong hình cầu, lấy đoạn bắt đầu tại gốc, đi qua P và kết thúc ở bề mặt khối lập phương. Để L là chiều dài của đoạn này. Bây giờ tất cả những gì bạn cần làm là nhân P với L; điều này tương đương với ánh xạ || P || từ khoảng [0, 1] đến khoảng [0, L]. Ánh xạ này phải là một đối một - mỗi điểm trong hình cầu đi đến một điểm duy nhất trong khối lập phương (và điểm trên bề mặt nằm trên bề mặt). Lưu ý rằng đây là giả định một hình cầu và khối lập phương; ý tưởng nên giữ ở nơi khác, bạn sẽ chỉ có một vài yếu tố quy mô liên quan.

Tôi đã xem xét phần cứng (tìm phân đoạn), nhưng đây là một vấn đề tiêu chuẩn về raycasting. Có một số liên kết here giải thích cách tính toán điều này cho một tia tùy ý so với hộp giới hạn trục liên kết; bạn có thể đơn giản hóa mọi thứ kể từ khi tia của bạn bắt đầu từ nguồn gốc và đi đến khối lập phương đơn vị. Nếu bạn cần giúp đơn giản hóa các phương trình, hãy cho tôi biết và tôi sẽ đâm vào nó.

0

Dường như có một giải pháp sạch hơn nhiều nếu bạn không sợ trang điểm và pi, không chắc chắn nếu nó nhanh hơn/so sánh mặc dù.

Chỉ cần các thành phần còn lại sau khi xác định khuôn mặt và làm:

u = asin (x)/half_pi 
v = asin (y)/half_pi 

Đây là một bước nhảy vọt trực quan, nhưng this dường như trở lại nó lên (mặc dù không hoàn toàn giống chủ đề), vì vậy hãy sửa lại cho tôi nếu Tôi đã sai.

Tôi quá lười để đăng minh họa giải thích lý do. : D

Các vấn đề liên quan