Created
October 30, 2019 21:02
-
-
Save BalintCsala/62bca8c487182bf519341f2b63d7702c to your computer and use it in GitHub Desktop.
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 <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