}
}
+#define ELS "|edgelabel|"
+#define ELSN (sizeof(ELS)-1)
+ /* Return true if node name starts with ELS */
+#define IS_LNODE(n) (!strncmp(agnameof(n),ELS,ELSN))
+
/* getSizes:
* Set up array of half sizes in inches.
*/
-double *getSizes(Agraph_t * g, pointf pad)
+double *getSizes(Agraph_t * g, pointf pad, int* n_elabels, int** elabels)
{
Agnode_t *n;
real *sizes = N_GNEW(2 * agnnodes(g), real);
- int i;
+ int i, nedge_nodes;
+ int* elabs;
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ if (elabels && IS_LNODE(n)) nedge_nodes++;
+
i = ND_id(n);
sizes[i * 2] = ND_width(n) * .5 + pad.x;
sizes[i * 2 + 1] = ND_height(n) * .5 + pad.y;
}
+ if (elabels && nedge_nodes) {
+ elabs = N_GNEW(nedge_nodes, int);
+ nedge_nodes = 0;
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ if (IS_LNODE(n))
+ elabs[nedge_nodes++] = ND_id(n);
+ }
+ *elabels = elabs;
+ *n_elabels = nedge_nodes;
+ }
+
return sizes;
}
* Assumes g is connected and simple, i.e., we can have a->b and b->a
* but not a->b and a->b
*/
-SparseMatrix makeMatrix(Agraph_t * g, int dim)
+SparseMatrix makeMatrix(Agraph_t* g, int dim, SparseMatrix *D)
{
SparseMatrix A = 0;
Agnode_t *n;
real *val;
real v;
int type = MATRIX_TYPE_REAL;
+ Agsym_t* symD = NULL;
+ real* valD = NULL;
if (!g)
return NULL;
val = N_GNEW(nedges, real);
sym = agfindedgeattr(g, "weight");
+ if (D) {
+ symD = agfindedgeattr(g, "len");
+ valD = N_NEW(nedges, real);
+ }
+
i = 0;
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
row = ND_id(n);
#endif
v = 1;
val[i] = v;
+ /* edge length */
+ if (symD) {
+#ifndef WITH_CGRAPH
+#else
+ if (sscanf (agxget (e, symD->index), "%lf", &v) != 1) v = 1;
+#endif
+ valD[i] = v;
+ }
i++;
}
}
A = SparseMatrix_from_coordinate_arrays(nedges, nnodes, nnodes, I, J,
val, type);
+ if (D) *D = SparseMatrix_from_coordinate_arrays(nedges, nnodes, nnodes, I, J, valD, type);
+
free(I);
free(J);
free(val);
+ if (valD) free (valD);
return A;
}
static int
fdpAdjust (graph_t* g, adjust_data* am)
{
- SparseMatrix A0 = makeMatrix(g, Ndim);
+ SparseMatrix A0 = makeMatrix(g, Ndim, NULL);
SparseMatrix A = A0;
real *sizes;
real *pos = N_NEW(Ndim * agnnodes(g), real);
pad.x = PS2INCH(DFLT_MARGIN);
pad.y = PS2INCH(DFLT_MARGIN);
}
- sizes = getSizes(g, pad);
+ sizes = getSizes(g, pad, NULL, NULL);
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
real* npos = pos + (Ndim * ND_id(n));
A = SparseMatrix_remove_diagonal(A);
}
- remove_overlap(Ndim, A, A->m, pos, sizes, am->value, am->scaling, &flag);
+ remove_overlap(Ndim, A, pos, sizes, am->value, am->scaling,
+ ELSCHEME_NONE, 0, NULL, NULL, &flag);
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
real *npos = pos + (Ndim * ND_id(n));
extern int cAdjust(graph_t *, int);
extern int scAdjust(graph_t *, int);
extern adjust_data *graphAdjustMode(graph_t *G, adjust_data*, char* dflt);
- extern double *getSizes(Agraph_t * g, pointf pad);
- extern SparseMatrix makeMatrix(Agraph_t * g, int dim);
+ extern double *getSizes(Agraph_t * g, pointf pad, int *n_elabels, int **elabels);
+ extern SparseMatrix makeMatrix(Agraph_t* g, int dim, SparseMatrix *D);
#ifdef __cplusplus
}
return sf;
}
+int*
+get_triangles (double *x, int n, int* tris)
+{
+ int* trilist = NULL;
+
+ if (n <= 2) return NULL;
+ agerr (AGERR, "get_triangles not yet implemented using GTS library\n");
+
+ return trilist;
+}
+
void
freeSurface (surface_t* s)
{
#include "triangle.c"
#include "assert.h"
+int*
+get_triangles (double *x, int n, int* tris)
+{
+ struct triangulateio in, mid, vorout;
+
+ if (n <= 2) return NULL;
+
+ in.numberofpoints = n;
+ in.numberofpointattributes = 0;
+ in.pointlist = (REAL *) N_GNEW(in.numberofpoints * 2, REAL);
+
+ for (i = 0; i < n; i++){
+ in.pointlist[i*2] = x[i*2];
+ in.pointlist[i*2 + 1] = x[i*2 + 1];
+ }
+ in.pointattributelist = NULL;
+ in.pointmarkerlist = NULL;
+ in.numberofsegments = 0;
+ in.numberofholes = 0;
+ in.numberofregions = 0;
+ in.regionlist = NULL;
+ mid.pointlist = (REAL *) NULL; /* Not needed if -N switch used. */
+ mid.pointattributelist = (REAL *) NULL;
+ mid.pointmarkerlist = (int *) NULL; /* Not needed if -N or -B switch used. */
+ mid.trianglelist = (int *) NULL; /* Not needed if -E switch used. */
+ mid.triangleattributelist = (REAL *) NULL;
+ mid.neighborlist = (int *) NULL; /* Needed only if -n switch used. */
+ mid.segmentlist = (int *) NULL;
+ mid.segmentmarkerlist = (int *) NULL;
+ mid.edgelist = (int *) NULL; /* Needed only if -e switch used. */
+ mid.edgemarkerlist = (int *) NULL; /* Needed if -e used and -B not used. */
+ vorout.pointlist = (REAL *) NULL; /* Needed only if -v switch used. */
+ vorout.pointattributelist = (REAL *) NULL;
+ vorout.edgelist = (int *) NULL; /* Needed only if -v switch used. */
+ vorout.normlist = (REAL *) NULL; /* Needed only if -v switch used. */
+
+ /* Triangulate the points. Switches are chosen to read and write a */
+ /* PSLG (p), preserve the convex hull (c), number everything from */
+ /* zero (z), assign a regional attribute to each element (A), and */
+ /* produce an edge list (e), a Voronoi diagram (v), and a triangle */
+ /* neighbor list (n). */
+
+ triangulate("Qenv", &in, &mid, &vorout);
+ assert (mid.numberofcorners == 3);
+
+ *tris = mid.numberoftriangles;
+
+ FREE(in.pointlist);
+ FREE(in.pointattributelist);
+ FREE(in.pointmarkerlist);
+ FREE(in.regionlist);
+ FREE(mid.pointlist);
+ FREE(mid.pointattributelist);
+ FREE(mid.pointmarkerlist);
+ FREE(mid.triangleattributelist);
+ FREE(mid.neighborlist);
+ FREE(mid.segmentlist);
+ FREE(mid.segmentmarkerlist);
+ FREE(mid.edgelist);
+ FREE(mid.edgemarkerlist);
+ FREE(vorout.pointlist);
+ FREE(vorout.pointattributelist);
+ FREE(vorout.edgelist);
+ FREE(vorout.normlist);
+
+ return mid.trianglelist;
+}
+
// maybe it should be replaced by RNG - relative neigborhood graph, or by GG - gabriel graph
int*
delaunay_tri (double *x, double *y, int n, int* nedges)
}
#else
static char* err = "Graphviz built without any triangulation library\n";
+int* get_triangles (double *x, int n, int* tris)
+{
+ agerr(AGERR, "get_triangles: %s\n", err);
+ return 0;
+}
v_data *delaunay_triangulation(double *x, double *y, int n)
{
agerr(AGERR, "delaunay_triangulation: %s\n", err);
int *delaunay_tri (double *x, double *y, int n, int* nedges);
+int *get_triangles (double *x, int n, int* ntris);
+
v_data *UG_graph(double *x, double *y, int n, int accurate_computation);
surface_t* mkSurface (double *x, double *y, int n, int* segs, int nsegs);
#include "memory.h"
#include "globals.h"
#include <time.h>
-#define MALLOC gmalloc
-#define REALLOC grealloc
-#define FREE free
-#define MEMCPY memcpy
-
-#define MACHINEACC 1.0e-16
-
-#ifndef SMOOTHER
-#include "post_process.h"
-
-typedef StressMajorizationSmoother OverlapSmoother;
-
-#define OverlapSmoother_struct StressMajorizationSmoother_struct
-
-#endif
static void ideal_distance_avoid_overlap(int dim, SparseMatrix A, real *x, real *width, real *ideal_distance, real *tmax, real *tmin){
/* if (x1>x2 && y1 > y2) we want either x1 + t (x1-x2) - x2 > (width1+width2), or y1 + t (y1-y2) - y2 > (height1+height2),
#endif
assert(treey->nil != newNode);
- while (((newNode = TreePredecessor(treey, newNode)) != treey->nil) && ((scan_point *)newNode->key)->node != k){
+ while ((newNode) && ((newNode = TreePredecessor(treey, newNode)) != treey->nil) && ((scan_point *)newNode->key)->node != k){
neighbor = (((scan_point *)newNode->key)->node)%n;
A = SparseMatrix_coordinate_form_add_entries(A, 1, &neighbor, &k, &one);
#ifdef DEBUG_RBTREE
treey->PrintKey(newNode0->key);
#endif
- RBDelete(treey,newNode0);
+ if (newNode0) RBDelete(treey,newNode0);
if (newNode != treey->nil && newNode != newNode0) {
#ifdef DEBUG_RBTREE
treey->PrintKey(newNode->key)
#endif
- RBDelete(treey,newNode);
+ if (newNode0) RBDelete(treey,newNode);
}
}
}
/* ============================== label overlap smoother ==================*/
-void OverlapSmoother_delete(OverlapSmoother sm){
-
- StressMajorizationSmoother_delete(sm);
+static void relative_position_constraints_delete(void *d){
+ relative_position_constraints data;
+ if (!d) return;
+ data = (relative_position_constraints) d;
+ if (data->irn) FREE(data->irn);
+ if (data->jcn) FREE(data->jcn);
+ if (data->val) FREE(data->val);
+ /* other stuff inside relative_position_constraints is assed back to the user hence no need to deallocator*/
+ FREE(d);
+}
+static relative_position_constraints relative_position_constraints_new(SparseMatrix A_constr, int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes){
+ relative_position_constraints data;
+ assert(A_constr);
+ data = MALLOC(sizeof(struct relative_position_constraints_struct));
+ data->constr_penalty = 1;
+ data->edge_labeling_scheme = edge_labeling_scheme;
+ data->n_constr_nodes = n_constr_nodes;
+ data->constr_nodes = constr_nodes;
+ data->A_constr = A_constr;
+ data->irn = NULL;
+ data->jcn = NULL;
+ data->val = NULL;
+
+ return data;
}
OverlapSmoother OverlapSmoother_new(SparseMatrix A, int m,
int dim, real lambda0, real *x, real *width, int include_original_graph, int neighborhood_only,
- real *max_overlap, real *min_overlap, int shrink){
+ real *max_overlap, real *min_overlap,
+ int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int shrink
+ ){
OverlapSmoother sm;
int i, j, k, *iw, *jw, *id, *jd, jdiag;
SparseMatrix B;
assert((!A) || SparseMatrix_is_symmetric(A, FALSE));
- assert((!A) || m == A->m);
+ sm = GNEW(struct OverlapSmoother_struct);
+ sm->scheme = SM_SCHEME_NORMAL;
+ if (constr_nodes && n_constr_nodes > 0 && edge_labeling_scheme != ELSCHEME_NONE){
+ sm->scheme = SM_SCHEME_NORMAL_ELABEL;
+ sm->data = relative_position_constraints_new(A_constr, edge_labeling_scheme, n_constr_nodes, constr_nodes);
+ sm->data_deallocator = relative_position_constraints_delete;
+ } else {
+ sm->data = NULL;
+ }
- sm = N_GNEW(1, struct OverlapSmoother_struct);
lambda = sm->lambda = N_GNEW(m,real);
for (i = 0; i < m; i++) sm->lambda[i] = lambda0;
continue;
}
if (d[j] > 0){/* those edges that needs expansion */
- w[j] = 100/d[j]/d[j];
+ w[j] = -100/d[j]/d[j];
+ /*w[j] = 100/d[j]/d[j];*/
} else {/* those that needs shrinking is set to negative in ideal_distance_avoid_overlap */
- w[j] = 1/d[j]/d[j];
+ /*w[j] = 1/d[j]/d[j];*/
+ w[j] = -1/d[j]/d[j];
d[j] = -d[j];
}
dist = d[j];
return sm;
}
-void OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x){
+void OverlapSmoother_delete(OverlapSmoother sm){
+
+ StressMajorizationSmoother_delete(sm);
+
+}
+
+real OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x){
int maxit_sm = 1;/* only using 1 iteration of stress majorization
is found to give better results and save time! */
- StressMajorizationSmoother_smooth(sm, dim, x, maxit_sm);
+ real res = StressMajorizationSmoother_smooth(sm, dim, x, maxit_sm, 0.001);
#ifdef DEBUG
{FILE *fp;
fp = fopen("/tmp/222","w");
export_embedding(fp, dim, sm->Lwd, x, NULL);
fclose(fp);}
#endif
+ return res;
}
/*================================= end OverlapSmoother =============*/
FREE(xmax);
}
+static int check_convergence(real max_overlap, real res, int has_penalty_terms, real epsilon){
+ if (!has_penalty_terms) return (max_overlap <= 1);
+ return res < epsilon;
+}
+
+void remove_overlap(int dim, SparseMatrix A, real *x, real *label_sizes, int ntry, real initial_scaling,
+ int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int *flag){
+ /*
+ edge_labeling_scheme: if ELSCHEME_NONE, n_constr_nodes/constr_nodes/A_constr are not used
+
+ n_constr_nodes: number of nodes that has constraints, these are nodes that is
+ . constrained to be close to the average of its neighbors.
+ constr_nodes: a list of nodes that need to be constrained. If NULL, unused.
+ A_constr: neighbors of node i are in the row i of this matrix. i needs to sit
+ . in between these neighbors as much as possible. this must not be NULL
+ . if constr_nodes != NULL.
+
+ */
-void remove_overlap(int dim, SparseMatrix A, int m, real *x, real *label_sizes, int ntry, real initial_scaling, int *flag){
real lambda = 0.00;
OverlapSmoother sm;
int include_original_graph = 0, i;
- real avg_label_size;
+ real LARGE = 100000;
+ real avg_label_size, res = LARGE;
real max_overlap = 0, min_overlap = 999;
int neighborhood_only = TRUE;
+ int has_penalty_terms = FALSE;
+ real epsilon = 0.005;
int shrink = 0;
-
+
#ifdef TIME
clock_t cpu;
#endif
cpu = clock();
#endif
- if (!label_sizes) return;
-
+ if (!label_sizes) return;
if (initial_scaling < 0) {
avg_label_size = 0;
- for (i = 0; i < m; i++) avg_label_size += label_sizes[i*dim]+label_sizes[i*dim+1];
- /* for (i = 0; i < m; i++) avg_label_size += 2*MAX(label_sizes[i*dim],label_sizes[i*dim+1]);*/
- avg_label_size /= m;
+ for (i = 0; i < A->m; i++) avg_label_size += label_sizes[i*dim]+label_sizes[i*dim+1];
+ /* for (i = 0; i < A->m; i++) avg_label_size += 2*MAX(label_sizes[i*dim],label_sizes[i*dim+1]);*/
+ avg_label_size /= A->m;
scale_to_edge_length(dim, A, x, -initial_scaling*avg_label_size);
- }
- else if (initial_scaling > 0) {
+ } else if (initial_scaling > 0){
scale_to_edge_length(dim, A, x, initial_scaling);
}
- if (!ntry) return;
+ if (!ntry) return;
*flag = 0;
_statistics[0] = _statistics[1] = 0.;
{FILE*fp;
fp = fopen("x1","w");
- for (i = 0; i < m; i++){
+ for (i = 0; i < A->m; i++){
fprintf(fp, "%f %f\n",x[i*2],x[i*2+1]);
}
fclose(fp);
}
#endif
+#ifdef ANIMATE
+ {FILE*fp;
+ fp = fopen("/tmp/m","wa");
+ fprintf(fp,"{");
+#endif
+ has_penalty_terms = (edge_labeling_scheme != ELSCHEME_NONE && n_constr_nodes > 0);
for (i = 0; i < ntry; i++){
- if (Verbose) print_bounding_box(m, dim, x);
- sm = OverlapSmoother_new(A, m, dim, lambda, x, label_sizes, include_original_graph, neighborhood_only,
- &max_overlap, &min_overlap, shrink);
+ if (Verbose) print_bounding_box(A->m, dim, x);
+ sm = OverlapSmoother_new(A, A->m, dim, lambda, x, label_sizes, include_original_graph, neighborhood_only,
+ &max_overlap, &min_overlap, edge_labeling_scheme, n_constr_nodes, constr_nodes, A_constr, shrink);
if (Verbose) fprintf(stderr, "overlap removal neighbors only?= %d iter -- %d, overlap factor = %g underlap factor = %g\n", neighborhood_only, i, max_overlap - 1, min_overlap);
- if (max_overlap <= 1){
+ if (check_convergence(max_overlap, res, has_penalty_terms, epsilon)){
+
OverlapSmoother_delete(sm);
if (neighborhood_only == FALSE){
break;
} else {
+ res = LARGE;
neighborhood_only = FALSE; shrink = 1;
continue;
}
}
- OverlapSmoother_smooth(sm, dim, x);
-
+ res = OverlapSmoother_smooth(sm, dim, x);
+ if (Verbose) fprintf(stderr,"res = %f\n",res);
+#ifdef ANIMATE
+ if (i != 0) fprintf(fp,",");
+ export_embedding(fp, dim, A, x, label_sizes);
+#endif
+ OverlapSmoother_delete(sm);
+ }
+ if (Verbose)
+ fprintf(stderr, "overlap removal neighbors only?= %d iter -- %d, overlap factor = %g underlap factor = %g\n", neighborhood_only, i, max_overlap - 1, min_overlap);
+#ifdef ANIMATE
+ fprintf(fp,"}");
+ fclose(fp);
+ }
+#endif
- OverlapSmoother_delete(sm);
+ if (has_penalty_terms){
+ /* now do without penalty */
+ remove_overlap(dim, A, x, label_sizes, ntry, 0.,
+ ELSCHEME_NONE, 0, NULL, NULL, flag);
}
#ifdef DEBUG
{FILE*fp;
fp = fopen("x2","w");
- for (i = 0; i < m; i++){
+ for (i = 0; i < A->m; i++){
fprintf(fp, "%f %f\n",x[i*2],x[i*2+1]);
}
fclose(fp);
#ifndef OVERLAP_H
#define OVERLAP_H
-#ifdef SMOOTHER
#include "post_process.h"
typedef StressMajorizationSmoother OverlapSmoother;
void OverlapSmoother_delete(OverlapSmoother sm);
-OverlapSmoother OverlapSmoother_new(SparseMatrix A, int m, int dim, real lambda0, real *x, real *width, int include_original_graph, int neighborhood_only,
- real *max_overlap, real *min_overlap, int shrink);
+OverlapSmoother OverlapSmoother_new(SparseMatrix A, int m,
+ int dim, real lambda0, real *x, real *width, int include_original_graph, int neighborhood_only,
+ real *max_overlap, real *min_overlap,
+ int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int shrink
+ );
-void OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x);
+enum {ELSCHEME_NONE = 0, ELSCHEME_PENALTY, ELSCHEME_PENALTY2, ELSCHEME_STRAIGHTLINE_PENALTY, ELSCHEME_STRAIGHTLINE_PENALTY2};
-#else
-#include "SparseMatrix.h"
-#endif
+struct relative_position_constraints_struct{
+ real constr_penalty; /* penalty parameter used in making edge labels as much on the line as possible */
+ int edge_labeling_scheme;/* specifying whether to treat node of the form |edgelabel|* as a special node representing an edge label.
+ 0 (no action, default), 1 (penalty based method to make that kind of node close to the center of its neighbor),
+ 2 (penalty based method to make that kind of node close to the "old" center of its neighbor),
+ 3 (two step process of overlap removal and straightening) */
+ int n_constr_nodes;/*n_constr_nodes: number of nodes that has constraints, these are nodes that is
+ constrained to be close to the average of its neighbors.*/
+ int *constr_nodes;/*constr_nodes: a list of nodes that need to be constrained. If NULL, unused.*/
+ int *irn;/* working arrays to hold the Laplacian of the constrain graph */
+ int *jcn;
+ real *val;
+ SparseMatrix A_constr; /*A_constr: neighbors of node i are in the row i of this matrix. i needs to sit
+ in between these neighbors as much as possible. this must not be NULL
+ if constr_nodes != NULL.*/
+
+};
+
+typedef struct relative_position_constraints_struct* relative_position_constraints;
+
+real OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x);
+
+void remove_overlap(int dim, SparseMatrix A, real *x, real *label_sizes, int ntry, real initial_scaling,
+ int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int *flag);
-void remove_overlap(int dim, SparseMatrix A, int m, real *x, real *label_sizes, int ntry, real initial_scaling, int *flag);
#endif