| 1 | % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(dot_graph_generator, [gen_dot_graph/3, gen_dot_graph/5, gen_dot_graph/6, | |
| 6 | dot_no_same_rank/1, dot_no_subgraph/3, | |
| 7 | print_graph_header/1,print_graph_footer/0, | |
| 8 | use_new_dot_attr_pred/7, % annotation for new-style dot predicate | |
| 9 | get_dot_cluster_name/2, | |
| 10 | translate_bvalue_to_colour/2, try_translate_bvalue_to_colour/2, | |
| 11 | translate_int_col/2]). | |
| 12 | ||
| 13 | :- meta_predicate(gen_dot_graph(*,6,5)). | |
| 14 | :- meta_predicate(gen_dot_graph(*,6,5,1,3)). | |
| 15 | :- meta_predicate(gen_dot_graph(*,*,6,5,1,3)). | |
| 16 | :- meta_predicate(node_id(6,*)). | |
| 17 | :- meta_predicate(node_predicate_call(6,*,*,*)). | |
| 18 | :- meta_predicate(trans_predicate_call(:,*,*,*,*,*)). % adds 3 or 5 args | |
| 19 | :- meta_predicate(merged_call5(5,*,*,*,*,*)). % adds 5 args | |
| 20 | :- meta_predicate(same_rank_call(1,*)). | |
| 21 | :- meta_predicate(subgraph_call(3,*,*,*,*,*)). | |
| 22 | :- meta_predicate(fgen_dot_graph(*,*,6,5,1,3)). | |
| 23 | :- meta_predicate(print_nodes(*,6,3)). | |
| 24 | :- meta_predicate(print_nodes2(*,*,6)). | |
| 25 | :- meta_predicate(print_transitions(*,*,*,5)). | |
| 26 | ||
| 27 | :- use_module(probsrc(module_information)). | |
| 28 | :- module_info(group,dot). | |
| 29 | :- module_info(description,'This a few tools for generating dot graphs.'). | |
| 30 | ||
| 31 | :- use_module(library(lists)). | |
| 32 | :- use_module(probsrc(preferences)). | |
| 33 | ||
| 34 | :- use_module(probsrc(debug)). | |
| 35 | :- use_module(probsrc(self_check)). | |
| 36 | :- use_module(probsrc(error_manager),[add_internal_error/2, add_message/3]). | |
| 37 | ||
| 38 | /* --------------------------------------------------- */ | |
| 39 | /* MAIN ENTRY POINTS FOR TCL */ | |
| 40 | /* --------------------------------------------------- */ | |
| 41 | ||
| 42 | gen_dot_graph(F,NodePredicate,TransPredicate) :- | |
| 43 | gen_dot_graph(F,NodePredicate,TransPredicate,dot_no_same_rank,dot_no_subgraph). | |
| 44 | gen_dot_graph(F,NodePredicate,TransPredicate,SameRankPred,SubGraphPred) :- | |
| 45 | gen_dot_graph(F,[],NodePredicate,TransPredicate,SameRankPred,SubGraphPred). | |
| 46 | ||
| 47 | gen_dot_graph(F,GraphAttrs,NodePredicate,TransPredicate,SameRankPred,SubGraphPred) :- | |
| 48 | formatsilent('% Generating Dot File: ~w~n',[F]), | |
| 49 | reset_ids, | |
| 50 | (get_preference(dot_horizontal_layout,true), | |
| 51 | \+ has_attribute(rankdir,_,GraphAttrs) -> Opts0 = [rankdir/'LR'|GraphAttrs] ; Opts0 = GraphAttrs), | |
| 52 | (select(no_page_size,Opts0,Opts) -> true | |
| 53 | ; get_preference(dot_with_page_size,true), | |
| 54 | \+ has_attribute(page,_,GraphAttrs), | |
| 55 | \+ has_attribute(size,_,GraphAttrs) | |
| 56 | -> Opts = [with_page_size|Opts0] | |
| 57 | ; Opts = Opts0), | |
| 58 | open(F,write,FStream,[encoding(utf8)]), | |
| 59 | (fgen_dot_graph(FStream,Opts,NodePredicate,TransPredicate,SameRankPred,SubGraphPred) -> true ; true), | |
| 60 | close(FStream), | |
| 61 | formatsilent('% Done~n',[]). | |
| 62 | ||
| 63 | ||
| 64 | % Placeholder predicates for when caller doesn't need SameRankPred and/or SubGraphPred | |
| 65 | dot_no_same_rank(_) :- fail. | |
| 66 | dot_no_subgraph(_, _, _) :- fail. | |
| 67 | ||
| 68 | ||
| 69 | node_id(P,TNodeID) :- | |
| 70 | call(P,NodeID,_,_,_,_,_), | |
| 71 | translate_id(NodeID,TNodeID). | |
| 72 | ||
| 73 | node_predicate_call(Pred,TNodeID,SubGraph,Attributes) :- | |
| 74 | get_new_style_node_pred(Pred,NodePredicate),!, | |
| 75 | call(NodePredicate,NodeID,SubGraph,Attributes), % new style has only 3 arguments with flexible attribute list | |
| 76 | translate_id(NodeID,TNodeID). | |
| 77 | node_predicate_call(NodePredicate,TNodeID,SubGraph,[shape/Shape|Attrs]) :- | |
| 78 | call(NodePredicate,NodeID,SubGraph,NodeDesc,Shape,Style,Color), % has 6 arguments | |
| 79 | translate_id(NodeID,TNodeID), | |
| 80 | (Style = none -> Attrs = Attrs2 ; Attrs = [style/Style|Attrs2]), | |
| 81 | (Color = none -> Attrs2 = Attrs3 ; Attrs2 = [color/Color|Attrs3]), | |
| 82 | %preference(dot_print_node_ids,true) -> we are not interested in internal ids of this module, are we?? | |
| 83 | Attrs3 = [label/NodeDesc]. | |
| 84 | ||
| 85 | get_new_style_node_pred(use_new_dot_attr_pred(NodePredicate),NodePredicate). | |
| 86 | get_new_style_node_pred(_:use_new_dot_attr_pred(NodePredicate),NodePredicate). | |
| 87 | ||
| 88 | % convert a new style Node Predicate which returns a flexible list of attributes | |
| 89 | % dummy call: real conversion is done in node_predicate_call | |
| 90 | use_new_dot_attr_pred(NodePredicate,NodeID,SubGraph,none,none,none,none) :- | |
| 91 | call(NodePredicate,NodeID,SubGraph,_Attributes). | |
| 92 | ||
| 93 | ||
| 94 | % ------- | |
| 95 | ||
| 96 | trans_predicate_call(Pred,_Opts,TNodeID,TSuccNodeID,Style,Attrs2) :- | |
| 97 | get_new_style_node_pred(Pred,NodePredicate),!, | |
| 98 | call(NodePredicate,NodeID,SuccNodeID,Attrs), % new style has only 3 arguments with flexible attribute list | |
| 99 | % TODO: allow to merge_transitions with same Attrs except label | |
| 100 | (select_attribute(style,Style,Attrs,Attrs2) -> true ; Style=solid,Attrs2=Attrs), | |
| 101 | translate_id_for_transition(NodeID,TNodeID), | |
| 102 | translate_id_for_transition(SuccNodeID,TSuccNodeID). | |
| 103 | trans_predicate_call(P,Opts,TNodeID,TSuccNodeID,Style,[color/Color,label/Label]) :- | |
| 104 | (has_attribute(merge_transitions,true,Opts) | |
| 105 | -> merged_call5(P,NodeID,Label,SuccNodeID,Color,Style) | |
| 106 | ; call(P,NodeID,Label,SuccNodeID,Color,Style) | |
| 107 | ), | |
| 108 | translate_id_for_transition(NodeID,TNodeID), | |
| 109 | translate_id_for_transition(SuccNodeID,TSuccNodeID). | |
| 110 | ||
| 111 | :- use_module(probsrc(tools_strings),[ajoin_with_sep/3]). | |
| 112 | :- use_module(probsrc(tools_meta),[setof4/4]). | |
| 113 | % merge all labels with the same origin, destination, color and style | |
| 114 | merged_call5(P,NodeID,Label,SuccNodeID,Color,Style) :- | |
| 115 | % we use setof4 rather than setof, because test 1033 fails on Intel platforms due to different order of sols | |
| 116 | setof4(Lbl,[NodeID,SuccNodeID,Color,Style],call(P,NodeID,Lbl,SuccNodeID,Color,Style), Labels), | |
| 117 | ajoin_with_sep(Labels,',',Label). | |
| 118 | ||
| 119 | ||
| 120 | same_rank_call(_:dot_no_same_rank,_) :- !,fail. | |
| 121 | same_rank_call(P,TNodes) :- | |
| 122 | call(P,Nodes), | |
| 123 | Nodes \= [], % empty list provides no information | |
| 124 | maplist(translate_id,Nodes,TNodes). | |
| 125 | /* should succeed once for every set of NodeIDs which should be of same rank */ | |
| 126 | ||
| 127 | % should succeed once for every subgraph and generate a subgraphID which is passed to the node predicate | |
| 128 | subgraph_call(_:dot_no_subgraph,_,_,_,_,_) :- !, fail. | |
| 129 | subgraph_call(P,SubGraphID,Style,Color,Label,OtherAttrs) :- | |
| 130 | call(P,ID,Style,Color), | |
| 131 | extract_new_attrs(ID,SubGraphID,Attrs), | |
| 132 | (select_attribute(label,Label,Attrs,OtherAttrs) -> true | |
| 133 | ; OtherAttrs=Attrs, Label=SubGraphID). | |
| 134 | /* Notes: SubGraphID: should be none if not in a subgraph; Style and Color can be none */ | |
| 135 | ||
| 136 | extract_new_attrs(sub_graph_with_attributes(ID,Attrs),SubGraphID,OtherAttrs) :- | |
| 137 | !, % new style subgraph predicate: additional info | |
| 138 | SubGraphID=ID, OtherAttrs=Attrs. | |
| 139 | extract_new_attrs(ID,ID,[]). % old style subgraph predicate: ID is just an atom | |
| 140 | ||
| 141 | :- dynamic stored_id/2, additional_id/2. | |
| 142 | :- dynamic next_id/1. | |
| 143 | next_id(0). | |
| 144 | ||
| 145 | reset_ids :- | |
| 146 | retractall(stored_id(_,_)), retractall(next_id(_)), | |
| 147 | retractall(additional_id(_,_)), | |
| 148 | assertz(next_id(0)). | |
| 149 | ||
| 150 | % translate ids to atoms; ensure that dot can deal with them | |
| 151 | translate_id(ID,TransID) :- | |
| 152 | (number(ID) -> TransID=ID | |
| 153 | ; var(ID) -> add_internal_error('Illegal variable identifier for dot:',translate_id(ID,TransID)), | |
| 154 | TransID is -1 | |
| 155 | ; stored_id(ID,SID) -> TransID=SID | |
| 156 | ; gen_new_node_id(NewAtom), | |
| 157 | assertz(stored_id(ID,NewAtom)), | |
| 158 | TransID = NewAtom | |
| 159 | ). | |
| 160 | ||
| 161 | gen_new_node_id(NewAtom) :- | |
| 162 | retract(next_id(NextId)), N1 is NextId+1, | |
| 163 | assertz(next_id(N1)), | |
| 164 | number_codes(NextId,NC), | |
| 165 | append("dot_node_",NC,AC), atom_codes(NewAtom,AC). | |
| 166 | ||
| 167 | % called in transition creation: we can no longer add new nodes: | |
| 168 | translate_id_for_transition(ID,TransID) :- | |
| 169 | (number(ID) -> TransID=ID | |
| 170 | ; var(ID) -> add_internal_error('Illegal variable identifier for dot:',translate_id(ID,TransID)), | |
| 171 | TransID is -1 | |
| 172 | ; stored_id(ID,SID) -> TransID=SID | |
| 173 | ; add_message(dot_graph_generator,'Unknown node: ',ID), | |
| 174 | gen_new_node_id(NewAtom), | |
| 175 | assertz(stored_id(ID,NewAtom)), | |
| 176 | assertz(additional_id(NewAtom,ID)), | |
| 177 | TransID=NewAtom | |
| 178 | ). | |
| 179 | ||
| 180 | print_additional_nodes(FStream) :- | |
| 181 | additional_id(DotAtom,OriginalID), | |
| 182 | format(FStream,' ~w [label="~w"];~n',[DotAtom,OriginalID]), | |
| 183 | fail. | |
| 184 | print_additional_nodes(_). | |
| 185 | ||
| 186 | /* ---------------------------------------------------------------------- */ | |
| 187 | ||
| 188 | ||
| 189 | fgen_dot_graph(FStream,GraphAttrs,NodePredicate,TransPredicate,SameRankPred,SubGraphPred) :- | |
| 190 | print_graph_header(FStream,prob_graph,GraphAttrs), | |
| 191 | (node_id(NodePredicate,_) -> true | |
| 192 | ; (format(user_error,"No nodes in gen_dot_graph: ~w, ~w, ~w, ~w.~n~n", | |
| 193 | [NodePredicate,TransPredicate,SameRankPred,SubGraphPred]),fail)), | |
| 194 | print_nodes(FStream,NodePredicate,SubGraphPred), | |
| 195 | fail. | |
| 196 | fgen_dot_graph(FStream,_GraphAttrs,_NodePredicate,_TransPredicate,SameRankPred,_SubGraphPred) :- | |
| 197 | same_rank_call(SameRankPred,Nodes), | |
| 198 | print_same_ranks(FStream,Nodes), | |
| 199 | fail. | |
| 200 | fgen_dot_graph(FStream,GraphAttrs,_NodePredicate,TransPredicate,_SameRankPred,_SubGraphPred) :- | |
| 201 | print_transitions(FStream,_NodeID,GraphAttrs,TransPredicate), | |
| 202 | fail. | |
| 203 | fgen_dot_graph(FStream,_,_,_,_,_) :- | |
| 204 | print_additional_nodes(FStream), | |
| 205 | print_graph_footer(FStream). | |
| 206 | ||
| 207 | /* ---------------------------------------------------------------------- */ | |
| 208 | ||
| 209 | print_graph_header(Type) :- print_graph_header(user_output,Type,[with_page_size]). | |
| 210 | print_graph_header(FStream,Type,Opts) :- | |
| 211 | (select(with_page_size,Opts,Opts1) | |
| 212 | -> Opts2 = [page/'8.5, 11',ratio/fill,size/'7.5,10'|Opts1] | |
| 213 | ; Opts2=Opts), | |
| 214 | (select(directed/'FALSE',Opts2,Opts3) -> GRAPH = 'graph' | |
| 215 | ; Opts3=Opts2, GRAPH = 'digraph' % directed graph | |
| 216 | ), | |
| 217 | (select(strict/'TRUE',Opts3,Opts4) -> STRICT = 'strict ' | |
| 218 | ; Opts4=Opts3, STRICT = '' | |
| 219 | ), | |
| 220 | format(FStream,'~w~w ~w {~n graph [',[STRICT,GRAPH,Type]), | |
| 221 | % graph [AttrList] sets default attributes | |
| 222 | print_dot_attrs(Opts4,FStream), | |
| 223 | format(FStream,'];~n',[]). | |
| 224 | % print('graph [orientation=landscape, page="8.5, 11",ratio=fill,size="7.5,10"];'),nl, | |
| 225 | ||
| 226 | print_graph_footer :- print_graph_footer(user_output). | |
| 227 | print_graph_footer(FStream) :- format(FStream,'}~n',[]). | |
| 228 | ||
| 229 | is_undirected_graph(GraphAttrs) :- member(directed/FALSE,GraphAttrs),!, FALSE='FALSE'. | |
| 230 | ||
| 231 | /* ---------------------------------------------------------------------- */ | |
| 232 | ||
| 233 | :- use_module(probsrc(tools_strings),[ajoin/2]). | |
| 234 | % get the dot name of a logical cluster, also relevant or lhead/ltail edge attributes | |
| 235 | get_dot_cluster_name(SubGraphID,CN) :- ajoin(['cluster_',SubGraphID],CN). | |
| 236 | ||
| 237 | % write dot nodes to a stream | |
| 238 | print_nodes(FStream,NodePredicate,SubGraphPred) :- | |
| 239 | subgraph_call(SubGraphPred,SubGraphID,Style,Color,Label,OtherAttrs), | |
| 240 | get_dot_cluster_name(SubGraphID,CN), | |
| 241 | format(FStream,' subgraph "~w" {~n',[CN]), | |
| 242 | (Style = none -> true ; format(FStream,' style="~w";~n',[Style])), | |
| 243 | (Color = none -> true ; format(FStream,' color="~w";~n',[Color])), | |
| 244 | simple_dot_string_escape(Label,ESID), % simple escape of unescaped ", avoid disturbing records | |
| 245 | format(FStream,' label="~w";~n',[ESID]), | |
| 246 | write(FStream, ' '), | |
| 247 | print_dot_attrs1(OtherAttrs,';\n ',';\n ',FStream), | |
| 248 | print_nodes2(FStream,SubGraphID,NodePredicate), | |
| 249 | write(FStream,'}'),nl(FStream), | |
| 250 | fail. | |
| 251 | print_nodes(FStream,NodePredicate,_SubGraphPred) :- | |
| 252 | print_nodes2(FStream,none,NodePredicate), | |
| 253 | nl(FStream). | |
| 254 | ||
| 255 | % If SubGraph can either be none or an ID generated by the subgraph_call | |
| 256 | print_nodes2(FStream,SubGraph,NodePredicate) :- | |
| 257 | node_predicate_call(NodePredicate,NodeID,SubGraph,Attrs), | |
| 258 | print_node(FStream,NodeID,Attrs), | |
| 259 | fail. | |
| 260 | print_nodes2(FStream,_Subgraph,_) :- nl(FStream). | |
| 261 | ||
| 262 | % print an individual DOT node with attributes as list | |
| 263 | print_node(FStream,NodeID,Attributes) :- | |
| 264 | format(FStream,' ~w [',[NodeID]), | |
| 265 | get_preference(dot_node_font_size,FSize), | |
| 266 | opt_add_attribute(fontsize,FSize,Attributes,Attrs2), | |
| 267 | print_dot_attrs(Attrs2,FStream), | |
| 268 | format(FStream,'];~n',[]). | |
| 269 | ||
| 270 | :- use_module(probsrc(tools),[simple_dot_string_escape/2]). | |
| 271 | % print attributes of a node or edge | |
| 272 | print_dot_attrs(List,FStream) :- exclude(is_meta_attribute,List,List1), | |
| 273 | print_dot_attrs1(List1,', ','',FStream). | |
| 274 | print_dot_attrs1([],_,_,_FStream) :- !. | |
| 275 | print_dot_attrs1([H|T],Sep,Term,FStream) :- get_attribute(H,Attr,Val),!, | |
| 276 | (compound(Val) -> EVal=Val % we hope no " inside the compound term | |
| 277 | ; simple_dot_string_escape(Val,EVal) % simple escape of unescaped " | |
| 278 | ), | |
| 279 | (T=[] | |
| 280 | -> format(FStream,'~w="~w"~w',[Attr,EVal,Term]) | |
| 281 | ; no_need_to_quote(Val) | |
| 282 | -> format(FStream,'~w=~w~w',[Attr,EVal,Sep]), | |
| 283 | print_dot_attrs1(T,Sep,Term,FStream) | |
| 284 | ; format(FStream,'~w="~w"~w',[Attr,EVal,Sep]), | |
| 285 | print_dot_attrs1(T,Sep,Term,FStream)). | |
| 286 | print_dot_attrs1(Err,Separator,Terminator,_) :- | |
| 287 | add_internal_error('Could not print attr:',print_dot_attrs1(Err,Separator,Terminator)). | |
| 288 | ||
| 289 | get_attribute(Attr/Val,Attr,Val). | |
| 290 | get_attribute(Attr=Val,Attr,Val). | |
| 291 | ||
| 292 | ||
| 293 | no_need_to_quote(Val) :- number(Val). | |
| 294 | no_need_to_quote(record). % mainly for test 1033 | |
| 295 | ||
| 296 | has_attribute(Name,Val,Attrs) :- member(H,Attrs), get_attribute(H,Name,Val). | |
| 297 | select_attribute(Name,Val,Attrs,Rest) :- select(H,Attrs,Rest), get_attribute(H,Name,Val). | |
| 298 | ||
| 299 | is_meta_attribute(H) :- get_attribute(H,Name,_), | |
| 300 | meta_argument(Name). % attributed not meant for dot, just for controlling the dot graph generator | |
| 301 | ||
| 302 | meta_argument(deals_with_pref). | |
| 303 | meta_argument(merge_transitions). | |
| 304 | ||
| 305 | opt_add_attribute(Name,_,Attrs,NewAttrs) :- has_attribute(Name,_,Attrs),!, | |
| 306 | NewAttrs = Attrs. | |
| 307 | opt_add_attribute(Name,Val,Attrs,[Name/Val|Attrs]). | |
| 308 | ||
| 309 | % -------------------------- | |
| 310 | ||
| 311 | ||
| 312 | print_transitions(FStream,NodeID,GraphAttrs,TransPredicate) :- | |
| 313 | (is_undirected_graph(GraphAttrs) -> DotArrow = '--' ; DotArrow = '->'), | |
| 314 | trans_predicate_call(TransPredicate,GraphAttrs,NodeID,SuccID,Style,Attributes), | |
| 315 | ||
| 316 | (NodeID=root -> preference(dot_print_root,true) ; true), | |
| 317 | ||
| 318 | (NodeID \= SuccID -> true | |
| 319 | ; preference(dot_print_self_loops,true) -> true | |
| 320 | ; has_attribute(deals_with_pref,dot_print_self_loops,GraphAttrs) -> true % the command itself processes the pref. | |
| 321 | ), | |
| 322 | ||
| 323 | format(FStream,' ~w ~w ~w [',[NodeID,DotArrow,SuccID]), | |
| 324 | ||
| 325 | (get_preference(dot_edge_penwidth,PenSize),PenSize \= 1 | |
| 326 | -> opt_add_attribute(penwidth,PenSize,Attributes,Attrs1) | |
| 327 | ; Attrs1=Attributes | |
| 328 | ), | |
| 329 | get_preference(dot_edge_font_size,FSize), | |
| 330 | opt_add_attribute(fontsize,FSize,Attrs1,Attrs2), | |
| 331 | (preference(dot_print_arc_colors,false), | |
| 332 | select_attribute(color,_,Attrs2,Attrs3) | |
| 333 | -> true % remove color attribute | |
| 334 | ; Attrs3=Attrs2 | |
| 335 | ), | |
| 336 | % acceptable styles Style ::= solid, bold, dotted, dashed, invis, arrowhead(none,Style), arrowtail(none,Style) | |
| 337 | print_style(Style,FStream), | |
| 338 | ||
| 339 | print_dot_attrs(Attrs3,FStream), | |
| 340 | format(FStream,'];~n',[]), % Note: we may have a trailing comma; but dotty accepts it | |
| 341 | fail. | |
| 342 | print_transitions(FStream,_NodeID,_,_) :- nl(FStream). | |
| 343 | ||
| 344 | % style term from old-style transition predicates | |
| 345 | print_style(solid,_) :- !. | |
| 346 | print_style(arrowhead(AS,S),FStream) :- !, format(FStream,'arrowhead=~w,',[AS]), print_style(S,FStream). | |
| 347 | print_style(arrowtail(AS,S),FStream) :- !, format(FStream,'dir=both,arrowtail=~w,',[AS]), print_style(S,FStream). | |
| 348 | print_style(Style,FStream) :- format(FStream,'style="~w",',[Style]). | |
| 349 | ||
| 350 | print_same_ranks(_,[]) :- !, | |
| 351 | add_message(dot_graph_generator,'Empty same rank result',''). | |
| 352 | print_same_ranks(_,[ID]) :- !, | |
| 353 | add_message(dot_graph_generator,'Singleton same rank result: ',ID). | |
| 354 | print_same_ranks(FStream,L) :- | |
| 355 | write(FStream,' { rank=same; '), | |
| 356 | print_same_ranks2(FStream,L), | |
| 357 | write(FStream,' }'),nl(FStream). | |
| 358 | ||
| 359 | print_same_ranks2(_FStream,[]). | |
| 360 | print_same_ranks2(FStream,[H|T]) :- | |
| 361 | write(FStream,H), write(FStream,'; '), | |
| 362 | print_same_ranks2(FStream,T). | |
| 363 | ||
| 364 | ||
| 365 | % utilities for converting values into colours: | |
| 366 | ||
| 367 | ||
| 368 | ||
| 369 | translate_bvalue_to_colour(Val,Col) :- | |
| 370 | (try_translate_bvalue_to_colour(Val,C) -> Col=C; Col=lightgray). | |
| 371 | ||
| 372 | try_translate_bvalue_to_colour(int(X),Res) :- !, (translate_int_col(X,Colour) -> Res=Colour ; Res=black). | |
| 373 | try_translate_bvalue_to_colour(string(X),Colour) :- is_of_type(X,rgb_color),!, X=Colour. | |
| 374 | try_translate_bvalue_to_colour(fd(X,GS),Colour) :- !, translate_fd_col(X,GS,Colour). | |
| 375 | try_translate_bvalue_to_colour(pred_true,Colour) :- !, Colour=olivedrab2. | |
| 376 | try_translate_bvalue_to_colour(pred_false,Colour) :- !, Colour=tomato. | |
| 377 | try_translate_bvalue_to_colour((A,_),Colour) :- !, try_translate_bvalue_to_colour(A,Colour). | |
| 378 | ||
| 379 | % TO DO : add string conversions, rgb values , ... | |
| 380 | :- use_module(probsrc(b_global_sets),[is_b_global_constant_hash/3]). | |
| 381 | ||
| 382 | translate_fd_col(X,GS,Res) :- | |
| 383 | is_b_global_constant_hash(GS,X,Colour), | |
| 384 | is_of_type(Colour,rgb_color),!, | |
| 385 | Res=Colour. | |
| 386 | translate_fd_col(X,_,Res) :- number(X), translate_int_col(X,Colour),!, Res=Colour. | |
| 387 | translate_fd_col(_,_,lightgray). | |
| 388 | ||
| 389 | translate_int_col(-1,Colour) :- !,Colour=tomato. % special case | |
| 390 | translate_int_col(Int,Colour) :- | |
| 391 | Y is abs(Int) mod 15, translate_int_col_aux(Y,Colour). | |
| 392 | translate_int_col_aux(0,gray95). | |
| 393 | translate_int_col_aux(1,blue). | |
| 394 | translate_int_col_aux(2,red). | |
| 395 | translate_int_col_aux(3,green). | |
| 396 | translate_int_col_aux(4,lightgray). | |
| 397 | translate_int_col_aux(5,orange). | |
| 398 | translate_int_col_aux(6,yellow). | |
| 399 | translate_int_col_aux(7,brown). | |
| 400 | translate_int_col_aux(8,violet). | |
| 401 | translate_int_col_aux(9,tomato). | |
| 402 | translate_int_col_aux(10,darkslateblue). | |
| 403 | translate_int_col_aux(11,maroon2). | |
| 404 | translate_int_col_aux(12,olivedrab2). | |
| 405 | translate_int_col_aux(13,chartreuse3). | |
| 406 | translate_int_col_aux(14,grey20). | |
| 407 | % red,green,blue,yellow,orange,black,white,gray,brown,violet,darkred,tomato,darkblue, | |
| 408 | % 'DarkGray',darkviolet,darkslateblue,lightblue,lightgray,maroon2,olivedrab2, | |
| 409 | % steelblue,chartreuse3,chartreuse4 |