]> granicus.if.org Git - graphviz/commitdiff
added a new algorithm for remove node overlap, main code is overlap.c, which utilize...
authoryifanhu <devnull@localhost>
Mon, 4 Feb 2008 20:26:54 +0000 (20:26 +0000)
committeryifanhu <devnull@localhost>
Mon, 4 Feb 2008 20:26:54 +0000 (20:26 +0000)
lib/sfdpgen/overlap.c [new file with mode: 0644]

diff --git a/lib/sfdpgen/overlap.c b/lib/sfdpgen/overlap.c
new file mode 100644 (file)
index 0000000..70419fe
--- /dev/null
@@ -0,0 +1,208 @@
+#include "general.h"
+#include "SparseMatrix.h"
+#include "spring_electrical.h"
+#include "post_process.h"
+#include "overlap.h"
+#include "call_tri.h"
+
+static void ideal_distance_avoid_overlap(int dim, real pad, SparseMatrix A, real *x, real *width, real *ideal_distance, real *tmax){
+  /*  if (x1>x2 && y1 > y2) we want either x1 + t (x1-x2) - x2 > pad + (width1+width2), or y1 + t (y1-y2) - y2 > pad + (height1+height2),
+      hence t = MAX(expandmin, MIN(expandmax, (pad + width1+width2)/(x1-x2) - 1, (pad + height1+height2)/(y1-y2) - 1)), and
+      new ideal distance = (1+t) old_distance. t can be negative sometimes.
+      The result ideal distance is set to negative if the edge needs shrinking
+  */
+  int i, j, jj;
+  int *ia = A->ia, *ja = A->ja;
+  real dist, dx, dy, wx, wy, t;
+  real expandmax = 1.5, expandmin = 1;
+
+  *tmax = 0;
+  assert(SparseMatrix_is_symmetric(A, FALSE));
+  for (i = 0; i < A->m; i++){
+    for (j = ia[i]; j < ia[i+1]; j++){
+      jj = ja[j];
+      if (jj == i) continue;
+      dist = distance(x, dim, i, jj);
+      dx = ABS(x[i*dim] - x[jj*dim]);
+      dy = ABS(x[i*dim+1] - x[jj*dim+1]);
+      wx = pad + width[i*dim]+width[jj*dim];
+      wy = pad + width[i*dim+1]+width[jj*dim+1];
+      if (dx < MACHINEACC*wx && dy < MACHINEACC*wy){
+       ideal_distance[j] = sqrt(wx*wx+wy*wy);
+       *tmax = 2;
+      } else {
+       if (dx < MACHINEACC*wx){
+         t = wy/dy;
+       } else if (dy < MACHINEACC*wy){
+         t = wx/dx;
+       } else {
+         t = MIN(wx/dx, wy/dy);
+       }
+       if (t > 1) t = MAX(t, 1.001);/* no point in things like t = 1.00000001 as this slow down convergence */
+       *tmax = MAX(*tmax, t);
+       t = MIN(expandmax, t);
+       t = MAX(expandmin, t);
+       if (t > 1) {
+         ideal_distance[j] = t*dist;
+       } else {
+         ideal_distance[j] = -t*dist;
+       }
+      }
+
+    }
+  }
+  return;
+}
+
+
+
+/* ============================== label overlap smoother ==================*/
+
+
+OverlapSmoother OverlapSmoother_new(SparseMatrix A, int dim, real lambda0, real *x, real *width, int include_original_graph,
+                                   real *max_overlap){
+  OverlapSmoother sm;
+  int i, j, k, m = A->m, *iw, *jw, *id, *jd, jdiag;
+  SparseMatrix B;
+  real *lambda, *d, *w, diag_d, diag_w, dist, pad = 0;
+
+  assert(SparseMatrix_is_symmetric(A, FALSE));
+
+  sm = MALLOC(sizeof(struct OverlapSmoother_struct));
+  lambda = sm->lambda = MALLOC(sizeof(real)*m);
+  for (i = 0; i < m; i++) sm->lambda[i] = lambda0;
+  
+  if (m > 2){
+    B= call_tri(m, dim, x);
+  } else {
+    B = SparseMatrix_copy(A);
+  }
+
+  if (include_original_graph){
+    sm->Lw = SparseMatrix_add(A, B);
+    SparseMatrix_delete(B);
+  } else {
+    sm->Lw = B;
+  }
+  sm->Lwd = SparseMatrix_copy(sm->Lw);
+
+  {FILE *fp;
+  fp = fopen("/tmp/111","w");
+  export_embedding(fp, dim, sm->Lwd, x);
+  fclose(fp);}
+
+
+  if (!(sm->Lw) || !(sm->Lwd)) {
+    OverlapSmoother_delete(sm);
+    return NULL;
+  }
+
+  assert((sm->Lwd)->type == MATRIX_TYPE_REAL);
+  
+  ideal_distance_avoid_overlap(dim, pad, sm->Lwd, x, width, (real*) (sm->Lwd->a), max_overlap);
+
+  /* no overlap at all! */
+  if (*max_overlap < 1){
+    for (i = 0; i < dim*m; i++) {
+      x[i] *= (*max_overlap);
+    }
+    goto RETURN;
+  }
+
+  iw = sm->Lw->ia; jw = sm->Lw->ja;
+  id = sm->Lwd->ia; jd = sm->Lwd->ja;
+  w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a;
+
+  for (i = 0; i < m; i++){
+    diag_d = diag_w = 0;
+    jdiag = -1;
+    for (j = iw[i]; j < iw[i+1]; j++){
+      k = jw[j];
+      if (k == i){
+       jdiag = j;
+       continue;
+      }
+      if (d[j] > 0){/* those edges that needs expansion */
+       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];
+       d[j] = -d[j];
+      }
+      dist = d[j];
+      diag_w += w[j];
+      d[j] = w[j]*dist;
+      diag_d += d[j];
+
+    }
+
+    lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */
+
+    assert(jdiag >= 0);
+    w[jdiag] = -diag_w + lambda[i];
+    d[jdiag] = -diag_d;
+  }
+ RETURN:
+  return sm;
+}
+
+void OverlapSmoother_delete(OverlapSmoother sm){
+
+  StressMajorizationSmoother_delete(sm);
+
+}
+
+void OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x){
+
+  StressMajorizationSmoother_smooth(sm, dim, x);
+  {FILE *fp;
+  fp = fopen("/tmp/222","w");
+  export_embedding(fp, dim, sm->Lwd, x);
+  fclose(fp);}
+
+}
+
+/*================================= end OverlapSmoother =============*/
+
+static void scale_to_edge_length(int dim, SparseMatrix A, real *x, real avg_label_size){
+  real dist;
+  int i;
+
+  dist = average_edge_length(A, dim, x);
+  fprintf(stderr,"avg edge len=%f avg_label-size= %f\n", dist, avg_label_size);
+
+
+  dist = avg_label_size/MAX(dist, MACHINEACC);
+
+  for (i = 0; i < dim*A->m; i++) x[i] *= dist;
+}
+
+void remove_overlap(int dim, SparseMatrix A, real *x, real *label_sizes, int ntry, int *flag){
+  real lambda = 0.00;
+  OverlapSmoother sm;
+  int include_original_graph = 0, i;
+  real avg_label_size;
+  real max_overlap = FALSE;
+
+  if (!label_sizes) return;
+
+  avg_label_size = 0;
+  for (i = 0; i < A->m; i++) avg_label_size += label_sizes[i*dim]+label_sizes[i*dim+1];
+  avg_label_size /= A->m;
+
+  scale_to_edge_length(dim, A, x,4*avg_label_size);
+
+  *flag = 0;
+
+  for (i = 0; i < ntry; i++){
+    sm = OverlapSmoother_new(A, dim, lambda, x, label_sizes, include_original_graph, &max_overlap); 
+    fprintf(stderr, "try %d, tmax = %f\n", i, max_overlap);
+
+    if (max_overlap <= 1){
+      OverlapSmoother_delete(sm);
+      break;
+    }
+    OverlapSmoother_smooth(sm, dim, x);
+    OverlapSmoother_delete(sm);
+  }
+
+}