lnvis

nanovg lightning network visualizer
git clone git://jb55.com/lnvis
Log | Files | Refs | README | LICENSE

update.c (5005B)


      1 
      2 #include "ln.h"
      3 #include "grid.h"
      4 #include <math.h>
      5 #include <assert.h>
      6 #include <stdio.h>
      7 
      8 struct node *hit_node(struct ln *ln) {
      9 	for (u32 i = 0; i < ln->node_count; ++i)
     10 	{
     11 		struct node *n = &ln->nodes[i];
     12 		if (!n->visible)
     13 			continue;
     14 
     15 		const double dx = fabs(n->x - ln->mx);
     16 		const double dy = fabs(n->y - ln->my);
     17 
     18 		const double d = sqrt(dx*dx + dy*dy);
     19 
     20 		/* printf("%s's dx %f dy %f d %f\n", n->alias, dx, dy, d); */
     21 
     22 		if (d <= n->size)
     23 			return n;
     24 	}
     25 
     26 	return NULL;
     27 }
     28 
     29 
     30 void repel_nodes(struct node *n1, struct node *n2, double dt) {
     31 	double dx = n2->x - n1->x;
     32 	double dy = n2->y - n1->y;
     33 
     34 	double d = sqrt(dx*dx + dy*dy);
     35 
     36 	static const double mindist = 200.0;
     37 	if (d < mindist) {
     38 
     39 		// normalized vector between two nodes
     40 		double nx = dx / d;
     41 		double ny = dy / d;
     42 
     43 		// get the distance past the minimum distance along
     44 		// the vector between the two nodes
     45 		double nnx = (d - mindist) * nx;
     46 		double nny = (d - mindist) * ny;
     47 
     48 		if (isnan(nnx) || isnan(nny))
     49 			return;
     50 
     51 		// normalize by frame time
     52 		double mx = nnx * dt;
     53 		double my = nny * dt;
     54 
     55 		// correct for the distance by accelerating the node away
     56 		// from the other node
     57 		n1->vx += mx;
     58 		n1->vy += my;
     59 
     60 		// do the same in the opposite direction for the other node
     61 		n2->vx -= mx;
     62 		n2->vy -= my;
     63 	}
     64 	else {
     65 		const double scale = 1.0;
     66 
     67 		n1->vx += dx * scale * dt;
     68 		n1->vy += dy * scale * dt;
     69 
     70 		n2->vx += -dx * scale * dt;
     71 		n2->vy += -dy * scale * dt;
     72 	}
     73 }
     74 
     75 
     76 static void force_graph(struct ln *ln, double dt) {
     77 	u32 i;
     78 
     79 	// channel constraints
     80 	for (i = 0; i < ln->channel_count; ++i) {
     81 		struct channel *channel = &ln->channels[i];
     82 
     83 		struct node *n1 = channel->nodes[0];
     84 		struct node *n2 = channel->nodes[1];
     85 
     86 		if (!n1->visible || !n2->visible)
     87 			continue;
     88 
     89 		repel_nodes(n1, n2, dt);
     90 	}
     91 }
     92 
     93 
     94 static void repel_nearby(struct node *node, double dt)
     95 {
     96 	struct node *n = NULL;
     97 	struct cell *cell = node->cell;
     98 
     99 	// might happen the first iteration?
    100 	if (cell == NULL)
    101 		return;
    102 
    103 	// we're the only one in this cell, there's nothing to repel
    104 	if (cell->node_count == 1)
    105 		return;
    106 
    107 	for (int i = 0; i < cell->node_count; ++i) {
    108 		n = cell->nodes[i];
    109 
    110 		// dont repel against ourselves
    111 		if (n == node)
    112 			continue;
    113 
    114 		assert(n);
    115 		assert(node);
    116 		repel_nodes(n, node, dt);
    117 	}
    118 }
    119 
    120 
    121 static void physics(struct ln *ln, double dt)
    122 {
    123 	static const double friction_coeff = 0.03;
    124 	static const double friction = 1.0 - friction_coeff;
    125 
    126 	// physics
    127 	for (u32 i = 0; i < ln->node_count; i++) {
    128 		struct node *node = &ln->nodes[i];
    129 
    130 		if (!node->visible)
    131 			continue;
    132 
    133 		/* repel_nearby(node, dt); */
    134 
    135 		// semi-implicit euler
    136 		node->ax *= friction;
    137 		node->ay *= friction;
    138 
    139 		// update node position
    140 		node->vx += node->ax * dt;
    141 		node->vy += node->ay * dt;
    142 
    143 		// forces (testing)
    144 		node->vx *= friction;
    145 		node->vy *= friction;
    146 
    147 		node->x += node->vx * dt;
    148 		node->y += node->vy * dt;
    149 	}
    150 }
    151 
    152 
    153 static void print_channel_info(struct channel *chan)
    154 {
    155 	printf("%u:%u:%hu %s %s -> %s %s (%f bits)\n",
    156 	       chan->short_channel_id.blocknum,
    157 	       chan->short_channel_id.txnum,
    158 	       chan->short_channel_id.outnum,
    159 	       chan->nodes[0]->id,
    160 	       chan->nodes[0]->alias,
    161 	       chan->nodes[1]->id,
    162 	       chan->nodes[1]->alias,
    163 	       chan->satoshis / 100.0
    164 		);
    165 }
    166 
    167 
    168 static void handle_click(struct ln *ln)
    169 {
    170 	// click detection
    171 	struct channel *chan = NULL;
    172 	struct node *hit = hit_node(ln);
    173 
    174 	ln->drag_target = hit;
    175 	ln->last_drag_target = hit;
    176 
    177 	if (!hit)
    178 		return;
    179 
    180 	// print some info about channels
    181 	printf("\nchannels\n--------\n");
    182 
    183 	for (u32 i = 0; i < ln->channel_count; i++) {
    184 		chan = &ln->channels[i];
    185 		chan->nodes[0]->adj_drag_target = 0;
    186 		chan->nodes[1]->adj_drag_target = 0;
    187         }
    188 
    189 	for (u32 i = 0; i < ln->channel_count; i++) {
    190 		chan = &ln->channels[i];
    191 
    192 		if (!chan->visible)
    193 			continue;
    194 
    195 		if (chan->nodes[0]->visible && chan->nodes[0] == ln->drag_target)
    196 			chan->nodes[1]->adj_drag_target |= 1;
    197 		else
    198 			chan->nodes[0]->adj_drag_target ^= 0;
    199 
    200 		if (chan->nodes[1]->visible && chan->nodes[1] == ln->drag_target)
    201 			chan->nodes[0]->adj_drag_target = 1;
    202 		else
    203 			chan->nodes[1]->adj_drag_target ^= 0;
    204 
    205 		if (nodeid_eq(chan->nodes[0]->id, hit->id) ||
    206 		    nodeid_eq(chan->nodes[1]->id, hit->id)) {
    207 			if (!chan->nodes[0]->visible || !chan->nodes[1]->visible)
    208 				continue;
    209 			print_channel_info(chan);
    210 		}
    211 	}
    212 }
    213 
    214 
    215 static void handle_rightclick(struct ln *ln)
    216 {
    217 	struct node *hit = hit_node(ln);
    218 	if (hit != NULL)
    219 		filter_network(NULL, hit, ln);
    220 }
    221 
    222 
    223 // force graph update logic
    224 void update(struct ln *ln, double dt)
    225 {
    226 	if (ln->clicked)
    227 		handle_click(ln);
    228 
    229 	if (ln->right_clicked)
    230 		handle_rightclick(ln);
    231 
    232 	// stop dragging
    233 	if (!ln->mdown && ln->drag_target) {
    234 		ln->last_drag_target = ln->drag_target;
    235 		ln->drag_target = NULL;
    236 	}
    237 
    238 	// drag
    239 	if (ln->mdown && ln->drag_target) {
    240 		ln->drag_target->x = ln->mx;
    241 		ln->drag_target->y = ln->my;
    242 		ln->drag_target->vx = 0;
    243 		ln->drag_target->vy = 0;
    244 	}
    245 
    246 	/* force_graph(ln, dt); */
    247 
    248 	/* physics(ln, dt); */
    249 
    250 	/* update_grid_move_nodes(ln); */
    251 }