1#include <DGtal/base/Common.h>
2#include <DGtal/helpers/StdDefs.h>
3#include <DGtal/geometry/curves/FrechetShortcut.h>
4#include <DGtal/shapes/Mesh.h>
6#ifndef BASICVECTOIMAGEEXPORTER_H
7#define BASICVECTOIMAGEEXPORTER_H
8class BasicVectoImageExporter
10 std::string LINE_COLOR;
11 std::string POINT_COLOR;
12 const float emptyCntWidth = 0;
13 const float meshCntWidth = 0;
23 typedef DGtal::Z2i::RealPoint Point2D;
24 typedef std::vector<Point2D> Contour2D;
34 std::string getHexCode(
const DGtal::Color &c);
36 std::string getExportType();
38 template <
typename CoordType>
39 CoordType reverseYCoord(CoordType y)
44 int mod(
int value,
int m)
48 return res < 0 ? res + m : res;
51 template <
typename TContour2D>
52 void addPathContent(
const TContour2D &contour)
54 if (contour.size() == 0)
58 if (myExportType == EpsExport)
60 myOutputStream << contour[0].first[0] <<
" " << contour[0].first[1] <<
" moveto" << std::endl;
61 for (
unsigned int i = 1; i < contour.size(); i++)
63 myOutputStream << contour[i].first[0] <<
" " << contour[i].first[1] <<
" lineto" << std::endl;
65 myOutputStream << contour[0].first[0] <<
" " << contour[0].first[1] <<
" lineto" << std::endl;
67 else if (myExportType == SvgExport)
69 if (contour.size() >= 3)
76 typedef std::pair<double, double> Point;
77 typedef std::pair<DrawType, std::vector<Point>> Path;
79 std::vector<Path> paths;
81 int size = contour.size();
83 for (
int i = 0; i < size; i++)
86 bool isLine = contour[i].second || contour[mod(i + 1, size)].second;
88 std::vector<Point> path;
89 double pointA[2] = {contour[mod(i, size)].first[0], contour[mod(i, size)].first[1]};
90 double pointB[2] = {contour[mod(i + 1, size)].first[0], contour[mod(i + 1, size)].first[1]};
93 path.push_back(std::make_pair(contour[mod(i + 1, size)].first[0], reverseYCoord(contour[mod(i + 1, size)].first[1])));
95 paths.push_back(std::make_pair(LINE, path));
100 double pointBefore[2] = {contour[mod(i - 1, size)].first[0], contour[mod(i - 1, size)].first[1]};
101 double vector1[2] = {(pointB[0] - pointBefore[0]), (pointB[1] - pointBefore[1])};
104 double firstControl[2] = {(pointA[0] + vector1[0]), (pointA[1] + vector1[1])};
107 double pointAfter[2] = {contour[mod(i + 2, size)].first[0], contour[mod(i + 2, size)].first[1]};
108 double vector2[2] = {(pointAfter[0] - pointA[0]), (pointAfter[1] - pointA[1])};
111 double secondControl[2] = {(pointB[0] - vector2[0]), (pointB[1] - vector2[1])};
113 path.push_back(std::make_pair(firstControl[0], reverseYCoord(firstControl[1])));
114 path.push_back(std::make_pair(secondControl[0], reverseYCoord(secondControl[1])));
115 path.push_back(std::make_pair(pointB[0], reverseYCoord(pointB[1])));
117 paths.push_back(std::make_pair(CURVE, path));
121 myOutputStream <<
"M " << contour[0].first[0] <<
" " << reverseYCoord(contour[0].first[1]);
122 for (
auto const &path : paths)
128 myOutputStream <<
" L " << path.second[0].first <<
" " << path.second[0].second;
132 myOutputStream <<
" C " << path.second[0].first <<
" " << path.second[0].second;
133 myOutputStream <<
", " << path.second[1].first <<
" " << path.second[1].second;
134 myOutputStream <<
", " << path.second[2].first <<
" " << path.second[2].second;
138 myOutputStream <<
" Z";
142 myOutputStream <<
"M ";
143 myOutputStream << contour[0].first[0] <<
"," << reverseYCoord(contour[0].first[1]) <<
" ";
144 for (
unsigned int i = 1; i < contour.size(); i++)
146 myOutputStream << contour[i].first[0] <<
"," << reverseYCoord(contour[i].first[1]) <<
" ";
148 myOutputStream << contour[0].first[0] <<
"," << reverseYCoord(contour[0].first[1]) <<
" z ";
154 template <
typename TContour>
155 void addPathContentBezierP0P1P2P3(
const TContour &contour)
157 if (myExportType == EpsExport)
159 if (contour.size() == 0)
163 myOutputStream << contour[0][0] <<
" " << contour[0][1] <<
" moveto" << std::endl;
165 for (
int i = 1; i < (int)(contour.size()) - 2; i = i + 3)
168 myOutputStream << contour[i][0] <<
" " << contour[i][1] <<
" ";
169 myOutputStream << contour[i + 1][0] <<
" " << contour[i + 1][1] <<
" ";
170 myOutputStream << contour[i + 2][0] <<
" " << contour[i + 2][1] <<
" curveto" << std::endl;
173 else if (myExportType == SvgExport)
175 if (contour.size < 1)
178 myOutputStream <<
"M " << contour[0][0] <<
" " << contour[0][1];
180 for (
int i = 1; i < contour.size(); i += 2)
182 myOutputStream <<
" Q " << contour[i % contour.size()][0] <<
" " << contour[i % contour.size()][1]
183 <<
", " << contour[(i + 1) % contour.size()][0] <<
" "
184 << contour[(i + 1) % contour.size()][1];
190 template <
typename TContour>
191 void addRegion(
const TContour &contour,
192 const DGtal::Color &color,
double linewidth)
194 if (myExportType == EpsExport)
196 myOutputStream <<
"newpath" << std::endl;
197 addPathContent(contour);
198 myOutputStream <<
"closepath" << std::endl;
201 myOutputStream <<
"gsave" << std::endl;
204 r = color.red() / 255.0;
205 g = color.green() / 255.0;
206 b = color.blue() / 255.0;
207 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
208 myOutputStream <<
"fill" << std::endl;
211 myOutputStream <<
"grestore" << std::endl;
212 myOutputStream << linewidth <<
" setlinewidth 0.7 0.2 0.2 setrgbcolor" << std::endl;
213 myOutputStream <<
"stroke" << std::endl;
217 myOutputStream <<
"grestore" << std::endl;
218 myOutputStream << emptyCntWidth <<
" setlinewidth " << r <<
" " << g <<
" " << b <<
" setrgbcolor"
220 myOutputStream <<
"stroke" << std::endl;
223 else if (myExportType == SvgExport)
227 myOutputStream <<
"<path \n style=\"fill:#" << getHexCode(color);
228 myOutputStream <<
"; fill-opacity:1,fill-rule:evenodd;stroke:#" << getHexCode(color) <<
";stroke-width:"
229 << emptyCntWidth <<
"px;";
230 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
231 myOutputStream <<
"d=\"";
235 myOutputStream <<
"<path \n style=\"fill:#" << getHexCode(color);
236 myOutputStream <<
"; fill-opacity:1,fill-rule:evenodd;stroke:red;stroke-width:" << meshCntWidth
238 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
239 myOutputStream <<
"d=\"";
242 addPathContent(contour);
243 myOutputStream <<
"\"\n";
244 myOutputStream <<
"id=\"path" << myCurrentIdPath <<
"\" \n";
245 myOutputStream <<
"inkscape:connector-curvature=\"0\" ",
246 myOutputStream <<
"sodipodi:nodetypes=\"cccccccccc\" />\n";
252 template <
typename TContour>
253 void addRegions(
const std::vector<TContour> &contours,
const DGtal::Color &color)
255 if (myExportType == EpsExport)
257 myOutputStream << emptyCntWidth <<
" setlinewidth" << std::endl;
259 r = color.red() / 255.0;
260 g = color.green() / 255.0;
261 b = color.blue() / 255.0;
262 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
264 myOutputStream <<
"newpath" << std::endl;
265 for (
auto const &cnt : contours)
269 myOutputStream <<
" closepath " << std::endl;
272 myOutputStream <<
"gsave" << std::endl;
273 myOutputStream <<
"fill" << std::endl;
274 myOutputStream <<
"grestore" << std::endl;
275 myOutputStream <<
"stroke" << std::endl;
290 else if (myExportType == SvgExport)
294 myOutputStream <<
"<path \n style=\"fill:#" << getHexCode(color);
295 myOutputStream <<
"; fill-opacity:1,fill-rule:evenodd;stroke:#" << getHexCode(color) <<
";stroke-width:"
296 << emptyCntWidth <<
";";
297 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
298 myOutputStream <<
"d=\"";
302 myOutputStream <<
"<path \n style=\"fill:#" << getHexCode(color);
303 myOutputStream <<
"; fill-opacity:1,fill-rule:evenodd;stroke:red;stroke-width:" << meshCntWidth <<
";";
304 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
305 myOutputStream <<
"d=\"";
307 for (
auto const &cnt : contours)
311 myOutputStream <<
"\"\n";
312 myOutputStream <<
"id=\"path" << myCurrentIdPath <<
"\" \n";
313 myOutputStream <<
"inkscape:connector-curvature=\"0\" ",
314 myOutputStream <<
"sodipodi:nodetypes=\"cccccccccc\" />\n";
326 template <
typename TContour>
327 void addRegionWithHoles(
const TContour &contour,
328 const std::vector<TContour> &listHoles,
329 const DGtal::Color &color)
332 r = color.red() / 255.0;
333 g = color.green() / 255.0;
334 b = color.blue() / 255.0;
335 if (myExportType == EpsExport)
337 myOutputStream <<
"newpath" << std::endl;
338 addPathContent(contour);
339 for (
auto const &hole : listHoles)
341 addPathContent(hole);
343 myOutputStream <<
"closepath" << std::endl;
345 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
346 myOutputStream <<
"fill" << std::endl;
348 else if (myExportType == SvgExport)
350 myOutputStream <<
"<path \n style=\"fill:#" << getHexCode(color);
351 myOutputStream <<
"; fill-opacity:1,fill-rule:evenodd;stroke:#" << getHexCode(color) <<
";stroke-width:"
352 << emptyCntWidth <<
"px;";
353 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
354 myOutputStream <<
"d=\"";
355 addPathContent(contour);
356 for (
auto const &hole : listHoles)
358 addPathContent(hole);
360 myOutputStream <<
"\"\n";
361 myOutputStream <<
"id=\"path" << myCurrentIdPath <<
"\" \n";
362 myOutputStream <<
"inkscape:connector-curvature=\"0\" ",
363 myOutputStream <<
"sodipodi:nodetypes=\"cccccccccc\" />\n";
369 template <
typename TPo
int2D>
370 void drawLine(
const TPoint2D &pt1,
const TPoint2D &pt2,
371 const DGtal::Color &color,
double lineWidth = 2.0)
374 r = color.red() / 255.0;
375 g = color.green() / 255.0;
376 b = color.blue() / 255.0;
377 if (myExportType == EpsExport)
379 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
380 myOutputStream << lineWidth <<
" setlinewidth" << std::endl;
381 myOutputStream << pt1[0] <<
" " << pt1[1] <<
" moveto" << std::endl;
382 myOutputStream << pt2[0] <<
" " << pt2[1] <<
" lineto" << std::endl;
383 myOutputStream <<
"stroke" << std::endl;
385 else if (myExportType == SvgExport)
387 myOutputStream <<
"draw line not implemented in SVG" << std::endl;
391 template <
typename TPo
int2D>
392 void addContour(
const std::vector<TPoint2D> &contour,
393 const DGtal::Color &color,
double lineWidth = 1.0)
395 if (myExportType == EpsExport)
397 myOutputStream <<
"newpath" << std::endl;
398 addPathContent(contour);
399 myOutputStream <<
"closepath" << std::endl;
401 r = color.red() / 255.0;
402 g = color.green() / 255.0;
403 b = color.blue() / 255.0;
404 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
406 myOutputStream << lineWidth <<
" setlinewidth stroke" << std::endl;
408 else if (myExportType == SvgExport)
411 myOutputStream <<
"<path \n style=\"stroke:#" << getHexCode(color);
412 myOutputStream <<
"; fill:none; stroke-opacity:1;stroke-width:" << lineWidth <<
";";
413 myOutputStream <<
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"" << std::endl;
414 myOutputStream <<
"d=\"";
416 addPathContent(contour);
418 myOutputStream <<
"\"\n";
419 myOutputStream <<
"id=\"path" << myCurrentIdPath <<
"\" \n";
420 myOutputStream <<
"inkscape:connector-curvature=\"0\" ",
421 myOutputStream <<
"sodipodi:nodetypes=\"cccccccccc\" />\n";
427 template <
typename TContour>
428 void addPathContentBezier(
const TContour &contour)
430 if (myExportType == EpsExport)
432 if (contour.size() <= 1)
437 myOutputStream << contour[2][0] <<
" " << contour[2][1] <<
" moveto" << std::endl;
438 for (
int i = 0; i < (int)(contour.size()); i = i + 4)
440 myOutputStream << contour[(i + 1) % contour.size()][0] <<
" " << contour[(i + 1) % contour.size()][1]
442 myOutputStream << contour[(i + 4) % contour.size()][0] <<
" " << contour[(i + 4) % contour.size()][1]
444 myOutputStream << contour[(i + 6) % contour.size()][0] <<
" " << contour[(i + 6) % contour.size()][1]
445 <<
" curveto" << std::endl;
448 else if (myExportType == SvgExport)
450 if (contour.size() < 1)
453 myOutputStream <<
"M " << contour[0][0] <<
" " << contour[0][1];
454 for (
int i = 1; i < contour.size(); i += 2)
456 myOutputStream <<
" Q " << contour[i % contour.size()][0] <<
" " << contour[i % contour.size()][1]
457 <<
", " << contour[(i + 1) % contour.size()][0] <<
" "
458 << contour[(i + 1) % contour.size()][1];
464 template <
typename TContour>
465 void addRegionsBezier(
const std::vector<TContour> &contours,
const DGtal::Color &color,
bool basicOrder =
false)
467 myOutputStream <<
"newpath" << std::endl;
468 for (
auto const &cnt : contours)
472 addPathContentBezierP0P1P2P3(cnt);
476 addPathContentBezier(cnt);
479 myOutputStream <<
"closepath" << std::endl;
482 myOutputStream <<
"gsave" << std::endl;
486 r = color.red() / 255.0;
487 g = color.green() / 255.0;
488 b = color.blue() / 255.0;
489 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
490 myOutputStream <<
"fill" << std::endl;
493 myOutputStream <<
"grestore" << std::endl;
494 myOutputStream << LINE_COLOR <<
"setrgbcolor" << std::endl;
495 myOutputStream <<
"0.1 setlinewidth" << std::endl;
496 myOutputStream <<
"stroke" << std::endl;
497 myOutputStream << POINT_COLOR <<
"setrgbcolor" << std::endl;
498 for (
auto const &cnt : contours)
500 addContourPoints(cnt);
505 template <
typename TContour>
506 void addContourPoints(
const TContour &contour,
const DGtal::Color &color = DGtal::Color::Red,
double radius = 2.0)
509 r = color.red() / 255.0;
510 g = color.green() / 255.0;
511 b = color.blue() / 255.0;
512 if (myExportType == EpsExport)
514 myOutputStream << r <<
" " << g <<
" " << b <<
" setrgbcolor" << std::endl;
515 if (contour.size() == 0)
520 for (
const auto &p : contour)
522 myOutputStream << p[0] <<
" " << p[1] <<
" moveto" << std::endl;
523 myOutputStream << std::fixed << p[0] <<
" " << p[1] <<
" " << radius <<
" 0 360 arc" << std::endl;
524 myOutputStream <<
"fill" << std::endl;
527 else if (myExportType == SvgExport)
529 for (
const auto &p : contour)
531 myOutputStream <<
"<circle cx=\"" << p[0] <<
"\" cy=\"" << reverseYCoord(p[1]) <<
"\" r=\"" << radius
532 <<
"\" fill = \"#" << getHexCode(color) <<
"\"/>";
537 BasicVectoImageExporter(
const std::string &imageName,
unsigned int width,
unsigned int height,
538 bool displayMesh =
false,
double scale = 1.0);
540 ~BasicVectoImageExporter() { myOutputStream.close(); };
543 unsigned int myWidth = 200;
544 unsigned int myHeight = 200;
545 double myScale = 1.0;
547 double myShiftX = 0.0;
548 double myShiftY = 0.0;
549 int myCurrentIdPath = 1;
550 std::vector<Contour2D> myPlainContours;
551 std::vector<Contour2D> myHoleContours;
552 std::string myImageName;
553 std::ofstream myOutputStream;
557 std::map<unsigned int, std::vector<unsigned int>> mapHoles;
558 std::map<unsigned int, DGtal::Color> colorMap;
559 ExportType myExportType = UnknowExport;