#include <cmath>
#include "GL/LineDrawing.h"
#include "GL/Font.h"
#include "GL/ImmediateMode.h"
BEGIN_NAMESPACE
static void glLineHelper(float x1, float y1, float x2, float y2)
{
glVertex2f(x1, y1);
glVertex2f(x2, y2);
}
static void CalculateBezierLineSegments(float controlPoints[4][2], float outputPoints[][2], int subDivisions)
{
// thick bezier curve triangulation experiment
for (int i = 0; i <= subDivisions; ++i)
{
float t1 = float(i) / subDivisions;
float t2 = 1.0f - t1;
for (int c = 0; c < 2; ++c)
outputPoints[i][c] = controlPoints[0][c]*1*t2*t2*t2+
controlPoints[1][c]*3*t2*t2*t1+
controlPoints[2][c]*3*t2*t1*t1+
controlPoints[3][c]*1*t1*t1*t1;
}
}
static bool ConvertSplinePolylineToBezierCurveList(float points[][2], int pointCount, float outputControlPoints[][4][2], float continuity = 0.5)
{
if (pointCount <= 2) // make it a minimum of 3 points needed (1 point is a point, 2 points is a straight line)
return false;
for (int i = 0; i < (pointCount-1); ++i)
{
// The end control points are coincident with the input points
outputControlPoints[i][0][0] = points[i][0];
outputControlPoints[i][0][1] = points[i][1];
outputControlPoints[i][3][0] = points[i+1][0];
outputControlPoints[i][3][1] = points[i+1][1];
if ( i == 0 ) {
outputControlPoints[i][1][0] = points[i][0];
outputControlPoints[i][1][1] = points[i][1];
}
// Calculate cp[1] and cp[2]
if ( i < (pointCount-2) )
{
float dx1 = points[i+2][0] - points[i+1][0];
float dy1 = points[i+2][1] - points[i+1][1];
float len1 = sqrt(dx1*dx1 + dy1*dy1);
float dx2 = points[i+1][0] - points[i][0];
float dy2 = points[i+1][1] - points[i][1];
float len2 = sqrt(dx2*dx2 + dy2*dy2);
float x = (dx1/len1 + dx2/len2) / 2.0f;
float y = (dy1/len1 + dy2/len2) / 2.0f;
float len = sqrt(x*x + y*y);
//const float lineWidth = 50.0;
//x = lineWidth * x / len;
//y = lineWidth * y / len;
outputControlPoints[i][2][0] = points[i+1][0] - continuity * 0.5f * len2 * x / len;
outputControlPoints[i][2][1] = points[i+1][1] - continuity * 0.5f * len2 * y / len;
outputControlPoints[i+1][1][0] = points[i+1][0] + continuity * 0.5f * len1 * x / len;
outputControlPoints[i+1][1][1] = points[i+1][1] + continuity * 0.5f * len1 * y / len;
}
}
outputControlPoints[pointCount-2][2][0] = points[pointCount-1][0];
outputControlPoints[pointCount-2][2][1] = points[pointCount-1][1];
return true;
}
void glDrawPolyline(float points[][2], int pointCount)
{
glSetColor(0xa0ff0000);
glLineWidth(0.5);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < (pointCount-1); ++i)
{
glLineHelper(points[i][0], points[i][1], points[i+1][0], points[i+1][1]);
}
glEnd();
}
void glDrawThickPolyline(float topPoints[][2], float points[][2], int pointCount, float thickness)
{
float lineWidth = thickness;
float dx1 = points[1][0] - points[0][0];
float dy1 = points[1][1] - points[0][1];
float len1 = sqrt(dx1*dx1 + dy1*dy1);
float dx2 = points[pointCount-1][0] - points[pointCount-2][0];
float dy2 = points[pointCount-1][1] - points[pointCount-2][1];
float len2 = sqrt(dx2*dx2 + dy2*dy2);
topPoints[0][0] = lineWidth * dy1 / len1;
topPoints[0][1] = lineWidth * dx1 / len1;
topPoints[pointCount-1][0] = lineWidth * dy2 / len2;
topPoints[pointCount-1][1] = lineWidth * dx2 / len2;
for (int i = 1; i < (pointCount-1); ++i)
{
dx1 = points[i+1][0] - points[i][0];
dy1 = points[i+1][1] - points[i][1];
len1 = sqrt(dx1*dx1 + dy1*dy1);
dx2 = points[i][0] - points[i-1][0];
dy2 = points[i][1] - points[i-1][1];
len2 = sqrt(dx2*dx2 + dy2*dy2);
float x = (dx1/len1 + dx2/len2) / 2.0f;
float y = (dy1/len1 + dy2/len2) / 2.0f;
float len = sqrt(x*x + y*y);
x = lineWidth * x / len;
y = lineWidth * y / len;
topPoints[i][0] = y;
topPoints[i][1] = x;
}
//glLineHelper(points[0][0], points[0][1], capPt[0], capPt[1]);
glSetColor(0xa0ff0000);
glLineWidth(0.5);
glBegin(GL_LINES);
// Flat/square cap
/*
for (int i = 0; i < pointCount; ++i)
{
if ( i == (pointCount-1) || i == 0 )
glLineHelper(points[i][0]+topPoints[i][0], points[i][1]-topPoints[i][1], points[i][0]-topPoints[i][0], points[i][1]+topPoints[i][1]);
}
*/
// Round cap
for (int i = 0; i < pointCount; ++i)
{
if ( i == (pointCount-1) || i == 0 ) {
float scale = 1.5;
if ( i == 0 )
scale = -1.5;
const int subDivisions = 8;
float controlPoints[4][2] = {
{ points[i][0]+topPoints[i][0], points[i][1]-topPoints[i][1] },
{ points[i][0]+topPoints[i][0]+topPoints[i][1]*scale, points[i][1]-topPoints[i][1]+topPoints[i][0]*scale },
{ points[i][0]-topPoints[i][0]+topPoints[i][1]*scale, points[i][1]+topPoints[i][1]+topPoints[i][0]*scale },
{ points[i][0]-topPoints[i][0], points[i][1]+topPoints[i][1] },
};
float outputPoints[subDivisions+1][2];
CalculateBezierLineSegments(controlPoints, outputPoints, subDivisions);
for (int j = 0; j < subDivisions; ++j)
{
glLineHelper(outputPoints[j][0], outputPoints[j][1], outputPoints[j+1][0], outputPoints[j+1][1]);
}
}
}
for (int i = 0; i < (pointCount-1); ++i)
{
glLineHelper( points[i][0]+topPoints[i][0], points[i][1]-topPoints[i][1], points[i+1][0]+topPoints[i+1][0], points[i+1][1]-topPoints[i+1][1] );
glLineHelper( points[i][0]-topPoints[i][0], points[i][1]+topPoints[i][1], points[i+1][0]-topPoints[i+1][0], points[i+1][1]+topPoints[i+1][1] );
}
glEnd();
}
void LineDrawingTests()
{
float polyLine[7][2] = { { 25, 45 }, { 50, 95 }, { 130, 95 }, { 120, 195 }, { 200, 75 }, { 300, 140 }, { 500, 95 } };
//glDrawPolyline(polyLine, 7);
float tmpPoints[7 + 1][2];
glDrawThickPolyline(tmpPoints, polyLine, 7, 4.0);
for (int i = 0; i < 7; ++i) {
polyLine[i][0] += 200;
polyLine[i][1] += 200;
}
float bezierControlPoints[6][4][2];
ConvertSplinePolylineToBezierCurveList(polyLine, 7, bezierControlPoints);
const int subDivisions = 16;
float lineSegments[6*(subDivisions+1) + 1][2];
for (int i = 0; i < 6; ++i) {
CalculateBezierLineSegments(bezierControlPoints[i], &lineSegments[i*(subDivisions)], subDivisions);
//glDrawPolyline(&lineSegments[i*(subDivisions+1)], subDivisions + 2);
}
float topPoints[6*(subDivisions) + 1][2];
glDrawThickPolyline(topPoints, lineSegments, 6*(subDivisions) + 1, 4.0);
/*
float cp[4][2] = { { 50, 75 }, { 300, 95 }, { 600, 700 }, { 824, 395 } };
float lineSegments[subDivisions+1][2];
glDrawPolyline(cp, 4);
CalculateBezierLineSegments(cp, lineSegments, subDivisions);
glDrawPolyline(lineSegments, subDivisions + 1);
float topPoints[subDivisions+1][2];
glDrawThickPolyline(topPoints, lineSegments, subDivisions + 1);
*/
}
END_NAMESPACE