PreviousUpNext

15.4.1039  src/lib/std/dot/dotgraph-to-planargraph.pkg

## dotgraph-to-planargraph.pkg

# Compiled by:
#     src/lib/std/standard.lib

# Dot-graphs are the raw abstract graphs as read in from disk.
# planar-graphs are the same graphs embedded in a plane for drawing.
# (See ../GRAPHS.OVERVIEW.)

stipulate
    package dg  =  dot_graphtree;                       # dot_graphtree                 is from   src/lib/std/dot/dot-graphtree.pkg
    package dt  =  dot_graphtree_traits;                # dot_graphtree_traits          is from   src/lib/std/dot/dot-graphtree-traits.pkg
    package f8b =  eight_byte_float;                    # eight_byte_float              is from   src/lib/std/eight-byte-float.pkg
    package gf  =  geometry2d_float;                    # geometry2d_float              is from   src/lib/std/2d/geometry2d-float.pkg
    package pg  =  planar_graphtree;                    # planar_graphtree              is from   src/lib/std/dot/planar-graphtree.pkg
    package g2d =  geometry2d;                          # geometry2d                    is from   src/lib/std/2d/geometry2d.pkg
herein

    package   dotgraph_to_planargraph
    :         Dotgraph_To_Planargraph
    {
        default_font_size = 14;                         # This was in view-font.pkg, moved here to eliminate dependency on X-dependent code.

        fun divscale (n, { wide, high } )
            =
            { col => wide / n,
              row => high / n
            };


        fun bind_view_node (ppf, prf, vg) node
            =
            {   name =  dg::node_name  node;

                case (pg::find_node (vg, name))
                    #
                    NULL =>
                        {   my  { center, size, label, shape, ... }
                                =
                                *(dg::node_info_of  node);

                            bbox = g2d::box::make
                                     ( g2d::point::subtract (center, divscale (2, size)),
                                       size
                                     );

                            trait
                                =
                                { position =>  ppf center,
                                  bbox     =>  prf bbox,
                                  base     =>  node,
                                  shape,
                                  label
                                };

                            pg::make_node (vg, name, THE trait);
                        };

                    THE nn => nn;

                esac;
            };


        stipulate

            arrowl = 10;                        # "arrow length" ?
            arroww = 7;                         # "arrow width"  ?

    #   pi_2   =  1.57079632679489661923;
    #   pi     =  3.14159265358979323846;
    #
    #   fun atan2 (y, 0.0)
    #           =>
    #           if   (y == 0.0)   0.0;
    #                elif (y  > 0.0)   pi_2;
    #                else             -pi_2;
    #                fi;
    #
    #       atan2 (y, x)
    #           =>
    #           if   (x >  0.0)  arctan (y/x);
    #           elif (y >= 0.0)  arctan (y/x) + pi;
    #           else             arctan (y/x) - pi;
    #           fi;
    #   end;  

        herein

            fun make_arrow
                  (      { x=>x', y=>y'}: gf::Point,
                    p as { x,     y    }: gf::Point,
                    arrowl,
                    arroww
                  )
                    =
                    {   delx = x'-x;
                        dely = y'-y;
                                                                    # math              is from   src/lib/std/src/bind-math-32.pkg
                        theta = math::atan2 (dely, delx);
                        costh = math::cos theta;
                        sinth = math::sin theta;

                        sp =           { x => x + (arrowl*costh + arroww*sinth),
                                         y => y + (arrowl*sinth - arroww*costh)
                                       };

                        ep =           { x => x + (arrowl*costh - arroww*sinth),
                                         y => y + (arrowl*sinth + arroww*costh)
                                       };

                        [sp, p, ep];
                    };

            fun make_view_node (scale_float, scale_point, scale_box, g, vg) 
                =
                {
                    bind_v_node = bind_view_node (scale_point, scale_box, vg);

                    fun last [a]     =>  a;
                        last (_ ! t) =>  last t;
                        last []      =>  raise exception lib_base::IMPOSSIBLE "dotgraph_to_vgraph::make_view_node";
                    end;

                    arrowl =  scale_float arrowl;
                    arroww = (scale_float arroww) / 2.0;

                    fun make_edge  tnode  edge
                        =
                        {   hnode = bind_v_node (dg::head edge);

                            (*(dg::edge_info_of edge))
                                ->
                                { points, arrow };
                                

                            info_points = map scale_point (points @ [arrow]);

                            arrowhead = make_arrow (scale_point (last points), scale_point arrow, arrowl, arroww);

                            info = { bbox   =>  gf::bound_box (arrowhead @ info_points),
                                     points =>  info_points,
                                     arrowhead
                                   };

                            pg::make_edge { graph=>vg, tail=>tnode, head=>hnode, info=>THE info };

                            ();
                        };

                    \\ n = dg::out_edges_apply (make_edge( bind_v_node n)) (g, n);
                };
        end;

        fun convert_dotgraph_to_planargraph  graph
            =
            {   (*(dg::graph_info_of  graph))
                    ->
                    { bbox => { wide=>gwid, high=>ght }, scale, ... };

                fun scale_float x
                    =
                    scale * (f8b::from_int x);

                fun scale_point ({ col=>x, row=>y } )
                    =
                    { x=>scale_float x, y=>scale_float (ght-y) };

                fun scale_box ({ col=>x, row=>y, wide, high } )
                    =
                    gf::BOX
                      { x =>  scale_float x,
                        y =>  scale_float (ght-(y+high)),
                        #
                        wide =>  scale_float wide,
                        high =>  scale_float high
                      };

                fun pick_node g
                      =
                      {   exception DONE;

                          my nodes:  Ref( List( dg::Node ) )
                              =
                              REF [];

                          fun pick n
                              =
                              {   nodes := [n];
                                  raise exception DONE;
                              };

                          dg::nodes_apply pick g
                          except
                              DONE = ();

                          list::head *nodes;
                      };

                graph_info
                    = { graph,

                        fontsize    =>  f8b::truncate (scale_float default_font_size),

                        graph_bbox  =>  gf::BOX { x => 0.0,
                                                  y => 0.0,
                                                  #
                                                  wide => scale_float gwid,
                                                  high => scale_float ght
                                                }
                      };

                picknode = pick_node  graph;

                default_node_info
                    =
                    { position =>  gf::point_zero,
                      bbox     =>  gf::BOX { x=>0.0, y=>0.0, wide=>0.0, high=>0.0 },
                      shape    =>  dt::BOX,
                      base     =>  picknode,
                      label    =>  ""
                    };

                default_edge_info
                    =
                    { points      =>  [],
                      arrowhead   =>  [],
                      bbox        =>  gf::BOX { x => 0.0,
                                                y => 0.0,
                                                wide => scale_float gwid,
                                                high => scale_float ght
                                              }
                    };

                vg = pg::make_graph
                       {
                         name =>  dg::graph_name  graph, 
                         info =>  THE graph_info,
                         #
                         make_default_graph_info =>  {. graph_info;        },
                         make_default_node_info  =>  {. default_node_info; },
                         make_default_edge_info  =>  {. default_edge_info; }
                       };

                dg::nodes_apply
                    (make_view_node (scale_float, scale_point, scale_box, graph, vg))
                    graph;

                vg;
            };

    };                          # package vgraph_aux 
end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext