2011-09-21 16 views
7

EDIT: Tôi không chắc liệu đây có phải là một câu hỏi mới hay không, vì vậy tôi chỉ cập nhật cái này ngay bây giờ. Bông tuyết hiện đang được tạo đúng cách, trừ khi tôi thay đổi toạ độ ban đầu. Ví dụ, nếu tam giác ban đầu của tôi cũng giống như hình ảnh 1, kết quả sau 5 lần lặp là hình ảnh 2:Không thể xoay bông tuyết Koch

enter image description here enter image description here

Tuy nhiên, nếu tam giác ban đầu của tôi là bất cứ điều gì khác nhau, ví dụ như hình ảnh 3, kết quả là lệch:

enter image description here enter image description here

tôi lại nghĩ rằng vấn đề là với normals của tôi nhưng tôi thực sự bị mất. Tôi đã cố gắng hàng giờ để tìm ra các công thức chính xác để làm điều này nhưng tôi không thực sự tiến bộ. Vì có vẻ như rất nhiều vấn đề là với các hình tam giác mới bị đảo ngược, tôi nghi ngờ rằng atan đang cho tôi một giá trị tiêu cực khi nó cho tôi một giá trị tích cực. Có cách nào toán học tôi có thể giải quyết vấn đề này không? Cảm ơn rất nhiều vì sự giúp đỡ của bạn!

Mã của tôi (trừ đi phần OpenGL vì tôi không nghĩ rằng họ là những vấn đề) là:

const int NumTimesToSubdivide = 5; 
const int NumSegments = 3072; // 3x4^n lines generated {3, 12, 48, 192, 768, 3072..} 
const int NumVertices = NumSegments * 2; // 2 vertices for each segment 

vec2 arrayA[NumVertices]; 
vec2 arrayB[NumVertices]; 

//---------------------------------------------------------------------------- 
void koch(const vec2 &a, const vec2 &b, vec2 * verts) {   

/* Calculate new segments. 
*   v1  
*   /\ 
*  /\ 
*  / \ 
* a----/  \----b 
*  v0  v2 
*/ 
vec2 v0; 
vec2 v1; 
vec2 v2; 

GLfloat distance(sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y,2))); 
GLfloat deltaX = abs(b.x - a.x); 
GLfloat deltaY = abs(b.y - a.y); 
GLfloat normalX((b.x - a.x)/deltaX); 
GLfloat normalY((b.y - a.y)/deltaY); 
GLfloat theta = atan2(b.y - a.y, b.x - a.x) - M_PI/3.0; 
cout << " theta = " << theta << endl; 

/************************* 
* Find trisection points 
*************************/ 
// horizontal line _____________ 
if(a.y == b.y) { 
    vec2 temp0(a.x + (deltaX * normalX/3) , a.y); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3) , a.y); 
    vec2 temp1((a.x + b.x)/2, a.y + distance * sin(theta)/3); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

//     | 
// vertical line | 
//     | 
else if(a.x == b.x){ 
    vec2 temp0(a.x , (a.y + (deltaY * normalY/3))); 
    vec2 temp2(a.x , (a.y + (deltaY * normalY * 2/3))); 
    vec2 temp1(a.x + distance * cos(theta)/3 , (a.y + b.y)/2); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

// slope != 0 && slope != 1 
else { 
    vec2 temp0(a.x + (deltaX * normalX/3), a.y + (deltaY * normalY/3)); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3), a.y + (deltaY * normalY * 2/3)); 
    // Andrew is the greatest! 
    vec2 temp1(temp0.x + distance * cos(theta)/3, 
       temp0.y + distance * sin(theta)/3);   
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

verts[0] = a; 
verts[1] = v0; 
verts[2] = v0; 
verts[3] = v1; 
verts[4] = v1; 
verts[5] = v2; 
verts[6] = v2; 
verts[7] = b; 

} 

//---------------------------------------------------------------------------- 

void divide_line(const vec2& a, const vec2& b, const vec2& c, int n) 
{ 

// arrayA = {a, b, b, c, c, a} i.e., the sides of the initial triangle 
arrayA[0] = a; 
arrayA[1] = b; 
arrayA[2] = b; 
arrayA[3] = c; 
arrayA[4] = c; 
arrayA[5] = a; 

// If at least one iteration: 
if(n > 0) { 
    // The current iteration, starting with 0 
    int currentIteration = 1; 
    // Do for every iteration from 0 - n: 
    while (currentIteration <= n) { 
     int i; 
     int j = 0; 
     int size = 3 * 2 * (pow(4,currentIteration-1)); 
     // Call koch() for each pair of vertices in arrayA 
     for(i = 0; i < size; i = i+2) { 
      vec2 verts[8]; 
      koch(arrayA[i], arrayA[i+1], verts); 
      // Store each vertex in arrayB 
      int k; 
      for(k = 0; k <= 7; k++) 
       arrayB[j++] = verts[k]; 
     } 
     // Copy arrayB to arrayA for next iteration. 
     size = 3 * 2 * pow(4, currentIteration); 
     for(i = 0; i < NumVertices; i++) { 
      arrayA[i] = arrayB[i]; 
     } 
     // Increase count of currentIteration. 
     currentIteration++; 
    } 
} else 
    printf("The number of iterations must be >= 0.\n"); 
} 

Tôi hiện đang cố gắng để thực hiện các đường cong Koch trong C++. Tôi có nó gần như hoạt động chính xác. Về cơ bản có ba trường hợp khác nhau mà tôi đang giải quyết: phân đoạn đường mà tôi cần phải chia thành bốn phân đoạn là ngang, dọc hoặc khác.

Vấn đề là khi chương trình tính toán các đỉnh mới cho các đoạn đường, có hai khả năng: tam giác có thể đối mặt với "lên" hoặc hình tam giác có thể úp xuống ". Tôi đã cố gắng để đưa điều này vào tài khoản bằng cách bình thường hóa các vectơ, nhưng tôi đã làm điều này không chính xác hoặc có cái gì đó hơi khác đi. Những hình ảnh dưới đây là hai ví dụ; cả hai đều có 3 lần lặp lại của fractal.

Mã để tách một đoạn thẳng phi ngang và phi thẳng đứng là dưới đây, kể từ khi hình tam giác có vẻ như khuôn mặt một cách đúng đắn cho các phân đoạn ngang dọc /:

if(a.x == b.x) { 
    ... 
} 
else if (a.y == b.y) { 
    ... 
} 
// slope != 0 && slope != 1 
else { 
    GLfloat deltaX = abs(b.x - a.x); 
    GLfloat deltaY = abs(b.y - a.y); 
    vec2 temp0(a.x + (deltaX * normalX/3), a.y + (deltaY * normalY/3)); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3), a.y + (deltaY * normalY * 2/3)); 
    GLfloat dist(sqrt(pow(temp2.x - temp0.x, 2) + pow(temp2.y - temp0.y,2))); 
    GLfloat theta = (a.x - b.x)/ (b.y - a.y); 
    vec2 temp1((a.x + b.x)/2 + dist * cos(atan(theta)) , 
       (a.y + b.y)/2 + dist * sin(atan(theta))); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

a và b là các vectơ của phân đoạn. Bình thườngX và bình thường là:

GLfloat normalX((b.x - a.x)/(abs(b.x - a.x))); 
GLfloat normalY((b.y - a.y)/(abs(b.y - a.y))); 

Bất kỳ ý tưởng nào về những gì tôi có thể làm để khắc phục vấn đề này?

+0

'a' và 'b' ở đây là gì? Sẽ dễ dàng hơn nếu bạn đăng thêm mã. – sinelaw

+0

GLfloat normalX ((b.x - a.x)/deltaX); GLfloat normalY ((b.y - a.y)/deltaY); nên là GLfloat normalX ((b.x - a.x)/distance); GLfloat normalY ((b.y - a.y)/distance); - giá trị của bạn sẽ là tất cả +1 hoặc -1 –

Trả lời

11

Sự cố của bạn có thể là atan(theta). Miền của nó quá nhỏ để sử dụng cho việc xác định góc chung. thay vào đó bạn nên sử dụng atan2(y,x):

GLfloat theta = atan2(b.y - a.y, a.x - b.x); 
vec2 temp1((a.x + b.x)/2 + dist * cos(theta) , 
      (a.y + b.y)/2 + dist * sin(theta)); 

(. Tôi đã không kiểm tra mã này, do đó có thể có một số lỗi dấu)

Read more: Atan2 (Wikipedia)


EDIT:

Đoán của tôi là bạn đang đưa ra tọa độ theo thứ tự sai.Nếu bạn nghĩ về một phân đoạn từ quan điểm của điểm bắt đầu đối diện với điểm kết thúc, đường cong sẽ luôn luôn mở rộng sang bên phải của bạn. Nếu bạn đặt tọa độ theo thứ tự ngược lại, đường cong sẽ được nhân đôi.

+0

Bạn đã đúng! Vấn đề là với tan và bây giờ nó đang hoạt động hoàn hảo. Cảm ơn bạn rất nhiều! –

+0

Câu trả lời này đã khắc phục được vấn đề ban đầu của tôi, nhưng một vấn đề mới đã nảy sinh (như chi tiết trong chỉnh sửa của tôi ở trên): ( –

+0

cảm ơn bạn! Bạn đã đúng. Thật buồn cười như thế nào một điều đơn giản có thể gây ra rất nhiều đau khổ :) –

1

Cung cấp tất cả các đỉnh ban đầu của bạn theo thứ tự ngược chiều kim đồng hồ và nó sẽ hoạt động theo cách bạn mong đợi.

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