Problem 1.
Create a function called smoothPath that takes as input an array of points (Vec2d*), the number of points (int), and a smoothing parameter (float) between 0.0 and 1.0. Apply this function to a stroke that has been drawn. Optionally, try applying it to the stroke as it's being drawn.
// global variables
int numPoints = 0;
Vec2d pointList[1000];
Vec2d lastPoint = Vec2d( 0,0 );
void mouseDownFunc ( int button, int state, int x, int y )
{
mouseX = x;
mouseY = windowH - y;
Vec2d currentPoint = Vec2d( mouseX, mouseY ); // for W5_1
if ( numPoints < 1000 && ( lastPoint-currentPoint ).length() > 10 ) {
pointList[ numPoints ].x = mouseX;
pointList[ numPoints ].y = mouseY;
lastPoint = currentPoint;
numPoints++;
}
}
//an array of points (Vec2d*), the number of points (int),
//and a smoothing parameter (float) between 0.0 and 1.0
void smoothPath ( Vec2d* Points, int numberPoints, float smoothing ) {
smoothing /= 2; // give weight, 0-1-0 <=> 0.25-0.5-0.25
//draw original path
glColor3f ( 0,0,1 );
glPointSize ( 3.0 );
glBegin( GL_POINTS );
for ( int i=0; i<numberPoints; i++ ) {
glVertex2f ( Points[i].x, Points[i].y );
}
glEnd();
glLineWidth ( 2.0 );
glBegin( GL_LINE_STRIP );
for ( int i=0; i<numberPoints; i++ ) {
glVertex2f ( Points[i].x, Points[i].y );
}
glEnd();
// draw smooth path
glColor3f ( 1,0,0 );
glBegin ( GL_LINE_STRIP );
glVertex2f ( Points[0].x, Points[0].y ); // start point
for ( int i=1; i<numberPoints-1; i++ ) {
Vec2d smoothPoint;
// smooth with using before and after points
smoothPoint.x = Points[i-1].x * smoothing/2 + Points[i].x * (1-smoothing) +
Points[i+1].x * smoothing/2;
smoothPoint.y = Points[i-1].y * smoothing/2 + Points[i].y * (1-smoothing) +
Points[i+1].y * smoothing/2;
glVertex2f ( smoothPoint.x, smoothPoint.y );
}
glVertex2f ( Points[numberPoints-1].x, Points[numberPoints-1].y ); // end point
glEnd();
}
void drawW6_1a ( void ) {
// appling to the stroke as it is being drawn
smoothPath ( pointList, numPoints, 0.9 );
}
// stroke version
void smoothPath2 ( Vec2d* Points, int numberPoints, float smoothing ) {
smoothing /= 2; // give weight, 0-1-0 <=> 0.25-0.5-0.25
smoothList[0] = Points[0];
smoothList[numPoints] = smoothList[numPoints];
// draw smooth path
for ( int i=1; i<numberPoints-1; i++ ) {
Vec2d smoothPoint;
// smooth with using before and after points
smoothPoint.x = Points[i-1].x * smoothing/2 + Points[i].x * (1-smoothing) +
Points[i+1].x * smoothing/2;
smoothPoint.y = Points[i-1].y * smoothing/2 + Points[i].y * (1-smoothing) +
Points[i+1].y * smoothing/2;
smoothList[i] = smoothPoint;
}
for( int i=1;i<numPoints-1;i++ ) {
Points[i] = smoothList[i];
}
float strokeWidth = 10.0;
glColor4f ( 0.0,0.3,0.0,0.5 ); // alpha value
glLineWidth ( 5.0 );
glBegin ( GL_TRIANGLE_STRIP );
for ( int i=1; i<numPoints-1; i++ ) {
Vec2d currentPoint = Points[i]; // center point
// calculating the point of stroke
Vec2d A = Points[i-1];
Vec2d B = Points[i+1];
Vec2d V = B - A;
V.normalize();
Vec2d Vp = Vec2d( -V.y, V.x );
Vec2d C = currentPoint + Vp*strokeWidth/2;
Vec2d D = currentPoint - Vp*strokeWidth/2;
glVertex2f( C.x, C.y );
glVertex2f( D.x, D.y );
}
glEnd();
}
: smooth path, small smoothing parameter
: large smoothing parameter
: smoothing while stroking
video of first and second one
video of third one
video of continuous smoothing of strokes
Problem 2.
Create a function called distortPath that distorts a shape by pushing its vertices radially away from 10 pre-set points on the screen, each of which should have a different distortion strength. Apply this function to a circle composed of 360 points. Optionally, allow the circle to be dragged about the screen.
void distortPath( Vec2d* Circle, int numCirclePoints, Vec2d* Points,
int numPoints, float* distortStrength) {
float distortX, distortY;
// for each point, add distort effect of every distort pre-set point
for( int i=0;i<numCirclePoints;i++ ) {
for( int j=0;j<numPoints;j++ ) {
// get distort vector ( direction, length )
Vec2d distortVector = Circle[i] - Points[j];
float distance = distortVector.length();
distortVector.normalize();
distortX += distortVector.x * distortStrength[j] *400 / distance / distance;
distortY += distortVector.y * distortStrength[j] *400 / distance / distance;
}
// change the position of original point
Circle[i].x += distortX;
Circle[i].y += distortY;
// allow the circle to be dragged about the screen.
if ( Circle[i].x > windowW ) Circle[i].x = windowW - 10;
if ( Circle[i].x < 0 ) Circle[i].x = 10;
if ( Circle[i].y > windowH ) Circle[i].y = windowH - 10;
if ( Circle[i].y < 0 ) Circle[i].y = 10;
// initialize the distortion effect
distortX = 0;
distortY = 0;
}
// draw distortion points
glColor3f( 0,0,0 );
glPointSize( 5.0 );
glBegin( GL_POINTS );
for( int i=0;i<numPoints;i++ ) {
glVertex2f( Points[i].x, Points[i].y );
}
glEnd();
// draw distorted circle
glColor3f( 0,0,1 );
glBegin( GL_LINE_LOOP );
for( int i=0;i<numCirclePoints;i++ ) {
glVertex2f( Circle[i].x, Circle[i].y );
}
glEnd();
}
void drawW6_2 ( void ) {
Vec2d Circle[360];
float angle;
float radius = 200;
Vec2d Center = Vec2d( windowW/2, windowH/2 );
glBegin( GL_LINE_LOOP );
for(int i=0;i<360;i++) {
angle = 360.0 / 360 * i; // angle of each point
Circle[i] = Vec2d( radius*cos_deg(angle)+Center.x,
radius*sin_deg(angle)+Center.y );
glVertex2f( Circle[i].x, Circle[i].y );
}
glEnd();
Vec2d Points[10] = { Vec2d(500,200), Vec2d(300,350), Vec2d(150,300),
Vec2d(200,450), Vec2d(300,500), Vec2d(400,400),
Vec2d(500,550), Vec2d(650,350), Vec2d(400,200),
Vec2d(550,150)
};
float Strength[10] = { 100, 50, 200, 300, 200,
20, 150, 10, 400, 100 };
distortPath( Circle, 360, Points, 10, Strength );
}
: distortion path
video of distortion path
Problem 3.
Create a function that detects if a drawn stroke intersects itself. If it has, draw a finished shape that uses the intersection point as its start and end point, and is filled in solid red. Call this function continuously while drawing.
// global variables
Vec2d intersectPoint;
int intersect( int endPoint ) {
// new line
Vec2d P0a( pointList[endPoint-1].x, pointList[endPoint-1].y );
Vec2d P0b( pointList[endPoint].x, pointList[endPoint].y );
Vec2d P1a, P1b;
float X, Y;
// check from first line through third last line
for( int i=0;i<endPoint-2;i++ ) {
P1a = pointList[i];
P1b = pointList[i+1];
// check in intersection is within line segment boundaries
float left0 = min( P0a.x, P0b.x );
float right0 = max( P0a.x, P0b.x );
float left1 = min( P1a.x, P1b.x );
float right1 = max( P1a.x, P1b.x );
float M0 = ( P0b.y - P0a.y ) / ( P0b.x - P0a.x );
float M1 = ( P1b.y - P1a.y ) / ( P1b.x - P1a.x );
if ( M0 != M1 ) {
X = ( P1a.y - P0a.y - P1a.x * M1 + P0a.x * M0 ) / ( M0 - M1 );
Y = P0a.y + ( X - P0a.x) * M0;
// if it does intersect
if ( X > left0 && X < right0 && X > left1 && X < right1 ) {
//numPoints = 0; // for debugging
intersectPoint = Vec2d ( X,Y ); // store the intersection
return i; // return the intersected line
}
}
}
return -1; // return -1 if it does not intersect
}
void drawW6_3 ( void ) {
//draw original path
glColor3f( 0,0,1 );
glPointSize( 3.0 );
glBegin( GL_POINTS );
for( int i=0;i<numPoints;i++ ) {
glVertex2f ( pointList[i].x, pointList[i].y );
}
glEnd();
glColor3f ( 0,0,1 );
glLineWidth ( 2.0 );
glBegin( GL_LINE_STRIP );
for ( int i=0; i<numPoints; i++ )
glVertex2f ( pointList[i].x, pointList[i].y );
glEnd();
int intersection; // variable for intersected point
for ( int i=3; i<numPoints; i++ ) {
int intersection = intersect( i );
if( intersection > -1 ) {
glColor3f ( 1,0,0 );
glBegin( GL_POLYGON );
glVertex2f ( intersectPoint.x, intersectPoint.y );
for( int j=intersection+1;j<i;j++ )
glVertex2f ( pointList[j].x, pointList[j].y );
glEnd();
}
}
}