Skip to content

Instantly share code, notes, and snippets.

@timeopochin
Created March 24, 2021 22:04
Show Gist options
  • Save timeopochin/d65718ff16d53939f3ebe123118fdd4b to your computer and use it in GitHub Desktop.
Save timeopochin/d65718ff16d53939f3ebe123118fdd4b to your computer and use it in GitHub Desktop.
SVG Stairs generator
#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