Remove uses of anaphora
[cl-graph.git] / dev / graphviz / graphviz-support.lisp
index e07e661..eda1187 100644 (file)
@@ -2,20 +2,14 @@
 
 #| simple-header
 
-$Id: graphviz-support.lisp,v 1.7 2005/06/21 20:51:51 moody Exp $
-
-Copyright 1992 - 2005 Experimental Knowledge Systems Lab, 
-University of Massachusetts Amherst MA, 01003-4610
-Professor Paul Cohen, Director
-
-Author: Gary King, Levente Mészáros, Attila Lendvai
+Author: Gary King, Levente Mészáros, Attila Lendvai
 
 DISCUSSION
 
 This file contains the stuff that does not depend on cl-graphviz.
 
 |#
-(in-package metabang.graph)
+(in-package #:metabang.graph)
 
 ;;; ---------------------------------------------------------------------------
 ;
@@ -24,15 +18,16 @@ This file contains the stuff that does not depend on cl-graphviz.
 ; "GRAPHVIZ".
 ;
 (defmethod graph->dot ((g basic-graph) (stream stream)
-                       &key 
+                       &key
                        (graph-formatter 'graph->dot-properties)
                        (vertex-key 'vertex-id)
                        (vertex-labeler nil)
                        (vertex-formatter 'vertex->dot)
-                       (edge-key nil)
                        (edge-labeler 'princ) 
-                       (edge-formatter 'edge->dot))
-  (format stream "~A G {~%graph " (if (contains-undirected-edge-p g) "graph" "digraph"))
+                       (edge-formatter 'edge->dot)
+                       &allow-other-keys)
+  (format stream "~A G {~%graph " 
+         (if (contains-undirected-edge-p g) "graph" "digraph"))
   (format stream "[")
   (funcall graph-formatter g stream)
   (format stream "];")
@@ -65,7 +60,7 @@ This file contains the stuff that does not depend on cl-graphviz.
              (princ " [" stream)
              (when (and directed? directed-edge-tag)
                (princ directed-edge-tag stream))
-             (when edge-key
+             (when edge-labeler
                (princ "label=\"" stream)
                (funcall edge-labeler e stream)
                (princ "\"," stream))
@@ -87,9 +82,11 @@ This file contains the stuff that does not depend on cl-graphviz.
         (iterate-vertexes 
          g
          (lambda (v)
+          ;(spy v)
            (iterate-edges
             v
             (lambda (e)
+             ;(spy e (undirected-edge-p e) (item-at-1 edges e))
               (when (and (undirected-edge-p e)
                          (not (item-at-1 edges e)))
                 (setf (item-at-1 edges e) t)
@@ -243,14 +240,16 @@ B--D []
 |#
 
 (defparameter *dot-graph-attributes*
-  '((:size coord)
+  '((:size coordinate)
     (:bb bounding-box)
     (:page text)
+    (:dpi float)
     (:ratio (:fill :compress :auto)) ;; Could actually be a float number too
     (:margin float)
     (:nodesep float)
     (:ranksep float)
     (:ordering (:out))
+    (:overlap text)
     (:rankdir ("LR" "RL" "BT"))
     (:pagedir text)
     (:rank (:same :min :max))
@@ -260,12 +259,14 @@ B--D []
     (:mclimit float)
     (:layers text)
     (:color text)
-    (:bgcolor text)))
+    (:bgcolor text)
+    (:fontname text)))
 
 (defparameter *dot-vertex-attributes*
   '((:pos coordinate)
     (:height float)
     (:width float)
+    (:margin float)
     (:fixed-size boolean)
     (:label text)
     (:shape (:record :plaintext :ellipse :circle :egg :triangle :box
@@ -273,10 +274,13 @@ B--D []
              :doublecircle))
     (:fontsize integer)
     (:fontname text)
+    (:fontcolor text)
     (:color text)
     (:fillcolor text)
     (:style (:filled :solid :dashed :dotted :bold :invis))
-    (:layer text)))
+    (:layer text)
+    (:url text)
+    (:peripheries integer)))
 
 (defparameter *dot-edge-attributes*
   '((:pos spline)
@@ -315,42 +319,59 @@ B--D []
   (:export-p t))
 
 (defclass* dot-graph-mixin (dot-attributes-mixin) ()
-  (:export-p t))
+  (:export-p t)
+  (:default-initargs
+    :vertex-class 'dot-vertex
+    :directed-edge-class 'dot-directed-edge
+    :undirected-edge-class 'dot-edge))
 (defclass* dot-vertex-mixin (dot-attributes-mixin) ()
   (:export-p t))
 (defclass* dot-edge-mixin (dot-attributes-mixin) ()
   (:export-p t))
 
-(defclass* dot-graph (graph-container dot-graph-mixin)
+(defclass* dot-graph (dot-graph-mixin graph-container)
   ()
-  (:default-initargs
-    :vertex-class 'dot-vertex
-    :directed-edge-class 'dot-directed-edge
-    :undirected-edge-class 'dot-edge)
   (:export-p t))
 
-(defclass* dot-vertex (graph-container-vertex dot-vertex-mixin) ()
+(defclass* dot-vertex (dot-vertex-mixin graph-container-vertex) ()
   (:export-p t))
-(defclass* dot-edge (graph-container-edge dot-edge-mixin) ()
+(defclass* dot-edge (dot-edge-mixin graph-container-edge) ()
   (:export-p t))
-(defclass* dot-directed-edge (directed-edge-mixin dot-edge) ()
+(defclass* dot-directed-edge (dot-edge directed-edge-mixin) ()
   (:export-p t))
 
 
-(defmethod (setf dot-attribute) :before (value (attr symbol) (thing dot-attributes-mixin))
+(defmethod (setf dot-attribute-value) :before (value (attr symbol) (thing dot-attributes-mixin))
+  (declare (ignore value))
   (ensure-valid-dot-attribute attr thing))
 
-(defmethod (setf dot-attribute) (value (attr symbol) (thing dot-attributes-mixin))
+(defmethod (setf dot-attribute-value) (value (attr symbol) (thing dot-attributes-mixin))
   (setf (getf (dot-attributes thing) attr) value))
 
 (defmethod dot-attribute-value ((attr symbol) (thing dot-attributes-mixin))
   (getf (dot-attributes thing) attr))
 
+(defmacro defpixel-inch-accessors (name attr type)
+  (bind ((actual-name (form-symbol name "-IN-PIXELS")))
+    `(progn
+       (eval-always (export ',actual-name))
+      (defmethod ,actual-name ((thing ,type))
+        "Return the attribute in pixels assuming 72 dpi"
+        (when (dot-attribute-value ,attr thing)
+          (* 72 (dot-attribute-value ,attr thing))))
+      (defmethod (setf ,actual-name) (value (thing ,type))
+        "Set the attribute in pixels assuming 72 dpi"
+        (setf (dot-attribute-value ,attr thing)
+             (coerce (/ value 72) 'double-float))))))
+
+(defpixel-inch-accessors width :width dot-vertex-mixin)
+(defpixel-inch-accessors height :height dot-vertex-mixin)
+
+
 (defmethod graph->dot-properties ((graph dot-graph-mixin) (stream t))
   (loop for (name value) on (dot-attributes graph) by #'cddr
         do
-        (print-dot-key-value name value *dot-graph-attributes* stream)
-        (format stream "                 ;~%")))
+        (print-dot-key-value name value *dot-graph-attributes* stream)))
 
 (defmethod vertex->dot ((vertex dot-vertex-mixin) (stream t))
   (format-dot-attributes vertex *dot-vertex-attributes* stream))
@@ -380,7 +401,8 @@ B--D []
   (destructuring-bind (key value-type)
       (or (assoc key dot-attributes)
           (error "Invalid attribute ~S" key))
-    (format stream "~a=~a" (string-downcase key)
+    (write-name-for-dot key stream)
+    (format stream "=~a" 
             (etypecase value-type
               ((member coordinate)
                (with-output-to-string (str)
@@ -392,7 +414,7 @@ B--D []
                      (princ el str)
                      (setf first nil)))
                  (princ "\"" str)))
-              ((member spline bounding-box)
+              ((member spline)
                (with-output-to-string (str)
                  (princ "\"" str)
                  (let ((first t))
@@ -404,6 +426,18 @@ B--D []
                      (princ (second el) str)
                      (setf first nil)))
                  (princ "\"" str)))
+              ((member bounding-box)
+               (with-output-to-string (str)
+                 (princ "\"" str)
+                 (let ((first t))
+                   (dolist (el value)
+                     (unless first
+                       (princ ", " str))
+                     (princ (first el) str)
+                     (princ "," str)
+                     (princ (second el) str)
+                     (setf first nil)))
+                 (princ "\"" str)))
               ((member integer)
                (unless (typep value 'integer)
                  (error "Invalid value for ~S: ~S is not an integer"
@@ -416,7 +450,9 @@ B--D []
               ((member text)
                (textify value))
               ((member float)
-               (coerce value 'single-float))
+               ;; graphviz does not support the 1.2e-3 format
+               (with-output-to-string (str)
+                 (format str "~,f" (coerce value 'single-float))))
               (list
                (unless (member value value-type :test 'equal)
                  (error "Invalid value for ~S: ~S is not one of ~S"
@@ -425,6 +461,12 @@ B--D []
                    (string-downcase value)
                    value))))))
 
+(defmethod write-name-for-dot (attribute stream)
+  (format stream "~(~A~)" attribute))
+
+(defmethod write-name-for-dot ((attribute (eql :url)) stream)
+  (format stream "URL"))
+
 (defun textify (object)
   (let ((string (princ-to-string object)))
     (with-output-to-string (stream)
@@ -455,8 +497,10 @@ B--D []
 (defmethod graph->dot-external ((g basic-graph) file-name &key (type :ps))
   "Generate an external represenation of a graph to a file, by running
 the program in *dot-path*."
+  (declare (ignorable file-name))
   (let ((dot-string (graph->dot g nil))
         (dot-type (concatenate 'string "-T" (string-downcase (symbol-name type)))))
+    (declare (ignorable dot-string dot-type))
     #+lispworks (with-open-stream
                     (s (sys:open-pipe (concatenate 'string *dot-path* " -Tpng -o" file-name)
                                       :direction :input))