Created
March 24, 2021 22:04
-
-
Save timeopochin/d65718ff16d53939f3ebe123118fdd4b to your computer and use it in GitHub Desktop.
SVG Stairs generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
typedef struct Point Point; | |
struct Point { | |
float x; | |
float y; | |
}; | |
void calculateStairs(const float angle, const float before, const float after, const float width, int stepCount); | |
int main() { | |
float angleDeg; | |
float before; | |
float after; | |
float width; | |
int stepCount; | |
printf("Angle of the corner (degrees): "); | |
scanf("%f", &angleDeg); | |
printf("Length of the stairs before corner: "); | |
scanf("%f", &before); | |
printf("Length of the stairs after corner: "); | |
scanf("%f", &after); | |
printf("Width of the stairs: "); | |
scanf("%f", &width); | |
printf("Number of steps: "); | |
scanf("%d", &stepCount); | |
calculateStairs(angleDeg, before, after, width, stepCount); | |
return 0; | |
} | |
void calculateStairs(const float angleDeg, const float before, const float after, const float width, const int stepCount) { | |
// Convert to radians | |
const float angle = (angleDeg*2*M_PI)/360; | |
// Calculate step depth | |
const float oppositeAngle = M_PI - angle; | |
const float afterGradient = - 1/tan(oppositeAngle); | |
const float afterYIntercept = width/sin(oppositeAngle); | |
const float arc = (width*oppositeAngle)/2; | |
const float arcDifference = width/tan(angle/2); | |
const float beforeArc = before - arcDifference; | |
const float afterArc = after - arcDifference; | |
const float pathLength = beforeArc + arc + afterArc; | |
const float stepDepth = pathLength/stepCount; | |
// Calculate points the lines go through before the arc | |
const int stepCountBefore = (beforeArc + arc/2)/stepDepth; | |
const int stepCountBeforeArc = beforeArc/stepDepth; | |
const int stepCountAfter = (afterArc + arc/2)/stepDepth; | |
const int stepCountAfterArc = afterArc/stepDepth; | |
Point* pointsOnPath = NULL; | |
Point* pointsOnDiagonal = NULL; | |
pointsOnPath = malloc((stepCount + 1)*sizeof(Point)); | |
pointsOnDiagonal = malloc((stepCount + 1)*sizeof(Point)); | |
int i; | |
float angleToPoint; | |
for (i = 0; i <= stepCount; i++) { | |
if (i <= stepCountBeforeArc) { | |
// Point on the path | |
pointsOnPath[i].x = width/2; | |
pointsOnPath[i].y = stepDepth*i - beforeArc; | |
} else if (i < stepCount - stepCountAfterArc) { | |
// Point on the arc | |
angleToPoint = (2*(stepDepth*(i - stepCountBeforeArc + stepCountBeforeArc) - beforeArc))/width; | |
pointsOnPath[i].x = (width*cos(angleToPoint))/2; | |
pointsOnPath[i].y = (width*sin(angleToPoint))/2; | |
} else { | |
// Point on second path | |
pointsOnPath[i].x = (width - after*sin(oppositeAngle) - afterArc*sin(oppositeAngle))/2 + stepDepth*sin(oppositeAngle)*(stepCount - i); | |
pointsOnPath[i].y = afterGradient*pointsOnPath[i].x + afterYIntercept/2; | |
} | |
if (i <= stepCountBefore) { | |
// Point on the diagonal before | |
pointsOnDiagonal[i].y = (i*beforeArc)/(stepCountBefore + 1) - beforeArc; | |
pointsOnDiagonal[i].x = pointsOnDiagonal[i].y/tan(oppositeAngle/2); | |
} else { | |
// Point on the diagonal after | |
pointsOnDiagonal[i].y = ((stepCount - i)*afterArc)/(stepCountAfter + 1) - afterArc; | |
pointsOnDiagonal[i].x = pointsOnDiagonal[i].y/tan(oppositeAngle/2); | |
} | |
} | |
// Calculate the points at the extremities of the line segments | |
Point* innerPoints = NULL; | |
Point* outerPoints = NULL; | |
innerPoints = malloc((stepCount + 1)*sizeof(Point)); | |
outerPoints = malloc((stepCount + 1)*sizeof(Point)); | |
float gradient; | |
for (i = 0; i <= stepCount; i++) { | |
gradient = (pointsOnPath[i].y - pointsOnDiagonal[i].y)/(pointsOnPath[i].x - pointsOnDiagonal[i].x); | |
if (i <= stepCountBefore) { | |
// Calculate the points before | |
innerPoints[i].x = 0; | |
innerPoints[i].y = pointsOnPath[i].y - gradient*pointsOnPath[i].x; | |
outerPoints[i].x = width; | |
outerPoints[i].y = gradient*(width - pointsOnPath[i].x) + pointsOnPath[i].y; | |
} else { | |
// Calculate the points after | |
innerPoints[i].x = (pointsOnPath[i].y - gradient*pointsOnPath[i].x)/(afterGradient - gradient); | |
innerPoints[i].y = afterGradient*innerPoints[i].x; | |
outerPoints[i].x = (pointsOnPath[i].y - gradient*pointsOnPath[i].x - afterYIntercept)/(afterGradient - gradient); | |
outerPoints[i].y = afterGradient*outerPoints[i].x + afterYIntercept; | |
} | |
//innerPoints[i].x = pointsOnPath[i].x; | |
//innerPoints[i].y = pointsOnPath[i].y; | |
//outerPoints[i].x = pointsOnDiagonal[i].x; | |
//outerPoints[i].y = pointsOnDiagonal[i].y; | |
} | |
free(pointsOnPath); | |
free(pointsOnDiagonal); | |
// Create the svg file and add the lines | |
FILE* svg = fopen("stairs.svg", "w"); | |
fprintf(svg, "<svg xmlns=\"http://www.w3.org/2000/svg\">\n"); | |
for (i = 0; i <= stepCount; i++) { | |
fprintf(svg, "\t<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"red\" />\n", innerPoints[i].x, innerPoints[i].y, outerPoints[i].x, outerPoints[i].y); | |
} | |
fprintf(svg, "\t<line x1=\"%f\" y1=\"%f\" x2=\"0\" y2=\"0\" stroke=\"blue\" />\n", innerPoints[0].x, innerPoints[0].y); | |
fprintf(svg, "\t<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"blue\" />\n", outerPoints[0].x, outerPoints[0].y, width, arcDifference); | |
fprintf(svg, "\t<line x1=\"%f\" y1=\"%f\" x2=\"0\" y2=\"0\" stroke=\"blue\" />\n", innerPoints[stepCount].x, innerPoints[stepCount].y); | |
fprintf(svg, "\t<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"blue\" />\n", outerPoints[stepCount].x, outerPoints[stepCount].y, width, arcDifference); | |
fprintf(svg, "</svg>\n"); | |
fclose(svg); | |
free(innerPoints); | |
free(outerPoints); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment