Cascading Curves Rotated By Angle

Hello,

I am trying to create a cascade of expanding curves that go in any direction based on an input angle. At the moment I have it working using ofDrawCurve, but only along the y-axis. The function takes in an x and y coordinate (xpos, ypos) and builds the curve from that point.

I have been able to rotate the x & y endpoints of the curve, but have been unable to figure out how to rotate the control points, px & py.

The test output looks like this. Essentially I’d like to have these curves shoot off in any arbitrary direction. I have a feeling there’s a simpler or easier way to do this, but I’m still new to oF so any pointers would be appreciated!

void ofApp::drawWaves (float xpos, float ypos, float pitch, float angle) {
    
    // Define starting wave width
    float curveWidth = ofGetWindowWidth() / widthDivisor;
    
    // Iterator value to keep track of where the loop is
    int curveNum = 0;
    
    // For loop that iterates through y values to create cascading curves
    // Goes through the height of the window
    for (int y = 0; y < ofGetWindowHeight(); y += pitch) {
        // Increment iterator value.
        curveNum += 1;
        
        // Define beginning and end coordinates of curve, Test points only along y-axis
        //float x1 = xpos - curveWidth;
        //float y1 = ypos + y;
        //float x2 = xpos + curveWidth;
        //float y2 = ypos + y;
        
        // Control points to determine the depth of the curve, Test points only along y-axis
        //float px1 = x1;
        //float py1 = ypos + y - curveDepth;
        //float px2 = x2;
        //float py2 = ypos + y - curveDepth;
        
        // Define beginning and end coordinates of curve
        float x1 = xpos - cos(angle)*curveWidth;
        float y1 = ypos - sin(angle)*curveWidth;
        float x2 = xpos + cos(angle)*curveWidth;
        float y2 = ypos + sin(angle)*curveWidth;
        
        // Control points to determine the depth of the curve
        float px1 = x1 - 2*curveDepth*sin(angle/2);
        float py1 = y1 + cos(angle)*curveDepth;
        float px2 = x2 - 2*curveDepth*sin(angle/2);
        float py2 = y2 + cos(angle)*curveDepth;
        
        // Define color. Cascade through RGB.
        if (curveNum % 3  == 0) {
            ofSetColor(0, 0, 255);
        }
        else if (curveNum % 3 == 1) {
            ofSetColor(255, 0, 0);
        }
        else {
            ofSetColor(0, 255, 0);
        }
        
        // Draw curve without fill
        ofNoFill();
        ofSetCurveResolution(curveResolution);
        ofDrawCurve(px1, py1, x1, y1, x2, y2, px2, py2);
        
        // Increase the width of the curve for the next iteration
        curveWidth += widthIncrementer;;
    }
}

Thank you for any help! :slight_smile:

Hey I could not get your code to run and im not entirely sure what you mean by rotating the control points. I’d suggest using vectors and get things working with lines and then curves should be an extension. Something like this works for me.

void ofApp::drawLines (float xpos, float ypos, float pitch, float angle)
{
    float circRad = 5.0;
    float radius = 30.0;
    glm::vec2 p1, p2, rotDir, pr;
    
    glm::vec2 origin(xpos, ypos);
    
    rotDir = glm::vec2(cos(angle), sin(angle));

    ofSetColor(255);
    ofDrawCircle(origin, circRad);
    
    float radialOffset = radius;
    for (int i = 0; i < 5; i++) {
        
        //point from the origin in the direction of angle
        pr = origin + radialOffset * rotDir;
        ofSetColor(255, 0, 0);
        ofDrawCircle(pr, circRad);
        
        //get the vector perpendicular to our rotation direction
        glm::vec2 pv = glm::vec2(rotDir.y, -rotDir.x);
        
        ofSetColor(255);
    
        //get 2 points either size of pr
        float halfWidth = radialOffset * 0.5;
        p1 = pr - halfWidth * pv;
        p2 = pr + halfWidth * pv;
        ofDrawLine(p1, p2);
        
        radialOffset *= 1.61803;
    }
}

It basically draws a series of points (the pv variable) further and further away from some origin (xpos, ypos), using radialOffset as a distance from the origin.

Then for each point, it finds a normal perpendicular to the rotation angle and gets 2 points either side of pv to draw a line. Those points would be the x1/y1 x2/y2 endpoints, and for the control points I think you could scale them out as you like.

Hope this helps

image

1 Like

This is very helpful! Thank you!

1 Like

Yeah cool glad it helped.

As a bit more info what is going on math wise, the example is using points in polar coordinates where their location in a 2d plane is defined by a radius and angle, vs cartesian coords which uses the x/y.

You convert from polar to cartesian using

x = radius * cos(angle)
y = radius * sin(angle)

Which lets you use the x/y to draw them.

If you want to explore rotation and other matrix based transforms a bit more this is a good resource http://immersivemath.com/ila/ch06_matrices/ch06.html#auto_label_435

1 Like