Line data Source code
1 : /*
2 : * Copyright (c) 2014-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #include <algorithm>
34 : #include <cmath>
35 : #include <fstream>
36 : #include <vector>
37 : #include "file_io_tikz.h"
38 : #include "common/util/string_util.h"
39 : #include "lib_grid/algorithms/geom_obj_util/geom_obj_util.h"
40 : #include "lib_grid/algorithms/bounding_box_util.h"
41 : #include "lib_grid/iterators/lg_for_each.h"
42 :
43 : using namespace std;
44 :
45 : namespace ug{
46 :
47 0 : TikzExportDesc::
48 0 : TikzExportDesc() :
49 0 : vrtRadius(0.1),
50 0 : vrtRimWidth(0.02),
51 : vrtColor(0.65, 0.65, 0.65),
52 0 : edgeWidth(0.025),
53 : edgeColor(0, 0, 0),
54 0 : faceRimWidth(0.015),
55 : faceColor(0.85, 0.85, 0.85),
56 0 : smallestVal(0.001)
57 0 : {}
58 :
59 0 : static vector2 trunk(const vector2& v, number smallestVal)
60 : {
61 : vector2 t;
62 0 : t.x() = smallestVal * round(v.x() / smallestVal);
63 0 : t.y() = smallestVal * round(v.y() / smallestVal);
64 0 : return t;
65 : }
66 :
67 :
68 : struct TIKZElem{
69 : GridObject* elem;
70 : float zmin;
71 : float zmax;
72 : int elemId;
73 : int subsetId;
74 :
75 : template <class vector_t>
76 0 : TIKZElem(GridObject* _e, int _si, const AABox<vector_t>& bbox) :
77 0 : elem(_e),
78 0 : elemId(_e->base_object_id()),
79 0 : subsetId(_si)
80 : {
81 : if(vector_t::Size == 3){
82 0 : zmin = bbox.min[2];
83 0 : zmax = bbox.max[2];
84 : }
85 : else
86 : zmin = zmax = 0;
87 : }
88 :
89 : // if x < y, x will be rendered before y
90 0 : bool operator <(const TIKZElem& e) const{
91 0 : if(zmin - e.zmin > SMALL) return false;
92 0 : else if(e.zmin - zmin > SMALL) return true;
93 :
94 0 : if(e.elemId > elemId) return false;
95 0 : else if(e.elemId < elemId) return true;
96 :
97 0 : if(zmax - e.zmax > SMALL) return false;
98 0 : else if(e.zmax - zmax > SMALL) return true;
99 :
100 0 : if(e.subsetId < subsetId) return false;
101 0 : else if(e.subsetId > subsetId) return true;
102 :
103 : return false;
104 : }
105 : };
106 :
107 :
108 :
109 0 : bool ExportGridToTIKZ(Grid& grid, const char* filename, const ISubsetHandler* psh,
110 : APosition aPos, TikzExportDesc desc)
111 : {
112 0 : UG_COND_THROW(!psh, "A subset handler is required to write a tikz file!\n");
113 :
114 0 : ofstream out(filename);
115 0 : UG_COND_THROW(!out, "Couldn't load file " << filename << "\n");
116 :
117 :
118 : vector<string> subsetIdentifyer;
119 : vector<bool> subsetNameIsDuplicate;
120 0 : for(int si = 0; si < psh->num_subsets(); ++si){
121 0 : string sname = psh->get_subset_name(si);
122 0 : for(size_t i = 0; i < sname.size(); ++i){
123 0 : char c = sname[i];
124 0 : if(!(isalnum(c) || c == '_'))
125 0 : sname[i] = '_';
126 : }
127 :
128 : // check if the string is already contained in subsetIdentifyers and mark it
129 : // as a duplicate if that's the case
130 : bool isDuplicate = false;
131 0 : for(size_t i = 0; i < subsetIdentifyer.size(); ++i){
132 0 : if(subsetIdentifyer[i] == sname){
133 : isDuplicate = true;
134 : break;
135 : }
136 : }
137 0 : subsetIdentifyer.push_back(sname);
138 0 : subsetNameIsDuplicate.push_back(isDuplicate);
139 : }
140 :
141 0 : number sml = max(SMALL, desc.smallestVal);
142 :
143 : Grid::VertexAttachmentAccessor<APosition> aaPos(grid, aPos);
144 :
145 : out << "% This tex-file was exported from ProMesh (www.promesh3d.com)" << endl << endl;
146 : out << "% Call 'pdflatex' with this script to generate a .pdf file from it." << endl << endl;
147 : out << "% By placing a file 'custom_promesh_style.tex' in the same folder as this" << endl;
148 : out << "% script, you may override all local style definitions with custom definitions." << endl << endl;
149 :
150 : out << "\\documentclass[tikz]{standalone}" << endl;
151 : out << "\\begin{document}" << endl;
152 : out << "\\begin{tikzpicture}" << endl;
153 :
154 : out << endl;
155 0 : out << "\\definecolor{vertexColor}{rgb}{" << desc.vrtColor.x() << ", "
156 0 : << desc.vrtColor.y() << ", " << desc.vrtColor.z() << "}" << endl;
157 0 : out << "\\definecolor{edgeColor}{rgb}{" << desc.edgeColor.x() << ", "
158 0 : << desc.edgeColor.y() << ", " << desc.edgeColor.z() << "}" << endl;
159 0 : out << "\\definecolor{faceColor}{rgb}{" << desc.faceColor.x() << ", "
160 0 : << desc.faceColor.y() << ", " << desc.faceColor.z() << "}" << endl;
161 : out << endl;
162 :
163 0 : out << "\\tikzset{vertexBase/.style={circle,draw=black,fill=vertexColor,line width=" << desc.vrtRimWidth << "cm,\n"
164 0 : << " inner sep=0,minimum size=" << desc.vrtRadius << "cm}}\n";
165 0 : out << "\\tikzset{edgeBase/.style={draw=edgeColor, line width=" << desc.edgeWidth << "cm}}\n";
166 0 : out << "\\tikzset{faceBase/.style={draw=black, fill=faceColor, line width=" << desc.faceRimWidth <<"cm}}\n";
167 :
168 : out << endl;
169 :
170 0 : for(int si = 0; si < psh->num_subsets(); ++si){
171 0 : if(!subsetNameIsDuplicate[si]){
172 0 : const std::string& subsetName = subsetIdentifyer[si];
173 : out << "% '" << subsetName << "' subset styles" <<endl;
174 0 : out << "\\tikzset{vertex_" << subsetName << "/.style={vertexBase}}\n";
175 0 : out << "\\tikzset{edge_" << subsetName << "/.style={edgeBase}}\n";
176 0 : out << "\\tikzset{face_" << subsetName << "/.style={faceBase}}\n";
177 : }
178 : }
179 :
180 : out << endl;
181 : out << "\\InputIfFileExists{./custom_promesh_style.tex}{}{}" << endl;
182 : out << endl;
183 :
184 :
185 : // create a vector which contains all objects that shall be rendered and sort it
186 : vector<TIKZElem> elems;
187 0 : lg_for_each(Vertex, v, grid){
188 0 : if(psh->get_subset_index(v) != -1)
189 0 : elems.push_back(TIKZElem(v, psh->get_subset_index(v),
190 : CalculateBoundingBox(v, aaPos)));
191 : }lg_end_for;
192 :
193 0 : lg_for_each(Edge, e, grid){
194 0 : if(psh->get_subset_index(e) != -1)
195 0 : elems.push_back(TIKZElem(e, psh->get_subset_index(e),
196 0 : CalculateBoundingBox(e, aaPos)));
197 : }lg_end_for;
198 :
199 0 : lg_for_each(Face, f, grid){
200 0 : if(psh->get_subset_index(f) != -1)
201 0 : elems.push_back(TIKZElem(f, psh->get_subset_index(f),
202 0 : CalculateBoundingBox(f, aaPos)));
203 : }lg_end_for;
204 :
205 0 : sort(elems.begin(), elems.end());
206 :
207 : out << "\\begin{scope}" << endl;
208 0 : for_each_in_vec(TIKZElem& tikzElem, elems){
209 0 : const std::string& subsetName = subsetIdentifyer[tikzElem.subsetId];
210 0 : switch(tikzElem.elemId){
211 0 : case VERTEX:{
212 0 : Vertex* vrt = static_cast<Vertex*>(tikzElem.elem);
213 0 : vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
214 0 : out << "\\node[vertex_" << subsetName << "] at (" << p.x() << "cm, " << p.y() << "cm) {};" << endl;
215 0 : }break;
216 :
217 0 : case EDGE:{
218 0 : Edge* e = static_cast<Edge*>(tikzElem.elem);
219 0 : out << "\\draw[edge_" << subsetName << "]";
220 0 : for(size_t i = 0; i < e->num_vertices(); ++i){
221 0 : Vertex* vrt = e->vertex(i);
222 0 : vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
223 0 : out << " (" << p.x() << "cm, " << p.y() << "cm)";
224 0 : if(i+1 != e->num_vertices())
225 0 : out << " --";
226 : }
227 : out << ";" << endl;
228 : }break;
229 :
230 0 : case FACE:{
231 0 : Face* f = static_cast<Face*>(tikzElem.elem);
232 0 : out << "\\filldraw[face_" << subsetName << "]";
233 0 : for(size_t i = 0; i < f->num_vertices(); ++i){
234 0 : Vertex* vrt = f->vertex(i);
235 0 : vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
236 0 : out << " (" << p.x() << "cm, " << p.y() << "cm) --";
237 : }
238 : out << " cycle;" << endl;
239 : }break;
240 :
241 : }
242 :
243 : }end_for;
244 :
245 :
246 : // for(int si = 0; si < psh->num_subsets(); ++si){
247 : // // draw all faces which are in a subset
248 : // for(FaceIterator iter = grid.begin<Face>();
249 : // iter != grid.end<Face>(); ++iter)
250 : // {
251 : // Face* f = *iter;
252 : // if(psh->get_subset_index(f) != si) // THIS IS NASTY! One should iterate over subset-elements directly instead
253 : // continue;
254 : // out << "\\filldraw[face" << si << "]";
255 : // for(size_t i = 0; i < f->num_vertices(); ++i){
256 : // Vertex* vrt = f->vertex(i);
257 : // vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
258 : // out << " (" << p.x() << "cm, " << p.y() << "cm) --";
259 : // }
260 : // out << " cycle;" << endl;
261 : // }
262 : // }
263 :
264 : // for(int si = 0; si < psh->num_subsets(); ++si){
265 : // // draw all edges which are in a subset
266 : // for(EdgeIterator iter = grid.begin<Edge>();
267 : // iter != grid.end<Edge>(); ++iter)
268 : // {
269 : // Edge* e = *iter;
270 : // if(psh->get_subset_index(e) != si) // THIS IS NASTY! One should iterate over subset-elements directly instead
271 : // continue;
272 : // out << "\\draw[edge" << si << "]";
273 : // for(size_t i = 0; i < e->num_vertices(); ++i){
274 : // Vertex* vrt = e->vertex(i);
275 : // vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
276 : // out << " (" << p.x() << "cm, " << p.y() << "cm)";
277 : // if(i+1 != e->num_vertices())
278 : // out << " --";
279 : // }
280 : // out << ";" << endl;
281 : // }
282 : // }
283 :
284 : // for(int si = 0; si < psh->num_subsets(); ++si){
285 : // // draw all nodes which are in a subset
286 : // for(VertexIterator iter = grid.begin<Vertex>();
287 : // iter != grid.end<Vertex>(); ++iter)
288 : // {
289 : // Vertex* vrt = *iter;
290 : // if(psh->get_subset_index(vrt) != si) // THIS IS NASTY! One should iterate over subset-elements directly instead
291 : // continue;
292 : // vector2 p = trunk(vector2(aaPos[vrt].x(), aaPos[vrt].y()), sml);
293 : // out << "\\node[vertex" << si << "] at (" << p.x() << "cm, " << p.y() << "cm) {};" << endl;
294 : // }
295 : // }
296 : out << "\\end{scope}" << endl;
297 :
298 : out << "\\end{tikzpicture}" << endl;
299 : out << "\\end{document}" << endl;
300 :
301 0 : out.close();
302 0 : return true;
303 0 : }
304 :
305 : }// end of namespace
|