开发者

Cannot rotate Koch snowflake

开发者 https://www.devze.com 2023-04-06 20:05 出处:网络
EDIT: I wasn\'t sure if this should be a new question or not so I am just updating this one for now. The snowflake is now being generated properly, unless I change the original coordinates. For exampl

EDIT: I wasn't sure if this should be a new question or not so I am just updating this one for now. The snowflake is now being generated properly, unless I change the original coordinates. For example, if my original triangle is like picture 1, the result after 5 iterations is picture 2:

Cannot rotate Koch snowflake

Cannot rotate Koch snowflake

However, if my original triangle is anything different, for example picture 3, the results are skewed:

Cannot rotate Koch snowflake

Cannot rotate Koch snowflake

I again think the problem is with my normals but I am really lost. I have tried for hours to figure out the correct formulas to do this but I am not really making any progress. Since it seems that a lot of times the problem is with the new triangles being inverted, I suspect that atan is giving me a negative value when it should be giving me a positive value. Is there a mathematical way I can get around this? Thank you so much for your help!

My code (minus the openGL portions because I don't think they are the problem) is:

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");
}

I am currently trying to implement the Koch curve in c++. I have it almost working correctly. There are basically three different cases that I am addressing: line segment that I need to break into four segments is horizontal, vertical, or other.

The problem is that when the program calculates what the new vertices are for the line segments, there are two possibilities: the triangle can face "up" or the triangle can face "down". I tried to take this into account by normalizing the vectors, but I either did this incorrectly or there is something else slightly off. The pictures below are two examples; both have 3 iterations of the the fractal.

The code for splitting a non-horizontal and non-vertical line segment is below, since the tri开发者_如何学Goangles seem like the face the right way for vertical/horizontal segments:

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 and b are the vectors of the segment. The normalX and normalY are:

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

Any ideas of what I can do to fix this problem?


Your problem is probably atan(theta). It's domain is too small to be used for generic angle determination. You should instead use 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));

(I've not tested this code, so there could be some sign errors.)

Read more: Atan2 (Wikipedia)


EDIT:

My guess is that you are giving the coordinates in the wrong order. If you think of one segment from the perspective of the start point facing the end point, the curve will always extrude to your right. If you give the coordinates in the opposite order, the curve will be mirrored.


Provide all your initial vertices in counter-clockwise order and it should work the way you expect.

0

精彩评论

暂无评论...
验证码 换一张
取 消