From: erg <devnull@localhost>
Date: Wed, 29 Apr 2009 00:48:48 +0000 (+0000)
Subject: Add support for mds model, in which user-supplied edge distances are
X-Git-Tag: LAST_LIBGRAPH~32^2~2133
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a99fedd494dbfbd7ecb005b267087f52d207bbe7;p=graphviz

Add support for mds model, in which user-supplied edge distances are
used rather than weighted shortest paths.
---

diff --git a/lib/neatogen/stress.h b/lib/neatogen/stress.h
index f138058de..3efed4d27 100644
--- a/lib/neatogen/stress.h
+++ b/lib/neatogen/stress.h
@@ -60,6 +60,7 @@ extern "C" {
 extern float *compute_apsp_packed(vtx_data * graph, int n);
 extern float *compute_apsp_artifical_weights_packed(vtx_data * graph, int n);
 extern float* circuitModel(vtx_data * graph, int nG);
+extern float* mdsModel (vtx_data * graph, int nG);
 extern int initLayout(vtx_data * graph, int n, int dim, double **coords, node_t** nodes);
 
 #endif
diff --git a/lib/neatogen/stuff.c b/lib/neatogen/stuff.c
index a5cc3fd79..284c4378f 100644
--- a/lib/neatogen/stuff.c
+++ b/lib/neatogen/stuff.c
@@ -116,23 +116,34 @@ static void free_3array(double ***rv)
 }
 
 
+/* lenattr:
+ * Return 1 if attribute not defined
+ * Return 2 if attribute string bad
+ */
 #ifdef WITH_CGRAPH
-static double doubleattr(void *obj, Agsym_t* index, double defval)
+static int lenattr(edge_t* e, Agsym_t* index, double* val)
 #else
-static double doubleattr(void *obj, int index, double defval)
+static int lenattr(edge_t* e, int index, double* val)
 #endif
 {
-    double val;
+    char* s;
 
 #ifdef WITH_CGRAPH
     if (index == NULL)
 #else
     if (index < 0)
 #endif
-	return defval;
-    if (sscanf(agxget(obj, index), "%lf", &val) < 1)
-	return defval;
-    return val;
+	return 1;
+
+    s = agxget(e, index);
+    if (*s == '\0') return 1;
+
+    if ((sscanf(s, "%lf", val) < 1) || (*val < 0) || ((*val == 0) && !Nop)) {
+	agerr(AGWARN, "bad edge len \"%s\"", s);
+	return 2;
+    }
+    else
+	return 0;
 }
 
 
@@ -202,20 +213,20 @@ static node_t *prune(graph_t * G, node_t * np, node_t * next)
 }
 
 #ifdef WITH_CGRAPH
-static double setEdgeLen(graph_t * G, node_t * np, Agsym_t* lenx)
+static double setEdgeLen(graph_t * G, node_t * np, Agsym_t* lenx, double dfltlen)
 #else
-static double setEdgeLen(graph_t * G, node_t * np, int lenx)
+static double setEdgeLen(graph_t * G, node_t * np, int lenx, double dfltlen)
 #endif
 {
     edge_t *ep;
     double total_len = 0.0;
-    double len=0;
+    double len;
+    int err;
 
     for (ep = agfstout(G, np); ep; ep = agnxtout(G, ep)) {
-	len = doubleattr(ep, lenx, 1.0);
-	if ((len < 0) || ((len == 0) && !Nop)) {
-	    agerr(AGWARN, "bad edge len %f in %s - set to 1\n", len, agnameof(G));
-	    len = 1.0;
+	if ((err = lenattr(ep, lenx, &len))) {
+	    if (err == 2) agerr(AGPREV, " in %s - setting to %.02f\n", agnameof(G), dfltlen);
+	    len = dfltlen;
 	}
 	ED_dist(ep) = len;
 	total_len += len;
@@ -235,6 +246,7 @@ int scan_graph_mode(graph_t * G, int mode)
     char *str;
     node_t *np, *xp, *other;
     double total_len = 0.0;
+    double dfltlen = 1.0;
 #ifdef WITH_CGRAPH
     Agsym_t* lenx;
 #else
@@ -245,6 +257,7 @@ int scan_graph_mode(graph_t * G, int mode)
 	fprintf(stderr, "Scanning graph %s, %d nodes\n", agnameof(G),
 		agnnodes(G));
 
+
     /* Eliminate singletons and trees */
     if (Reduce) {
 	for (np = agfstnode(G); np; np = xp) {
@@ -279,14 +292,14 @@ int scan_graph_mode(graph_t * G, int mode)
 	    GD_neato_nlist(G)[i] = np;
 	    ND_id(np) = i++;
 	    ND_heapindex(np) = -1;
-	    total_len += setEdgeLen(G, np, lenx);
+	    total_len += setEdgeLen(G, np, lenx, dfltlen);
 	}
     } else {
 	Epsilon = DFLT_TOLERANCE;
 	getdouble(G, "epsilon", &Epsilon);
 	for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
 	    ND_id(np) = i++;
-	    total_len += setEdgeLen(G, np, lenx);
+	    total_len += setEdgeLen(G, np, lenx, dfltlen);
 	}
     }