Skip to content

Instantly share code, notes, and snippets.

@BalintCsala
Created October 30, 2019 21:02
Show Gist options
  • Save BalintCsala/62bca8c487182bf519341f2b63d7702c to your computer and use it in GitHub Desktop.
Save BalintCsala/62bca8c487182bf519341f2b63d7702c to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <stdlib.h>
// Konstansok
const double PI = 3.141592654;
const int METER = 20;
const int WIDTH = 800;
const int HEIGHT = 400;
const double G = -9.81;
const char *SVG_HEADER = "<svg width='800px' height='400px' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink'>";
const char *SVG_FOOTER = "</svg>";
const int STEPS = 100;
// 2 dimenziós vektor struktúra
typedef struct Vector {
double x, y;
} vec;
// Vektor függvények
vec vec_sub(vec a, vec b);
double vec_len(vec v);
// SVG függvények
void animacio(FILE *file, double t, char *id);
void vonal(FILE *file, double x1, double y1, double x2, double y2, char *szin, int vastagsag);
void kor(FILE *file, double cx, double cy, double sugar, char *szin);
void alakzat(FILE *file, char *pontok, char *szin, char *korvonal);
void teglalap(FILE *file, double x, double y, double w, double h, char *szin);
// Segítő függvények
double map(double val, double min, double max, double out_min, double out_max);
vec pozicio(vec kezdo, vec sebesseg, double t);
int talalat(vec madar, vec malac, vec sebesseg, double max_t);
int main()
{
// Előre beállított seed keresgélés után
srand(1570233692);
// File megnyitása
FILE *output = fopen("angry.svg", "w");
// Alap SVG fejléc beillesztése
fputs(SVG_HEADER, output);
int fold_magassag = HEIGHT - 10;
int margo = 100;
// Háttér
teglalap(output, 0, 0, WIDTH, HEIGHT, "hsl(180, 60%, 60%)");
// Nap
kor(output, 50, 30, 20, "yellow");
// Felhők
for (int i = 0; i < 30; i++) {
double x = rand() % 1200 + 860;
double y = rand() % 100;
double r = rand() % 40 + 20;
fprintf(output, "<ellipse cx='%f' cy='%f' rx='%f' ry='%f' fill='white' fill-opacity='0.8'>\n", x, y, r, r / 2.0);
fprintf(output, " <animate attributeName='cx' from='%f' to='%f' dur='%fs' repeatCount='indefinite' />\n", x, -60.0, rand() % 20 + 20.0);
fprintf(output, "</ellipse>\n");
}
// Hegyek random sétáló alapján
char color[20];
for (int hegy = 0; hegy < 4; hegy++) {
sprintf(color, "hsl(%d, 60%%, %d%%)", 180 - hegy * 20, 50 - hegy * 8);
double vy = -1;
double y = 150 + hegy * 50 + rand() % 20 - 10;
fprintf(output, "<polygon points='800 400, 0 400");
vec min = {-1, HEIGHT};
for (int i = 0; i <= 80; i++) {
double x = WIDTH / 80.0 * i;
if (min.y > y) {
min.x = x;
min.y = y;
}
fprintf(output, ",%.2f %.2f", x, y);
y += (rand() % 100) / 100.0 * 30 - 15;//vy;
vy += ((rand() % 100) / 100.0 - 0.5) * 10.0;
}
fprintf(output, "' fill='%s' />\n", color);
// Zászló
vonal(output, min.x, min.y, min.x, min.y - 8, "rgb(54, 34, 6)", 1);
teglalap(output, min.x + 1, min.y - 8, 5, 4, "red");
}
// Föld
teglalap(output, 0, fold_magassag, WIDTH, 10, "green");
// Madár állvány
teglalap(output, margo, fold_magassag - 3 * METER, METER / 2.0, 3 * METER, "rgb(54, 34, 6)");
// Malac állvány
teglalap(output, WIDTH - margo - 2.5 * METER, fold_magassag - 2 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo + 2.5 * METER, fold_magassag - 2 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo, fold_magassag - 2 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo + 5 - 3 * METER, fold_magassag - 2.5 * METER, 6 * METER, METER / 2.0, "grey");
teglalap(output, WIDTH - margo - 1.5 * METER, fold_magassag - 4.5 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo + 1.5 * METER, fold_magassag - 4.5 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo + 5 - 2 * METER, fold_magassag - 5 * METER, 4 * METER, METER / 2.0, "grey");
teglalap(output, WIDTH - margo, fold_magassag - 7 * METER, METER / 2.0, 2 * METER, "grey");
teglalap(output, WIDTH - margo + 5 - 1 * METER, fold_magassag - 7 * METER, 2 * METER, METER / 2.0, "grey");
// Malac
vec malac_poz = { WIDTH - margo + 5, fold_magassag - 15 * METER / 2.0 };
char malac_path[80];
sprintf(malac_path, "%.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f",
malac_poz.x - 10, malac_poz.y - 4,
malac_poz.x - 12, malac_poz.y - 12,
malac_poz.x, malac_poz.y - 8,
malac_poz.x + 12, malac_poz.y - 12,
malac_poz.x + 10, malac_poz.y - 4);
alakzat(output, malac_path, "green", "black");
kor(output, malac_poz.x, malac_poz.y, 10, "green");
kor(output, malac_poz.x, malac_poz.y + 2, 5.5, "green");
kor(output, malac_poz.x - 3, malac_poz.y + 2, 1, "black");
kor(output, malac_poz.x + 3, malac_poz.y + 2, 1, "black");
// A szimulációhoz a kezdő- és végpontok
vec madar = {0, 3};
vec malac = {30, 7};
int index = 0;
for (int szog = 10; szog <= 60; szog += 5) {
double rad = (double)szog / 180 * PI;
for (int sebesseg = 10; sebesseg <= 30; sebesseg++) {
vec vel = { cos(rad) * sebesseg, sin(rad) * sebesseg };
// Max annyi idő kell, amennyi idő alatt elhagyja a malacot
double dx = malac.x - madar.x + 1;
double max_t = dx / vel.x;
// Szimuláció
int lepes = talalat(madar, malac, vel, max_t);
// Találat -> vonal kirajzolása
if (lepes > -1) {
index += 1;
char vonal_szin[40];
char id[20];
sprintf(vonal_szin, "hsl(%03d, 100%%, 50%%)", index * 20);
sprintf(id, "path%d", index);
vec pos, prev;
double t;
for (int j = 1; j < lepes - 2; j += 2) {
t = max_t / STEPS * j;
prev = pozicio(madar, vel, t - max_t / STEPS);
pos = pozicio(madar, vel, t);
double x1 = margo + 5 + map(prev.x, 0, 30, 0, 30 * METER);
double y1 = fold_magassag - 10 - map(prev.y, 0, 30, 0, 30 * METER);
double x2 = margo + 5 + map(pos.x, 0, 30, 0, 30 * METER);
double y2 = fold_magassag - 10 - map(pos.y, 0, 30, 0, 30 * METER);
vonal(output, x1, y1, x2, y2, vonal_szin, 1);
}
// Jelölő
char str[20];
sprintf(str, "%d fok, %d m/s", szog, sebesseg);
fprintf(output, "<rect x = '-2' y='-2' width='4' height='4' fill='%s' stroke='black'>\n", vonal_szin);
animacio(output, max_t * 3, id);
fprintf(output, "</rect>");
// Árnyék a láthatóság kedvéért
for (int i = 0; i < 2; i++) {
fprintf(output, "<text x='%f' y='%f' fill='%s'>%s\n", 11.0 - i, 17.0 - i, i == 0 ? "black" : vonal_szin, str);
animacio(output, max_t * 3, id);
fprintf(output, "</text>");
}
// Jelölő animációja
fprintf(output, "<path d='");
for (int j = 0; j < lepes - 1; j += 2) {
pos = pozicio(madar, vel, max_t / STEPS * j);
double x = margo + 5 + map(pos.x, 0, 30, 0, 30 * METER);
double y = fold_magassag - 10 - map(pos.y, 0, 30, 0, 30 * METER);
if (j == 0) {
fprintf(output, "M%f %f", x, y);
} else {
fprintf(output, " L%f %f", x, y);
}
}
fprintf(output, "' fill='none' id='path%d' />", index);
}
}
}
// Madár
vec madar_poz = { margo + 5, fold_magassag - 3 * METER - 10 };
kor(output, madar_poz.x - 3, madar_poz.y - 8, 5, "red");
kor(output, madar_poz.x + 2, madar_poz.y - 10, 5, "red");
kor(output, madar_poz.x, madar_poz.y, 10, "red");
char paths[60];
sprintf(paths, "%.2f, %.2f %.2f, %.2f %.2f, %.2f",
madar_poz.x + 3, madar_poz.y - 3,
madar_poz.x + 8, madar_poz.y,
madar_poz.x + 3, madar_poz.y + 3);
alakzat(output, paths, "orange", "black");
sprintf(paths, "%.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f, %2f",
madar_poz.x - 10, madar_poz.y,
madar_poz.x - 15, madar_poz.y - 5,
madar_poz.x - 19, madar_poz.y + 2,
madar_poz.x - 16, madar_poz.y - 1);
alakzat(output, paths, "black", "none");
// Az eredeti <svg> tag bezárása
fputs(SVG_FOOTER, output);
// A file bezárása
fclose(output);
return 0;
}
// Kivonja a b vektort az a-ból
vec vec_sub(vec a, vec b)
{
vec res = { a.x - b.x, a.y - b.y };
return res;
}
// Visszaadja a vektor hosszát
double vec_len(vec v)
{
return hypot(v.x, v.y);
}
void vonal(FILE *file, double x1, double y1, double x2, double y2, char *szin, int vastagsag)
{
fprintf(file, "<line x1='%f' y1='%f' x2='%f' y2='%f' stroke='%s' stroke-width='%d' />\n", x1, y1, x2,
y2, szin, vastagsag);
}
void animacio(FILE *file, double t, char *id)
{
fprintf(file, " <animateMotion dur='%.2fs' repeatCount='indefinite'>\n", t);
fprintf(file, " <mpath xlink:href='#%s' />\n", id);
fprintf(file, " </animateMotion>");
}
void kor(FILE *file, double cx, double cy, double sugar, char *szin)
{
fprintf(file, "<circle cx='%f' cy='%f' r='%f' fill='%s' stroke='black' />\n", cx, cy,
sugar, szin);
}
void alakzat(FILE *file, char *pontok, char *szin, char *korvonal)
{
fprintf(file, "<polygon points='%s' fill='%s' stroke='%s' />\n", pontok, szin, korvonal);
}
void teglalap(FILE *file, double x, double y, double w, double h, char *szin)
{
fprintf(file, "<rect x = '%f' y='%f' width='%f' height='%f' fill='%s' stroke='black' />\n", x, y, w, h, szin);
}
// Lineárisan átkonvertál egy értéket a [min, max] intervallumból az [out_min, out_max] intervallumba
double map(double val, double min, double max, double out_min, double out_max)
{
double factor = (val - min) / (max - min);
return (out_max - out_min) * factor + out_min;
}
vec pozicio(vec kezdo, vec sebesseg, double t)
{
vec res = {
kezdo.x + sebesseg.x * t,
kezdo.y + sebesseg.y * t + G * t * t
};
return res;
}
// -1-et ad vissza, ha nincs találat, a szükséges lépésszámot, ha van
int talalat(vec madar, vec malac, vec sebesseg, double max_t)
{
int i;
vec pos;
for (i = 0; i < STEPS; i++) {
double t = max_t / STEPS * i;
pos = pozicio(madar, sebesseg, t);
if (vec_len(vec_sub(pos, malac)) < 1) {
return i;
}
}
return -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment