NAPISD
PAHdb website C++ backend
Loading...
Searching...
No Matches
Canvas.cpp
1#include "Canvas.h"
2
3Canvas::Canvas()
4 : _color("ffffff"), _size({300, 200}), _defaultcharacterheight(2.25),
5 _defaultticklength(3.0) {
6 _items.reserve(4);
7}
8
9void Canvas::add(CanvasItem &item) { _items.emplace_back(item.clone()); }
10
11void Canvas::add(std::vector<Plot> &plots) {
12
13 for (auto &plot : plots) {
14
15 _items.emplace_back(plot.clone());
16 }
17}
18
19PLINT Canvas::lookUpColor(std::string_view hex) {
20
21 auto index = std::find(_colormap.begin(), _colormap.end(), hex);
22
23 PLINT entry = std::distance(_colormap.begin(), index);
24
25 if (index == _colormap.end()) {
26
27 _colormap.emplace_back(hex);
28
29 std::stringstream ss;
30
31 ss << std::hex << hex.substr(0, 6);
32
33 int rgb;
34
35 ss >> rgb;
36
37 int a = 255;
38
39 if (hex.size() == 8) {
40
41 ss.str(std::string());
42
43 ss.clear();
44
45 ss << std::hex << hex.substr(6);
46
47 ss >> a;
48 }
49
50 _plstream->scol0a(entry, (rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff,
51 static_cast<float>(a) / 255.0f);
52 }
53
54 return (entry);
55}
56
57void Canvas::paintOnScreen() {
58
59 _plstream = std::make_unique<plstream>();
60
61 _plstream->sdev("xwin");
62
63 _plstream->spause(true);
64
65 _plstream->spage(72.0, 72.0, _size.at(0), _size.at(1), 0.0, 0.0);
66
67 paint();
68}
69
70void Canvas::paintOnPostscript(std::string_view filename) {
71
72 _plstream = std::make_unique<plstream>();
73
74 _plstream->sdev("epscairo");
75
76 std::string f(filename);
77
78 _plstream->sfnam(f.append(".ps").c_str());
79
80 _plstream->spause(false);
81
82 _plstream->spage(0.0, 0.0, _size.at(0), _size.at(1), 0.0, 0.0);
83
84 //_plstream->sdiori(1);
85
86 _plstream->setopt("aspect", "1");
87
88 paint();
89}
90
91void Canvas::paintOnPDF(std::string_view filename) {
92
93 _plstream = std::make_unique<plstream>();
94
95 _plstream->sdev("pdfcairo");
96
97 std::string f(filename);
98
99 _plstream->sfnam(f.append(".pdf").c_str());
100
101 _plstream->spause(false);
102
103 _plstream->spage(0.0, 0.0, _size.at(0), _size.at(1), 0.0, 0.0);
104
105 //_plstream->sdiori(1);
106
107 _plstream->setopt("aspect", "1");
108
109 paint();
110}
111
112void Canvas::paintOnPNG(std::string_view filename) {
113
114 _plstream = std::make_unique<plstream>();
115
116 _plstream->sdev("pngcairo");
117
118 std::string f(filename);
119
120 _plstream->sfnam(f.append(".png").c_str());
121
122 _plstream->spause(false);
123
124 _plstream->spage(0.0, 0.0, _size.at(0), _size.at(1), 0.0, 0.0);
125
126 _defaultcharacterheight *= 1.5;
127
128 paint();
129}
130
131void Canvas::paintOnJPEG(std::string_view filename) {
132
133 _plstream = std::make_unique<plstream>();
134
135 _plstream->sdev("cairojpeg");
136
137 std::string f(filename);
138
139 _plstream->sfnam(f.append(".jpeg").c_str());
140
141 _plstream->spause(false);
142
143 _plstream->spage(0.0, 0.0, _size.at(0), _size.at(1), 0.0, 0.0);
144
145 _defaultcharacterheight *= 1.5;
146
147 paint();
148}
149
150void Canvas::paint() {
151
152 bool hadfirstpage = false;
153
154 _plstream->scmap0n(64);
155
156 _colormap.clear();
157
158 lookUpColor(_color);
159
160 _plstream->init();
161
162 _plstream->fontld(1);
163
164 _plstream->font(2);
165
166 _plstream->schr(_defaultcharacterheight, 1.0);
167
168 std::array<double, 2> margins;
169
170 for (auto &item : _items) {
171
172 switch (item->type) {
173
174 case CanvasItem::Type::I_Plot: {
175
176 Plot *plot = dynamic_cast<Plot *>(item.get());
177
178 if (plot->isAdvance() || !hadfirstpage) {
179
180 _plstream->adv(0);
181
182 hadfirstpage = true;
183 }
184
185 draw(plot);
186 } break;
187
188 case CanvasItem::Type::I_Panels: {
189 if (!hadfirstpage) {
190
191 _plstream->adv(0);
192
193 hadfirstpage = true;
194 }
195
196 Panels *panels = dynamic_cast<Panels *>(item.get());
197
198 margins[0] = panels->getYMargins().at(0);
199
200 margins[1] = panels->getYMargins().at(0) +
201 (panels->getYMargins().at(1) - panels->getYMargins().at(0)) /
202 static_cast<double>(panels->getRows());
203
204 for (auto &panel : *panels) {
205
206 Plot *plot = dynamic_cast<Plot *>(panel.get());
207
208 plot->setYMargins(margins);
209
210 if (plot->isAdvance()) {
211
212 margins[0] = margins[1];
213
214 margins[1] = margins[1] + (panels->getYMargins().at(1) -
215 panels->getYMargins().at(0)) /
216 static_cast<double>(panels->getRows());
217 }
218
219 draw(plot);
220 }
221
222 } break;
223 case CanvasItem::Type::I_Text: {
224 if (!hadfirstpage) {
225
226 _plstream->adv(0);
227
228 hadfirstpage = true;
229 }
230
231 Text *text = dynamic_cast<Text *>(item.get());
232
233 _plstream->vpor(0.0, 1.0, 0.0, 1.0);
234
235 _plstream->wind(0.0, 1.0, 0.0, 1.0);
236
237 _plstream->col0(lookUpColor(text->getColor()));
238
239 _plstream->schr(_defaultcharacterheight, text->getSize());
240
241 _plstream->ptex(text->getCoordinates().at(0),
242 text->getCoordinates().at(1),
243 cosf(M_PI * text->getAngle() / 180.0),
244 sinf(M_PI * text->getAngle() / 180.0),
245 text->getJustification(), text->getText().data());
246 } break;
247 default: {
248
249 throw(Exception("Unsupported graphics type"));
250 } break;
251 }
252 }
253}
254
255void Canvas::draw(Plot *plot) {
256
257 _plstream->vpor(plot->getXMargins().at(0), plot->getXMargins().at(1),
258 plot->getYMargins().at(0), plot->getYMargins().at(1));
259
260 float xmin, xmax, ymin, ymax;
261
262 xmin = plot->getXLimits().at(0);
263
264 xmax = plot->getXLimits().at(1);
265
266 ymin = plot->getYLimits().at(0);
267
268 ymax = plot->getYLimits().at(1);
269
270 _plstream->wind(xmin, xmax, ymin, ymax);
271
272 _plstream->width(plot->getLineWidth());
273
274 _plstream->lsty(static_cast<PLINT>(plot->getLineStyle()));
275
276 if (plot->isDrawHorizontalGrid() || plot->isDrawHorizontalFineGrid()) {
277
278 _plstream->col0(lookUpColor(plot->getHorizontalGrid().getColor()));
279
280 _plstream->lsty(
281 static_cast<PLINT>(plot->getHorizontalGrid().getLineStyle()));
282
283 _plstream->width(plot->getHorizontalGrid().getLineWidth());
284
285 if (plot->isDrawHorizontalFineGrid()) {
286
287 _plstream->box("gh", 0.0, 0.0, "", 0.0, 0.0);
288 } else {
289
290 _plstream->box("g", 0.0, 0.0, "", 0.0, 0.0);
291 }
292 }
293
294 if (plot->isDrawVerticalGrid() || plot->isDrawVerticalFineGrid()) {
295
296 _plstream->col0(lookUpColor(plot->getVerticalGrid().getColor()));
297
298 _plstream->lsty(static_cast<PLINT>(plot->getVerticalGrid().getLineStyle()));
299
300 _plstream->width(plot->getVerticalGrid().getLineWidth());
301
302 if (plot->isDrawVerticalFineGrid()) {
303
304 _plstream->box("", 0, 0, "gh", 0, 0);
305 } else {
306
307 _plstream->box("", 0, 0, "g", 0, 0);
308 }
309 }
310
311 for (auto &p : *plot) {
312
313 switch (p->type) {
314
315 case CanvasItem::Type::I_Point: {
316
317 Point *point = dynamic_cast<Point *>(p.get());
318
319 _plstream->col0(lookUpColor(point->getColor()));
320
321 _plstream->width(plot->getLineWidth());
322
323 _plstream->lsty(static_cast<PLINT>(plot->getLineStyle()));
324
325 _plstream->ssym(_defaultcharacterheight, point->getSize());
326
327 PLFLT px = point->getCoordinates().at(0);
328
329 PLFLT py = point->getCoordinates().at(1);
330
331 _plstream->sym(1, &px, &py, point->getSymbol());
332 } break;
333 case CanvasItem::Type::I_Line: {
334
335 Line *line = dynamic_cast<Line *>(p.get());
336
337 _plstream->col0(lookUpColor(line->getColor()));
338
339 _plstream->lsty(static_cast<PLINT>(line->getLineStyle()));
340
341 _plstream->width(line->getLineWidth());
342
343 _plstream->join(
344 line->getStartCoordinates().at(0), line->getStartCoordinates().at(1),
345 line->getEndCoordinates().at(0), line->getEndCoordinates().at(1));
346 } break;
347 case CanvasItem::Type::I_Curve: {
348
349 Curve *curve = dynamic_cast<Curve *>(p.get());
350
351 if (curve->getX().size() == 0) {
352
353 continue;
354 }
355
356 const PLFLT *x = curve->getX().data();
357
358 const PLFLT *xerr = curve->getXErr().data();
359
360 const PLFLT *y = curve->getY().data();
361
362 const PLFLT *yerr = curve->getYErr().data();
363
364 size_t n = curve->getX().size();
365
366 if (xerr || yerr) {
367
368 _plstream->lsty(static_cast<PLINT>(curve->getLineStyle()));
369
370 _plstream->width(curve->getLineWidth());
371
372 _plstream->col0(lookUpColor(curve->getColor()));
373
374 std::vector<PLFLT> min(n);
375
376 std::vector<PLFLT> max(n);
377
378 if (xerr) {
379
380 std::transform(curve->getX().begin(), curve->getX().end(),
381 curve->getXErr().begin(), min.begin(),
382 std::minus<PLFLT>());
383
384 std::transform(curve->getX().begin(), curve->getX().end(),
385 curve->getXErr().begin(), max.begin(),
386 std::plus<PLFLT>());
387
388 _plstream->errx(n, x, min.data(), max.data());
389 }
390 if (yerr) {
391
392 std::transform(curve->getY().begin(), curve->getY().end(),
393 curve->getYErr().begin(), min.begin(),
394 std::minus<PLFLT>());
395
396 std::transform(curve->getY().begin(), curve->getY().end(),
397 curve->getYErr().begin(), max.begin(),
398 std::plus<PLFLT>());
399
400 _plstream->erry(n, x, min.data(), max.data());
401 }
402 }
403
404 if (curve->isFill() && curve->getSymbol() == 0) {
405
406 _plstream->col0(lookUpColor(curve->getFillColor()));
407
408 if (y[0] == 0.0f && y[n - 1] == 0.0f) {
409
410 _plstream->fill(n, x, y);
411 } else {
412
413 std::vector<PLFLT> a(curve->getX().begin(), curve->getX().end());
414
415 std::vector<PLFLT> b(curve->getY().begin(), curve->getY().end());
416
417 if (y[n - 1] != 0.0f) {
418
419 a.push_back(x[n - 1]);
420
421 b.push_back(0.0f);
422 }
423
424 if (y[0] != 0.0f) {
425
426 a.insert(a.begin(), x[0]);
427
428 b.insert(b.begin(), 0.0f);
429 }
430
431 _plstream->fill(a.size(), a.data(), b.data());
432 }
433 }
434
435 _plstream->col0(lookUpColor(curve->getColor()));
436
437 if (curve->getSymbol() == 0) {
438
439 _plstream->lsty(static_cast<PLINT>(curve->getLineStyle()));
440
441 _plstream->width(curve->getLineWidth());
442
443 _plstream->line(n, x, y);
444 } else {
445
446 _plstream->ssym(_defaultcharacterheight, curve->getSymbolSize());
447
448 _plstream->poin(n, x, y, curve->getSymbol());
449 }
450 } break;
451 case CanvasItem::Type::I_Text: {
452
453 Text *text = dynamic_cast<Text *>(p.get());
454
455 _plstream->col0(lookUpColor(text->getColor()));
456
457 _plstream->width(plot->getLineWidth());
458
459 _plstream->lsty(static_cast<PLINT>(plot->getLineStyle()));
460
461 _plstream->schr(_defaultcharacterheight, text->getSize());
462
463 if (text->getSystem() == Text::CoordinateSystem::DATA) {
464
465 _plstream->ptex(text->getCoordinates().at(0),
466 text->getCoordinates().at(1),
467 (xmax - xmin) * cosf(M_PI * text->getAngle() / 180.0),
468 (ymax - ymin) * sinf(M_PI * text->getAngle() / 180.0),
469 text->getJustification(), text->getText().data());
470 } else if (text->getSystem() == Text::CoordinateSystem::NORMAL) {
471
472 _plstream->ptex(xmin + (xmax - xmin) * text->getCoordinates().at(0),
473 ymin + (ymax - ymin) * text->getCoordinates().at(1),
474 (xmax - xmin) * cosf(M_PI * text->getAngle() / 180.0),
475 (ymax - ymin) * sinf(M_PI * text->getAngle() / 180.0),
476 text->getJustification(), text->getText().data());
477 }
478 } break;
479 case CanvasItem::Type::I_Panels:
480 default:
481
482 throw(Exception("Unsupported graphics type"));
483 break;
484 }
485 }
486
487 _plstream->col0(lookUpColor(plot->getColor()));
488
489 _plstream->lsty(static_cast<PLINT>(plot->getLineStyle()));
490
491 _plstream->width(plot->getLineWidth());
492
493 _plstream->schr(_defaultcharacterheight, plot->getFontSize());
494
495 _plstream->smaj(_defaultticklength, plot->getMajorTickLength());
496
497 _plstream->smin(_defaultticklength, plot->getMinorTickLength());
498
499 for (auto &ax : plot->getXAxis()) {
500
501 _plstream->sxax(ax.getMaxDigits(), ax.getPrecision());
502
503 if (ax.getAxisOptString().find('n') != std::string::npos &&
504 ax.getStyle() == Axis::Style::WritePowerInFrame) {
505
506 float order;
507
508 order = floor(log10(xmax));
509
510 if (std::abs(order) > 1.0) {
511
512 std::ostringstream ostr;
513
514 ostr << "(x10#u" << order << "#d)";
515
516 _plstream->ptex(0.9 * (xmax - xmin) + xmin, 0.05 * (ymax - ymin) + ymin,
517 xmax, 0.0, 0.0, ostr.str().c_str());
518
519 xmin /= pow(10, order);
520
521 xmax /= pow(10, order);
522 }
523 }
524
525 if (ax.getStyle() != Axis::Style::Default) {
526
527 _plstream->wind(xmin, xmax, ymin, ymax);
528 }
529
530 if (ax.getTickFinder()) {
531
532 std::string axisoptstr(ax.getAxisOptString());
533
534 const std::string opts("mnst");
535
536 std::string::size_type i;
537 for (const char opt : opts) {
538
539 if ((i = axisoptstr.find(opt)) != std::string::npos) {
540
541 axisoptstr.erase(i, 1);
542 }
543 }
544
545 _plstream->axes(0.0, 0.0, axisoptstr.data(), 0, 0, "", 0, 0);
546
547 PLFLT p_xmin, p_xmax, p_ymin, p_ymax;
548
549 _plstream->gspa(p_xmin, p_xmax, p_ymin, p_ymax);
550
551 PLFLT dx = abs(xmax - xmin);
552
553 double dy = (axisoptstr.find('i') == std::string::npos ? -1.0 : 1.0) *
554 (ymax - ymin) * _defaultticklength *
555 plot->getMajorTickLength() /
556 ((plot->getYMargins().at(1) - plot->getYMargins().at(0)) *
557 (p_ymax - p_ymin));
558
559 PLFLT ticks[16];
560
561 PLINT nticks = ax.getTickFinder()(PL_X_AXIS, sizeof(ticks), ticks, xmin,
562 xmax, nullptr);
563
564 for (PLINT i = 0; i < nticks; i++) {
565
566 _plstream->join(ticks[i], ymax + dy, ticks[i], ymax);
567
568 double pos = (ticks[i] - xmin) / dx;
569
570 if (xmin > xmax) {
571
572 pos = (xmin - ticks[i]) / dx;
573 }
574
575 char label[16];
576
577 if (ax.getLabelFormatter()) {
578
579 ax.getLabelFormatter()(PL_X_AXIS, ticks[i], label, sizeof(label),
580 nullptr);
581 } else {
582
583 snprintf(label, sizeof(label), "%g", ticks[i]);
584 }
585
586 _plstream->mtex("t", 1.5, pos, 0.5, label);
587 }
588 } else {
589
590 _plstream->slabelfunc(ax.getLabelFormatter(), nullptr);
591
592 _plstream->axes(0.0, 0.0, ax.getAxisOptString().data(), 0, 0, "", 0, 0);
593 }
594
595 if (ax.getAxisOptString().find('m') != std::string::npos) {
596
597 _plstream->mtex("t", 3.5, 0.5, 0.5, ax.getTitle().data());
598 } else {
599
600 _plstream->mtex("b", 3.5, 0.5, 0.5, ax.getTitle().data());
601 }
602 }
603
604 for (auto &ax : plot->getYAxis()) {
605
606 _plstream->syax(ax.getMaxDigits(), ax.getPrecision());
607
608 if (ax.getAxisOptString().find('n') != std::string::npos &&
609 ax.getStyle() == Axis::Style::WritePowerInFrame) {
610
611 float order;
612
613 order = floor(log10(ymax));
614
615 if (std::abs(order) > 1.0) {
616
617 std::ostringstream ostr;
618
619 ostr << "(x10#u" << order << "#d)";
620
621 _plstream->ptex(0.05 * (xmax - xmin) + xmin, 0.9 * (ymax - ymin) + ymin,
622 (xmax - xmin), 0.0, 0.0, ostr.str().c_str());
623
624 ymin /= pow(10, order);
625
626 ymax /= pow(10, order);
627 }
628 }
629
630 if (ax.getStyle() != Axis::Style::Default) {
631
632 _plstream->wind(xmin, xmax, ymin, ymax);
633 }
634
635 if (ax.getTickFinder()) {
636
637 std::string axisoptstr(ax.getAxisOptString());
638
639 const std::string opts("mnst");
640
641 std::string::size_type i;
642 for (const char opt : opts) {
643
644 if ((i = axisoptstr.find(opt)) != std::string::npos) {
645
646 axisoptstr.erase(i, 1);
647 }
648 }
649
650 _plstream->axes(0.0, 0.0, axisoptstr.data(), 0, 0, "", 0, 0);
651
652 PLFLT p_xmin, p_xmax, p_ymin, p_ymax;
653
654 _plstream->gspa(p_xmin, p_xmax, p_ymin, p_ymax);
655
656 double dx = (axisoptstr.find('i') == std::string::npos ? -1.0 : 1.0) *
657 (xmax - xmin) * _defaultticklength *
658 plot->getMajorTickLength() /
659 ((plot->getXMargins().at(1) - plot->getXMargins().at(0)) *
660 (p_xmax - p_xmin));
661
662 PLFLT dy = abs(ymax - ymin);
663
664 PLFLT ticks[16];
665
666 PLINT nticks = ax.getTickFinder()(PL_Y_AXIS, sizeof(ticks), ticks, ymin,
667 ymax, nullptr);
668
669 for (PLINT i = 0; i < nticks; i++) {
670
671 _plstream->join(xmax + dx, ticks[i], xmax, ticks[i]);
672
673 double pos = (ticks[i] - ymin) / dy;
674
675 if (ymin > ymax) {
676
677 pos = (ymin - ticks[i]) / dy;
678 }
679
680 char label[16];
681
682 if (ax.getLabelFormatter()) {
683
684 ax.getLabelFormatter()(PL_Y_AXIS, ticks[i], label, sizeof(label),
685 nullptr);
686 } else {
687
688 snprintf(label, sizeof(label), "%g", ticks[i]);
689 }
690
691 _plstream->mtex("l", 1.5, pos, 0.5, label);
692 }
693 } else {
694
695 _plstream->slabelfunc(ax.getLabelFormatter(), nullptr);
696
697 _plstream->axes(0.0, 0.0, "", 0, 0, ax.getAxisOptString().data(), 0, 0);
698 }
699
700 if (ax.getAxisOptString().find('m') != std::string::npos) {
701
702 _plstream->mtex("r", 3.5, 0.5, 0.5, ax.getTitle().data());
703 } else {
704
705 _plstream->mtex("l", 3.5, 0.5, 0.5, ax.getTitle().data());
706 }
707 }
708}
Definition Curve.h:11
Definition Line.h:9
Definition Plot.h:20
Definition Point.h:11
Definition Text.h:13

From FY2025 onward the NASA Ames PAH IR Spectroscopic Database is being supported through the Laboratory Astrophysics Round 3 directed Work Package at NASA Ames.
From FY2023-2025 the NASA Ames PAH IR Spectroscopic Database was supported through the Laboratory Astrophysics Round 2 directed Work Package at NASA Ames.
From FY2019-2022 the NASA Ames PAH IR Spectroscopic Database was supported through a directed Work Package at NASA Ames titled: "Laboratory Astrophysics – The NASA Ames PAH IR Spectroscopic Database".
© Copyright 2021-2025, Christiaan Boersma