Graph API & internal structures redesign
[hypercube:hypercube.git] / IO / providers / ps.cpp
1 #include <cstring>
2 #include <iostream>
3 #include <iomanip>
4 #include <fstream>
5 #include "CORE/vertex.h"
6 #include "CORE/edge.h"
7 #include "CORE/config.h"
8 #include "IO/modules.h"
9 #include "ps_snippet.h"
10 #include "ps.h"
11
12
13 using namespace std;
14
15 #define tr(val,dim) ((dim).y()-(val))
16
17 static Coordinates edgeValuePos(Coordinates &p1, Coordinates &p2,
18   int size, int fontSize)
19 {
20         Coordinates u, m;
21
22         u = p2 - p1;
23         m = p1 + (u / 2);
24
25         if ((u.x() > 0 && u.y() > 0) || (u.x() < 0 && u.y() < 0))
26                 return Coordinates(m.x() + size / 2, m.y() - size / 2);
27         else
28                 return Coordinates(m.x() + size / 2, m.y() + size / 2 + fontSize);
29 }
30
31
32 static void prolog(Graph *graph, PsSnippet *sn, wofstream &fs)
33 {
34         Coordinates dim = graph->dimensions();
35
36         fs << "%!PS-Adobe-3.0 EPSF-3.0" << endl
37            << "%%BoundingBox: 0 0 " << dim.x() << " " << dim.y() << endl
38            << "%%Creator: Hypercube ("APP_HOMEPAGE")" << endl;
39
40         if (sn->font()->font())
41                 fs << "%%DocumentSuppliedResources: font ";
42         else
43                 fs << "%%DocumentNeededResources: font ";
44         fs << sn->font()->name() << endl;
45
46         fs << "%%EndComments" << endl << endl
47            << "%%BeginProlog" << endl;
48
49         if (sn->font()->font())
50                 fs << "%%BeginResource: font " << sn->font()->name() << endl
51                    << sn->font()->font() << endl
52                    << "%%EndResource" << endl << endl;
53
54         if (sn->encoding()->encoding()) {
55                 fs << "/encoding [" << endl
56                    << sn->encoding()->encoding() << endl
57                    << "] def" << endl << endl;
58
59                 fs << "/reencode {" << endl
60                    << " findfont" << endl
61                    << " dup length dict begin" << endl
62                    << "         {1 index /FID ne {def} {pop pop} ifelse} forall" << endl
63                    << "         /Encoding encoding def" << endl
64                    << "         currentdict" << endl
65                    << " end" << endl
66                    << " definefont pop" << endl
67                    << "} def" << endl << endl;
68
69                 fs << "/rfont /" << sn->font()->name() << " reencode" << endl
70                    << "/font /rfont def" << endl << endl;
71         } else
72                 fs << "/font /" << sn->font()->name() << " def" << endl << endl;
73
74         fs << "/e {newpath moveto lineto stroke} def" << endl
75            << "/v {newpath arc closepath fill} def" << endl
76            << "/d {moveto show} def" << endl
77            << "/f {font findfont exch scalefont setfont} def" << endl
78            << "/lw {setlinewidth} def" << endl
79            << "/c {setrgbcolor} def" << endl << endl;
80
81         fs << "%%EndProlog" << endl << endl;
82 }
83
84 static void edges(Graph *graph, wofstream &fs)
85 {
86         Coordinates c1, c2, t;
87         Color color;
88         int fontSize = -1, lineWidth = -1;
89         Coordinates dim = graph->dimensions();
90         Edge *e;
91
92
93         for (int zValue = -2; zValue < 0; zValue++ ) {
94                 for (size_t i = 0; i < graph->edge_size(); i++) {
95                         e = graph->edge(i);
96                         if (e->zValue() != zValue)
97                                 continue;
98
99                         c1 = e->src()->coordinates() + Coordinates(
100                           e->src()->size() / 2, e->src()->size() / 2);
101                         c2 = e->dst()->coordinates() + Coordinates(
102                           e->dst()->size() / 2, e->dst()->size() / 2);
103
104                         if (color != e->color()) {
105                                 color = e->color();
106                                 fs << color.red() << " " << color.green() << " "
107                                    << color.blue() << " c" << endl;
108                         }
109                         if (lineWidth != e->size()) {
110                                 lineWidth = e->size();
111                                 fs << lineWidth << " lw" << endl;
112                         }
113                         fs << c1.x() << " " << tr(c1.y(), dim) << " "
114                            << c2.x() << " " << tr(c2.y(), dim) << " e" << endl;
115                 }
116                 fs << endl;
117
118                 for (size_t i = 0; i < graph->edge_size(); i++) {
119                         e = graph->edge(i);
120                         if (e->zValue() != zValue || e->fontSize() == 0)
121                                 continue;
122
123                         c1 = e->src()->coordinates() + Coordinates(
124                           e->src()->size() / 2, e->src()->size() / 2);
125                         c2 = e->dst()->coordinates() + Coordinates(
126                           e->dst()->size() / 2, e->dst()->size() / 2);
127
128                         if (e->fontSize() != fontSize) {
129                                 fontSize = e->fontSize();
130                                 fs << fontSize << " f" << endl;
131                         }
132                         if (e->color() != color) {
133                                 color = e->color();
134                                 fs << color.red() << " " << color.green() << " "
135                                    << color.blue() << " c" << endl;
136                         }
137
138                         t = edgeValuePos(c1, c2, e->size(), e->fontSize());
139                         fs << "(" << e->text() << ") "
140                            << t.x() << " " << tr(t.y(), dim) << " d" << endl;
141                 }
142                 fs << endl;
143         }
144 }
145
146 static void vertexes(Graph *graph, wofstream &fs)
147 {
148         Coordinates c;
149         Color color;
150         int fontSize = -1;
151         Coordinates dim = graph->dimensions();
152         Vertex *v;
153
154
155         for (size_t i = 0; i < graph->vertex_size(); i++) {
156                 v = graph->vertex(i);
157
158                 c = v->coordinates()
159                   + Coordinates(v->size() / 2, v->size() / 2);
160
161                 if (v->color() != color) {
162                         color = v->color();
163                         fs << color.red() << " " << color.green() << " " << color.blue()
164                            << " c" << endl;
165                 }
166                 fs << c.x() << " " << tr(c.y(), dim) << " " << v->size() / 2
167                    << " 0 360 v" << endl;
168         }
169         fs << endl;
170
171         for (size_t i = 0; i < graph->vertex_size(); i++) {
172                 v = graph->vertex(i);
173                 if (v->fontSize() == 0)
174                         continue;
175
176                 c = v->coordinates()
177                   + Coordinates(v->size() / 2, v->size() / 2);
178
179                 if (v->fontSize() != fontSize) {
180                         fontSize = v->fontSize();
181                         fs << fontSize << " f" << endl;
182                 }
183                 if (v->color() != color) {
184                         color = v->color();
185                         fs << color.red() << " " << color.green() << " " << color.blue()
186                            << " c" << endl;
187                 }
188                 fs << "(" << v->text() << ") "
189                    << c.x() + v->size() / 2 << " "
190                    << tr(c.y() + v->size(), dim)
191                    << " d" << endl;
192         }
193         fs << endl;
194 }
195
196
197 IO::Error PsGraphOutput::writeGraph(Graph *graph, const char *filename)
198 {
199         for (PsSnippet **sp = snippets; *sp; sp++) {
200                 codecvt<wchar_t,char,mbstate_t> *cvt = 0;
201
202                 for (Encoding **ep = encodings; *ep; ep++)
203                         if (!strcmp((*sp)->encoding()->name(), (*ep)->name()))
204                                 cvt = (*ep)->cvt();
205                 if (!cvt)
206                         return WriteError;
207
208                 wofstream fs;
209                 locale lc(locale(), cvt);
210                 fs.imbue(lc);
211                 fs.open(filename);
212
213                 prolog(graph, *sp, fs);
214                 edges(graph, fs);
215                 vertexes(graph, fs);
216                 fs << "%%EOF" << endl;
217
218                 fs.close();
219                 if (!fs.fail())
220                         return Ok;
221         }
222
223         return WriteError;
224 }