Newer
Older
invertedlogic / invertedlogic / iLFramework / toolkit / src / GL / LineDrawing.cpp
@John Ryland John Ryland on 10 Nov 2019 6 KB add framework
#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