12#include "../tools/openFile.h"
20#include <unordered_map>
41#define ED_idx(e) (((etoi_t*)AGDATA(e))->idx)
60"Usage: mingle <options> <file>\n\
61 -a t - max. turning angle [0-180] (40)\n\
62 -c i - compatibility measure; 0 : distance, 1: full (default)\n\
63 -i iter: number of outer iterations/subdivisions (4)\n\
64 -k k - number of neighbors in the nearest neighbor graph of edges (10)\n\
65 -K k - the force constant\n\
66 -m method - method used. 0 (force directed), 1 (agglomerative ink saving, default), 2 (cluster+ink saving)\n\
67 -o fname - write output to file fname (stdout)\n\
68 -p t - balance for avoiding sharp angles\n\
69 The larger the t, the more sharp angles are allowed\n\
70 -r R - max. recursion level with agglomerative ink saving method (100)\n\
71 -T fmt - output format: gv (default) or simple\n\
95 if ((h =
aghead(e)) == n)
return 1;
96 if (h == prevh)
return 1;
121 while ((c = getopt(argc, argv,
":a:c:i:k:K:m:o:p:r:T:v:?")) != -1) {
124 if (sscanf(optarg,
"%lf", &
s) > 0 &&
s >= 0)
127 std::cerr <<
"-a arg " << optarg <<
" must be positive real - ignored\n";
133 std::cerr <<
"-c arg " << optarg <<
" must be an integer in [0,"
137 if (sscanf(optarg,
"%d", &i) > 0 && i >= 0)
140 std::cerr <<
"-i arg " << optarg <<
" must be a non-negative integer - "
144 if (sscanf(optarg,
"%d", &i) > 0 && i >= 2)
147 std::cerr <<
"-k arg " << optarg <<
" must be an integer >= 2 - ignored\n";
150 if (sscanf(optarg,
"%lf", &
s) > 0 &&
s > 0)
153 std::cerr <<
"-K arg " << optarg <<
" must be positive real - ignored\n";
156 if (sscanf(optarg,
"%d", &i) > 0 && 0 <= i && i <=
METHOD_INK)
159 std::cerr <<
"-k arg " << optarg <<
" must be an integer >= 2 - ignored\n";
165 if (sscanf(optarg,
"%lf", &
s) > 0)
168 std::cerr <<
"-p arg " << optarg <<
" must be real - ignored\n";
171 if (sscanf(optarg,
"%d", &i) > 0 && i >= 0)
174 std::cerr <<
"-r arg " << optarg <<
" must be a non-negative integer - "
178 if (!strcmp(optarg,
"gv"))
180 else if (!strcmp(optarg,
"simple"))
183 std::cerr <<
"-T arg " << optarg <<
" must be \"gv\" or \"simple\" - "
188 if (sscanf(optarg,
"%d", &i) > 0 && i >= 0)
189 Verbose =
static_cast<unsigned char>(i);
197 std::cerr <<
cmd <<
": option -" << optopt <<
" missing argument\n";
202 if (optopt ==
'\0' || optopt ==
'?')
205 std::cerr <<
cmd <<
": option -" << optopt <<
" unrecognized\n";
221 <<
"Mingle params:\n"
225 <<
" K = " << std::setprecision(2) <<
opts.
K <<
'\n'
226 <<
" fmt = " << (
opts.
fmt ?
"simple" :
"gv") <<
'\n'
229 <<
" angle_param = " << std::setprecision(2) <<
opts.
angle_param <<
'\n'
230 <<
" angle = " << std::setprecision(2) << (180 *
opts.
angle /
M_PI) <<
'\n';
241 const std::vector<double> &x =
edge.x;
243 for (j = 0; j <
edge.npoints; j++){
246 const std::vector<double> tt1{0.15, 0.5, 0.85};
247 const std::vector<double> tt2{0.15, 0.4, 0.6, 0.85};
248 const std::vector<double> &tt = (j == 1 || j ==
edge.npoints - 1) ? tt2 : tt1;
249 for (
const double t : tt){
250 for (k = 0; k <
dim; k++) {
251 if (k != 0) os <<
',';
252 os << std::setprecision(3) << (x[(j-1)*
dim+k]*(1-t)+x[j*
dim+k]*t);
257 if (j == 0 || j ==
edge.npoints - 1) {
258 for (k = 0; k <
dim; k++) {
259 if (k != 0) os <<
',';
260 os << std::setprecision(3) << x[j *
dim + k];
269 const std::vector<double> &x =
edge.x;
271 for (j = 0; j <
edge.npoints; j++){
272 if (j != 0) os <<
':';
273 for (k = 0; k <
dim; k++) {
274 if (k != 0) os <<
',';
275 os << std::setprecision(3) << x[j *
dim + k];
278 if (j <
edge.npoints - 1 && !
edge.wgts.empty()) {
279 os <<
';' << std::setprecision(3) <<
edge.wgts[j];
287 double len, t, len_total0 = 0;
289 const std::vector<double> &x =
edge.x;
290 std::vector<double> lens(
edge.npoints);
292 for (j = 0; j <
edge.npoints - 1; j++){
294 for (k = 0; k <
dim; k++){
297 lens[j] =
len = sqrt(
len/k);
300 for (j = 0; j <
edge.npoints - 1; j++){
301 t =
edge.wgts[j] / maxwgt;
303 r = 255*t; g = 0; b = 255*(1-t);
304 if (j != 0) os <<
':';
305 os << std::hex << std::setw(2) << std::setfill(
'0') <<
'#' << r << g << b
307 if (j <
edge.npoints - 2) {
308 os <<
';' << (lens[j] / len_total0);
311 os << std::dec << std::setw(0);
314static void export_dot(FILE *fp,
size_t ne,
const std::vector<pedge> &edges,
325 for (
size_t i = 0; i < ne; i++){
327 if (!
edge.wgts.empty()) {
328 for (j = 0; j <
edge.npoints - 1; j++){
329 maxwgt = std::max(maxwgt,
edge.wgts[j]);
334 std::ostringstream buf;
340 agxset(e, epos, buf.str().c_str());
344 agxset(e, esects, buf.str().c_str());
347 if (!
edge.wgts.empty()) {
350 agxset(e, eclrs, buf.str().c_str());
362 return std::hash<int>{}(x.first) ^ std::hash<int>{}(x.second);
393 const int *ia =
A->ia;
394 const int *ja =
A->ja;
395 for (
size_t i = 0; i <
A->m; i++){
396 for (
int j = ia[i]; j < ia[i+1]; j++){
398 pm[std::pair((
int)i, ja[j])] = idx++;
413 const int k = pm[std::pair(i, j)];
420 const int *ia =
A->ia;
421 const int *ja =
A->ja;
423 std::vector<double> xx(nz * 4);
426 for (
size_t i = 0; i <
A->m; i++){
427 for (
int j = ia[i]; j < ia[i+1]; j++){
430 xx[nz*
dim+1] = x[i*2+1];
431 xx[nz*
dim+2] = x[ja[j]*2];
432 xx[nz*
dim+3] = x[ja[j]*2+1];
445 std::vector<pedge> edges =
459int main(
int argc,
char *argv[])
int getDotNodeID(Agnode_t *n)
SparseMatrix SparseMatrix_import_dot(Agraph_t *g, double **x, int format)
void initDotIO(Agraph_t *g)
void setDotNodeID(Agnode_t *n, int v)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
void SparseMatrix_delete(SparseMatrix A)
abstract graph C library, Cgraph API
helpers for verbose/debug printing
std::vector< pedge > edge_bundling(SparseMatrix A0, int dim, const std::vector< double > &x, int maxit_outer, double K, int method, int nneighbor, int compatibility_method, int max_recursion, double angle_param, double angle)
void pedge_export_gv(FILE *fp, size_t ne, const std::vector< pedge > &edges)
static NORETURN void graphviz_exit(int status)
static int eval(Agraph_t *g, int root)
static double len(glCompPoint p)
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
int agxset(void *obj, Agsym_t *sym, const char *value)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
void agerrorf(const char *fmt,...)
int agerr(agerrlevel_t level, const char *fmt,...)
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
char * agnameof(void *)
returns a string descriptor for the object.
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
static const char * usage
char * fileName(ingraph_state *sp)
Return name of current file being processed.
Agraph_t * nextGraph(ingraph_state *sp)
ingraph_state * newIngraph(ingraph_state *sp, char **files)
supports user-supplied data
static const char use_msg[]
std::unordered_map< std::pair< int, int >, int, PointHash > PointMap
static int bundle(Agraph_t *g, const opts_t &opts)
static void genBundleSpline(const pedge &edge, std::ostream &os)
static void genBundleInfo(const pedge &edge, std::ostream &os)
static int checkG(Agraph_t *g)
static void export_dot(FILE *fp, size_t ne, const std::vector< pedge > &edges, Agraph_t *g)
static void init(int argc, char *argv[], opts_t &opts)
static void genBundleColors(const pedge &edge, std::ostream &os, double maxwgt)
SparseMatrix nearest_neighbor_graph(int nPts, int num_neighbors, const std::vector< double > &x)
static FILE * openFile(const char *argv0, const char *name, const char *mode)
implementation of Agrec_t
a hash derivation function for int pairs
size_t operator()(const std::pair< int, int > &x) const