colorz
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
44
render.c
44
render.c
@@ -6,17 +6,20 @@
|
|||||||
|
|
||||||
#define WINDOW_WIDTH 800
|
#define WINDOW_WIDTH 800
|
||||||
#define WINDOW_HEIGHT 600
|
#define WINDOW_HEIGHT 600
|
||||||
#define NODE_RADIUS 15
|
#define NODE_RADIUS 5
|
||||||
#define ITERATIONS 500 // layout simulation steps
|
#define ITERATIONS 1000 // layout simulation steps
|
||||||
#define COOLING 0.97 // temperature cooling rate
|
#define COOLING 1 // temperature cooling rate
|
||||||
|
|
||||||
typedef struct {
|
struct layout_node_t {
|
||||||
double x, y; // position
|
double x, y; // position
|
||||||
double vx, vy; // velocity / displacement
|
double vx, vy; // velocity / displacement
|
||||||
} layout_node_t;
|
};
|
||||||
|
typedef struct layout_node_t layout_node_t;
|
||||||
|
|
||||||
static void draw_circle(SDL_Renderer *renderer, int cx, int cy, int r)
|
// display a simple node of radius r
|
||||||
|
static void draw_node(SDL_Renderer *renderer, int cx, int cy, int r)
|
||||||
{
|
{
|
||||||
|
SDL_SetRenderDrawColor(renderer, 215, 153, 33, 255);
|
||||||
for (int dy = -r; dy <= r; dy++) {
|
for (int dy = -r; dy <= r; dy++) {
|
||||||
int dx = (int)sqrt((double)(r * r - dy * dy));
|
int dx = (int)sqrt((double)(r * r - dy * dy));
|
||||||
SDL_RenderDrawLine(renderer, cx - dx, cy + dy, cx + dx,
|
SDL_RenderDrawLine(renderer, cx - dx, cy + dy, cx + dx,
|
||||||
@@ -24,7 +27,7 @@ static void draw_circle(SDL_Renderer *renderer, int cx, int cy, int r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fruchterman-Reingold force-directed layout
|
// compute a layout based on the fruchtermann-reingold algorithm.
|
||||||
static layout_node_t *compute_layout(const graph_t *graph)
|
static layout_node_t *compute_layout(const graph_t *graph)
|
||||||
{
|
{
|
||||||
int n = graph->n;
|
int n = graph->n;
|
||||||
@@ -32,8 +35,6 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
if (!nodes)
|
if (!nodes)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Seed random positions
|
|
||||||
srand((unsigned)time(NULL));
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
nodes[i].x = (double)(rand() % (WINDOW_WIDTH - 100)) + 50;
|
nodes[i].x = (double)(rand() % (WINDOW_WIDTH - 100)) + 50;
|
||||||
nodes[i].y = (double)(rand() % (WINDOW_HEIGHT - 100)) + 50;
|
nodes[i].y = (double)(rand() % (WINDOW_HEIGHT - 100)) + 50;
|
||||||
@@ -42,15 +43,13 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
double area = (WINDOW_WIDTH - 200) * (WINDOW_HEIGHT - 200);
|
double area = (WINDOW_WIDTH - 200) * (WINDOW_HEIGHT - 200);
|
||||||
double k = sqrt(area / n); // optimal distance between nodes
|
double k = sqrt(area / n);
|
||||||
double temp = WINDOW_WIDTH * 0.1; // initial temperature
|
double temp = WINDOW_WIDTH * 0.1;
|
||||||
|
|
||||||
for (int iter = 0; iter < ITERATIONS; iter++) {
|
for (int iter = 0; iter < ITERATIONS; iter++) {
|
||||||
// Reset displacements
|
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
nodes[i].vx = nodes[i].vy = 0.0;
|
nodes[i].vx = nodes[i].vy = 0.0;
|
||||||
|
|
||||||
// Repulsive forces (all pairs)
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = i + 1; j < n; j++) {
|
for (int j = i + 1; j < n; j++) {
|
||||||
double dx = nodes[i].x - nodes[j].x;
|
double dx = nodes[i].x - nodes[j].x;
|
||||||
@@ -70,7 +69,6 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attractive forces (edges only)
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
node_t *neighbor = graph->adj_lists[i];
|
node_t *neighbor = graph->adj_lists[i];
|
||||||
while (neighbor) {
|
while (neighbor) {
|
||||||
@@ -95,7 +93,6 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply displacements, clamped to temperature
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
double disp = sqrt(nodes[i].vx * nodes[i].vx +
|
double disp = sqrt(nodes[i].vx * nodes[i].vx +
|
||||||
nodes[i].vy * nodes[i].vy);
|
nodes[i].vy * nodes[i].vy);
|
||||||
@@ -115,7 +112,6 @@ static layout_node_t *compute_layout(const graph_t *graph)
|
|||||||
nodes[i].y));
|
nodes[i].y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cool the temperature
|
|
||||||
temp *= COOLING;
|
temp *= COOLING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,11 +130,11 @@ void render_graph(SDL_Renderer *renderer, const graph_t *graph)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Clear background
|
// Clear background
|
||||||
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
|
SDL_SetRenderDrawColor(renderer, 48, 48, 48, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
// Draw edges
|
// Draw edges
|
||||||
SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
|
SDL_SetRenderDrawColor(renderer, 189, 189, 189, 255);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
node_t *neighbor = graph->adj_lists[i];
|
node_t *neighbor = graph->adj_lists[i];
|
||||||
|
|
||||||
@@ -160,17 +156,7 @@ void render_graph(SDL_Renderer *renderer, const graph_t *graph)
|
|||||||
int y = (int)layout[i].y;
|
int y = (int)layout[i].y;
|
||||||
|
|
||||||
// Node fill
|
// Node fill
|
||||||
SDL_SetRenderDrawColor(renderer, 100, 149, 237, 255);
|
draw_node(renderer, x, y, NODE_RADIUS);
|
||||||
draw_circle(renderer, x, y, NODE_RADIUS);
|
|
||||||
|
|
||||||
// Node border
|
|
||||||
SDL_SetRenderDrawColor(renderer, 200, 220, 255, 255);
|
|
||||||
for (int deg = 0; deg < 360; deg++) {
|
|
||||||
double a = deg * M_PI / 180.0;
|
|
||||||
SDL_RenderDrawPoint(renderer,
|
|
||||||
x + (int)(NODE_RADIUS * cos(a)),
|
|
||||||
y + (int)(NODE_RADIUS * sin(a)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(layout);
|
free(layout);
|
||||||
|
|||||||
Reference in New Issue
Block a user