NCBI C++ ToolKit
svg_renderer.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: svg_renderer.cpp 47292 2022-12-21 00:32:34Z evgeniev $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Vladislav Evgeniev
27  *
28  * File Description: SVG file rendering
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
34 #include <sstream>
35 #include <iomanip>
36 #include <numeric>
37 
39 #include <gui/print/svg.hpp>
40 #include <gui/opengl/glutils.hpp>
41 #include <gui/opengl/glpane.hpp>
43 
44 #include <gui/utils/matrix4.hpp>
45 #include <gui/utils/matrix3.hpp>
46 
48 
49 #include <util/image/image.hpp>
50 #include <util/image/image_io.hpp>
51 #include <util/md5.hpp>
52 
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 ////////////////////////////////////////////////////////////////////////////////
57 
58 void CSVGRenderer::Initialize(const TVPRect& viewport)
59 {
60  static string svg_css = \
61  " <![CDATA[\n" \
62  "\t\t@import url(\"https://www.ncbi.nlm.nih.gov/projects/sviewer/css/svg_fonts.css\");\n" \
63  "\t]]>\n";
64 
65  m_Height = viewport.Height();
66 
67  m_SVG.reset(new svg::SVG(svg::ViewBox(0, 0, viewport.Width(), viewport.Height()), svg::Style(svg_css), NStr::XmlEncode("Generated by NCBI Genome Workbench http://www.ncbi.nlm.nih.gov/tools/gbench/")));
68 }
69 
71 {
72  m_SVG.reset();
76 }
77 
78 void CSVGRenderer::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
79 {
80  //CRenderVector::Viewport(x, m_Height - y - height, width, height);
81  CRenderVector::Viewport(x, y, width, height);
82 }
83 
84 void CSVGRenderer::Ortho(GLdouble left, GLdouble right,
85  GLdouble bottom, GLdouble top,
86  GLdouble nearVal, GLdouble farVal)
87 {
88  //CRenderVector::Ortho(left, right, top, bottom, nearVal, farVal);
89  CRenderVector::Ortho(left, right, bottom, top, nearVal, farVal);
90 }
91 
93  const CRgbaColor& color)
94 {
95  if (m_CurrentFont != NULL) {
96  LOG_POST("BeginText() called without first calling CSVGRenderer::EndText()");
97  return;
98  }
99 
100  m_CurrentFont = font;
102  m_TextColor = color;
103 }
104 
106 {
107  if (m_CurrentFont != NULL) {
108  LOG_POST("BeginText() called without first calling CSVGRenderer::EndText()");
109  return;
110  }
111 
112  m_CurrentFont = font;
115 }
116 
118 {
120  if (m_CurrentFont == NULL) {
121  LOG_POST("EndText() called without first calling CSVGRenderer::BeginText()");
122  return;
123  }
124 
127 }
128 
130  const char* text,
131  TModelUnit rotate_degrees)
132 {
134  if (m_CurrentFont == NULL) {
135  LOG_POST(Error << "Unable to write text - must call BeginText() first");
136  return;
137  }
138 
139  CVect2<float> origin((float)x, (float)y);
141  origin.Set(origin.X(), m_Height - origin.Y() - 1);
142 
143  string encoded_text = NStr::XmlEncode(text);
144  *m_SVG << svg::Text(origin, encoded_text, svg::Font(*m_CurrentFont), svg::Fill(m_TextColor), m_ClippingId, rotate_degrees);
145 }
146 
148  TModelUnit width, TModelUnit height,
149  const char* text,
152  TModelUnit rotate_degrees)
153 {
155  if (m_CurrentFont == NULL) {
156  LOG_POST(Error << "Unable to write text - must call BeginText() first");
157  return;
158  }
159 
160  CVect2<float> origin((float)x, (float)y);
161  if (align & CGlTextureFont::eAlign_HCenter) {
162  origin.Set((float)(x + width / 2.0), (float)y);
163  }
164  else if (align & CGlTextureFont::eAlign_Right) {
165  origin.Set((float)(x + width), (float)y);
166  }
167  if (align & CGlTextureFont::eAlign_VCenter) {
168  origin.Set(origin.X(), (float)(y + (height - m_CurrentFont->TextHeight()) / 2.0));
169  }
171  origin.Set(origin.X(), m_Height - origin.Y() - 1);
172 
173  string encoded_text = NStr::XmlEncode((trunc == CGlTextureFont::eTruncate_None) ? text : m_CurrentFont->Truncate(text, width, trunc));
174  *m_SVG << svg::Text(origin, encoded_text, svg::Font(*m_CurrentFont, align), svg::Fill(m_TextColor), m_ClippingId, rotate_degrees);
175 }
176 
178 {
179  m_SVG->WriteToStream(ostrm);
180  ostrm.flush();
181 }
182 
183 void CSVGRenderer::BeginClippingRect(GLint x, GLint y, GLsizei width, GLsizei height)
184 {
185  if (!m_ClippingId.empty())
187  m_ClippingId = x_ClippingRect(x, y, width, height);
188 }
189 
191 {
192  if (!m_ClippingStack.empty()) {
194  m_ClippingStack.pop();
195  }
196  else {
197  m_ClippingId.clear();
198  }
199 }
200 
202 {
203  MatrixMode(GL_MODELVIEW);
204  PushMatrix();
205 
206  for (size_t j = 0; j < node->GetPositions().size(); ++j) {
208  mat.Transpose();
209  LoadMatrixf(mat.GetData());
210 
211  if (node->GetDrawMode() == GL_LINES ||
212  node->GetDrawMode() == GL_LINE_STRIP ||
213  node->GetDrawMode() == GL_LINE_LOOP) {
214  x_PrintLineBuffer(*node);
215  }
216  if (node->GetDrawMode() == GL_POINTS) {
217  x_PrintPointBuffer(*node);
218  }
219  else if (node->GetDrawMode() == GL_TRIANGLES ||
220  node->GetDrawMode() == GL_TRIANGLE_FAN ||
221  node->GetDrawMode() == GL_TRIANGLE_STRIP) {
222  x_PrintTriBuffer(*node);
223  }
224  else if (node->GetDrawMode() == GL_QUADS) {
225  x_PrintQuadBuffer(*node);
226  }
227  }
228 
229  PopMatrix();
230 }
231 
233 {
234  _ASSERT(m_SVG);
235  vector<CVect2<float> > vertices;
236  vector<CRgbaColor> colors;
237 
238  node.Get2DVertexBuffer(vertices);
239  x_ProjectVertices(vertices);
240 
241  if (vertices.size() == 0)
242  return;
243 
244  GLushort pattern = 0xffff; // glLineStipple pattern
245  GLint factor = 1; // glLineStipple repeat factor
246  double width = 0.0; // linewidth
247  svg::Stroke::ELineCapStyle lcap{ svg::Stroke::eDefaultCap };
248  svg::Stroke::ELineJoinStyle ljoin{ svg::Stroke::eDefaultJoin };
249 
250  bool has_color = node.GetColors(colors, m_IsGreyscale);
251  // Use color buffer for color or, if none, use color in State.
252  CRgbaColor default_color;
253  node.GetDefaultColor(default_color, m_IsGreyscale);
254 
255  x_GetLineStyle(node, pattern, factor, width, lcap, ljoin);
256 
257  if (node.GetDrawMode() == GL_LINES) {
258  for (size_t i = 0; i < vertices.size(); i += 2) {
259  if (i + 1 >= vertices.size())
260  break;
261 
262  *m_SVG << svg::Line(vertices[i], vertices[i + 1], svg::Stroke(has_color ? colors[i] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
263  }
264  }
265  else if (node.GetDrawMode() == GL_LINE_STRIP) {
266  for (size_t i = 1; i < vertices.size(); i++) {
267  *m_SVG << svg::Line(vertices[i - 1], vertices[i], svg::Stroke(has_color ? colors[i - 1] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
268  }
269  }
270  else if (node.GetDrawMode() == GL_LINE_LOOP) {
271  for (size_t i = 1; i < vertices.size(); i++) {
272  *m_SVG << svg::Line(vertices[i - 1], vertices[i], svg::Stroke(has_color ? colors[i - 1] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
273  }
274  *m_SVG << svg::Line(vertices[0], vertices[vertices.size() - 1], svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
275  }
276 }
277 
279 {
280  _ASSERT(m_SVG);
281  vector<CVect2<float> > vertices;
282  vector<CRgbaColor> colors;
283 
284  node.Get2DVertexBuffer(vertices);
285  x_ProjectVertices(vertices);
286 
287  if (vertices.size() == 0)
288  return;
289 
290  bool has_color = node.GetColors(colors, m_IsGreyscale);
291 
292  // Use color buffer for color or, if none, use color in State, if set
293  CRgbaColor default_color;
294  node.GetDefaultColor(default_color, m_IsGreyscale);
295 
296  double width = 1; // pointsize
297  if (node.GetState().PointSizeSet()) {
298  width = node.GetState().GetPointSize();
299  }
300 
301  if (node.GetDrawMode() == GL_POINTS) {
302  for (size_t i = 0; i < vertices.size(); ++i) {
303  *m_SVG << svg::Circle(vertices[i], width, svg::Fill(has_color ? colors[i] : default_color), svg::Stroke(), m_ClippingId);
304  }
305  }
306 }
307 
309 {
310  _ASSERT(m_SVG);
311  vector<CVect2<float> > vertices;
312  vector<CRgbaColor> colors;
313 
314  node.Get2DVertexBuffer(vertices);
315  x_ProjectVertices(vertices);
316 
317  if (vertices.size() == 0)
318  return;
319 
320  vector<CRgbaColor> gradient;
321  bool has_color = node.GetColors(colors, m_IsGreyscale);
322  bool flat_shading = (node.GetState().GetShadeModel() == GL_FLAT);
323  if (has_color && !flat_shading) {
324  x_GetGradientColors(vertices, colors, gradient);
325  }
326 
327  // Use color buffer for color or, if none, use color in State, if set
328  CRgbaColor default_color;
329  node.GetDefaultColor(default_color, m_IsGreyscale);
330 
331  GLushort pattern = 0xffff; // glLineStipple pattern
332  GLint factor = 1; // glLineStipple repeat factor
333  double width = 0.0; // linewidth
334  svg::Stroke::ELineCapStyle lcap{ svg::Stroke::eDefaultCap };
335  svg::Stroke::ELineJoinStyle ljoin{ svg::Stroke::eDefaultJoin };
336 
337  // GL_LINE or GL_FILL
338  bool filled = true;
339  if (node.GetState().GetPolygonMode() == GL_LINE) {
340  filled = false;
341 
342  x_GetLineStyle(node, pattern, factor, width, lcap, ljoin);
343  }
344 
345  string fill_pattern;
346  if (node.GetState().IsEnabled(GL_POLYGON_STIPPLE) && node.GetState().PolygonStippleSet()) {
347  fill_pattern = x_PolygonStippleToPattern(node.GetState().GetPolygonStipple(), has_color ? colors[0] : default_color);
348  }
349 
350  svg::Fill fill;
351  if (!fill_pattern.empty()) {
352  fill = svg::Fill((string const&)fill_pattern);
353  }
354  else if (gradient.size() > 1) {
355  fill = svg::Fill((string const&)x_LinearGradient(gradient));
356  }
357  else {
358  fill = svg::Fill(has_color ? colors[0] : default_color);
359  }
360 
361  if (node.GetDrawMode() == GL_TRIANGLES) {
362 
363  CTriPerimeter tp;
364  bool uniform_color{ true };
365  for (size_t i = 0; i < vertices.size(); i += 3) {
366  if (i + 2 >= vertices.size())
367  break;
368 
369  if (has_color && flat_shading) {
370  if (!(colors[i] == colors[0])) {
371  tp.Clear();
372  uniform_color = false;
373  break;
374  }
375  }
376 
377  tp.AddTri(vertices[i], vertices[i + 1], vertices[i + 2]);
378  }
379  // Can we convert this into a single perimeter?
380  vector<CVect2<float> > perimeter = tp.GetPerimiter();
381 
382  if (perimeter.size() > 2 && filled) {
383  *m_SVG << svg::Polygon(perimeter, fill, svg::Stroke(), m_ClippingId);
384  }
385  else {
386  if (uniform_color && !gradient.empty()) {
387  fill = svg::Fill(has_color ? colors[0] : default_color);
388  }
389 
390  for (size_t i = 0; i < vertices.size(); i += 3) {
391  if (i + 2 >= vertices.size())
392  break;
393 
394  vector<CVect2<float> > triangle;
395  triangle.push_back(vertices[i]);
396  triangle.push_back(vertices[i + 1]);
397  triangle.push_back(vertices[i + 2]);
398 
399  if (filled) {
400  if (uniform_color)
401  *m_SVG << svg::Polygon(triangle, fill, svg::Stroke(), m_ClippingId);
402  else
403  *m_SVG << svg::Polygon(triangle, svg::Fill(colors[i]), svg::Stroke(), m_ClippingId);
404  }
405  else {
406  *m_SVG << svg::Polygon(triangle, svg::Fill(), svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
407  }
408  }
409  }
410  }
411  else if (node.GetDrawMode() == GL_TRIANGLE_STRIP) {
412  bool uniform_color{ true };
413  CTriPerimeter tp;
414  for (size_t i = 2; i < vertices.size(); i++) {
415  tp.AddTri(vertices[i], vertices[i - 1], vertices[i - 2]);
416 
417  if (has_color && flat_shading) {
418  if (!(colors[i] == colors[0])) {
419  tp.Clear();
420  uniform_color = false;
421  break;
422  }
423  }
424  }
425 
426  // Can we convert this into a single perimeter?
427  vector<CVect2<float> > perimeter = tp.GetPerimiter();
428 
429  if (perimeter.size() > 2 && filled) {
430  *m_SVG << svg::Polygon(perimeter, fill, svg::Stroke(), m_ClippingId);
431  }
432  else {
433  for (size_t i = 2; i < vertices.size(); i++) {
434  vector<CVect2<float> > triangle;
435  triangle.push_back(vertices[i]);
436  triangle.push_back(vertices[i - 1]);
437  triangle.push_back(vertices[i - 2]);
438 
439  if (filled) {
440  if (uniform_color)
441  *m_SVG << svg::Polygon(triangle, fill, svg::Stroke(), m_ClippingId);
442  else
443  *m_SVG << svg::Polygon(triangle, svg::Fill(colors[i]), svg::Stroke(), m_ClippingId);
444  }
445  else {
446  *m_SVG << svg::Polygon(triangle, svg::Fill(), svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
447  }
448  }
449  }
450  }
451  else if (node.GetDrawMode() == GL_TRIANGLE_FAN) {
452  CVect2<float> v1p = vertices[0];
453 
454  vector<CVect2<float> > perimeter;
455  for (size_t i = 1; i < vertices.size(); i++) {
456  perimeter.push_back(vertices[i]);
457  }
458 
459  // would user maybe want perimiter for edges? The could have always
460  // just drawn edges for that, rather than tris.
461  if (filled) {
462  *m_SVG << svg::Polygon(perimeter, fill, svg::Stroke(), m_ClippingId);
463  }
464  else {
465  for (size_t i = 2; i < vertices.size(); i++) {
466  CVect2<float> v2p = vertices[i - 1];
467  CVect2<float> v3p = vertices[i];
468 
469  *m_SVG << svg::Line(v1p, v2p, svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
470  *m_SVG << svg::Line(v2p, v3p, svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
471  *m_SVG << svg::Line(v3p, v1p, svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
472  }
473  }
474  }
475 }
476 
478 {
479  _ASSERT(m_SVG);
480  vector<CVect2<float> > vertices;
481  vector<CRgbaColor> colors;
482 
483  node.Get2DVertexBuffer(vertices);
484  x_ProjectVertices(vertices);
485 
486  if (vertices.size() == 0)
487  return;
488 
489  bool has_color = node.GetColors(colors, m_IsGreyscale);
490 
491  // use color in State. Since triangles are flat, there is no color buffer
492  // (if we see a buffer we assume it is not flat)
493  CRgbaColor default_color;
494  node.GetDefaultColor(default_color, m_IsGreyscale);
495 
496  GLushort pattern = 0xffff; // glLineStipple pattern
497  GLint factor = 1; // glLineStipple repeat factor
498  double width = 1.0; // linewidth
499  svg::Stroke::ELineCapStyle lcap{ svg::Stroke::eDefaultCap };
500  svg::Stroke::ELineJoinStyle ljoin{ svg::Stroke::eDefaultJoin };
501 
502  // GL_LINE or GL_FILL
503  bool filled = true;
504  if (node.GetState().GetPolygonMode() == GL_LINE) {
505  filled = false;
506 
507  x_GetLineStyle(node, pattern, factor, width, lcap, ljoin);
508  }
509  svg::Fill fill(has_color ? colors[0] : default_color);
510 
511  for (size_t i = 3; i < vertices.size(); i += 4) {
512 
513  vector<CVect2<float> > quad;
514  quad.push_back(vertices[i - 3]);
515  quad.push_back(vertices[i - 2]);
516  quad.push_back(vertices[i - 1]);
517  quad.push_back(vertices[i]);
518 
519  if (filled) {
520  *m_SVG << svg::Polygon(quad, fill, svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
521  }
522  else {
523  *m_SVG << svg::Polygon(quad, svg::Fill(), svg::Stroke(has_color ? colors[0] : default_color, width, ljoin, (svg::Stroke::ELineCapStyle)lcap, pattern, factor), m_ClippingId);
524  }
525  }
526 }
527 
528 
529 
531 {
532  double px, py;
533  double dummyz;
534 
535  GLdouble model_view_matrix[16];
536  GLdouble projection_matrix[16];
537  GetModelViewMatrix(model_view_matrix);
538  GetProjectionMatrix(projection_matrix);
539 
540  gluProjectX(vertex.X(), vertex.Y(), 0.0, model_view_matrix, projection_matrix, m_Viewport, &px, &py, &dummyz);
541  vertex.Set(float(px), float(m_Height - py - 1));
542 }
543 
544 
545 inline void CSVGRenderer::x_ProjectVertices(vector<CVect2<float>>& vertices)
546 {
547  GLdouble model_view_matrix[16];
548  GLdouble projection_matrix[16];
549  GetModelViewMatrix(model_view_matrix);
550  GetProjectionMatrix(projection_matrix);
551 
552  for (auto& vertex : vertices) {
553  double px, py;
554  double dummyz;
555 
556  gluProjectX(vertex.X(), vertex.Y(), 0.0, model_view_matrix, projection_matrix, m_Viewport, &px, &py, &dummyz);
557  vertex.Set(float(px), float(m_Height - py - 1));
558  }
559 }
560 
561 string CSVGRenderer::x_PolygonStippleToPattern(const GLubyte* stipple, const CRgbaColor& fill_rgba_color)
562 {
563  string stipple_hash;
564  {
565  CMD5 md5;
566  md5.Update((const char*)stipple, sizeof(GLubyte) * 128);
567  string color = fill_rgba_color.ToString();
568  md5.Update(color.c_str(), color.length());
569  stipple_hash = md5.GetHexSum();
570  }
572  return m_PolygonStipplePatterns[stipple_hash];
573 
574  unsigned char fill_color[4];
575  fill_color[CImage::eRed] = fill_rgba_color.GetRedUC();
576  fill_color[CImage::eGreen] = fill_rgba_color.GetGreenUC();
577  fill_color[CImage::eBlue] = fill_rgba_color.GetBlueUC();
578  fill_color[CImage::eAlpha] = fill_rgba_color.GetAlphaUC();
579  unsigned char empty_color[4];
580  empty_color[CImage::eRed] = 0xff;
581  empty_color[CImage::eGreen] = 0xff;
582  empty_color[CImage::eBlue] = 0xff;
583  empty_color[CImage::eAlpha] = 0x00;
584  CImage stipple_pttn(32, 32, 4);
585  unsigned k = 0;
586  for (unsigned i = 0; i < 128; ++i) {
587 
588  for (int j = 7; j >= 0; j--) {
589 
590  size_t y = (k % 32);
591  size_t x = 31 - (k / 32);
592 
593  if (stipple[i] & (1 << j)) {
594  memcpy(stipple_pttn(x, y), fill_color, sizeof(fill_color));
595  }
596  else {
597  memcpy(stipple_pttn(x, y), empty_color, sizeof(empty_color));
598  }
599  k++;
600  }
601  }
602  std::stringstream ss;
603  CImageIO::WriteImage(stipple_pttn, ss, CImageIO::ePng);
604  string pattern_id("polygon-stipple");
606  m_PolygonStipplePatterns[stipple_hash] = pattern_id;
607 
608  *m_SVG << svg::Pattern(pattern_id, svg::Image("data:image/png;base64," + CStringUtil::base64Encode(ss.str())));
609 
610  return pattern_id;
611 }
612 
613 string CSVGRenderer::x_LinearGradient(std::vector<CRgbaColor> const& colors)
614 {
615  string gradient_hash;
616  {
617  CMD5 md5;
618  for (auto const& color : colors) {
619  string color_str = color.ToString();
620  md5.Update(color_str.c_str(), color_str.length());
621  }
622  gradient_hash = md5.GetHexSum();
623  }
624  if (m_LinearGradients.end() != m_LinearGradients.find(gradient_hash))
625  return m_LinearGradients[gradient_hash];
626 
627  string gradient_id("gradient");
628  gradient_id += NStr::NumericToString(m_LinearGradients.size() + 1);
629  m_LinearGradients[gradient_hash] = gradient_id;
630 
631  *m_SVG << svg::LinearGradient(gradient_id, colors);
632 
633  return gradient_id;
634 }
635 
636 string CSVGRenderer::x_ClippingRect(GLint x, GLint y, GLsizei width, GLsizei height)
637 {
638  string rect_hash;
639  {
640  CMD5 md5;
641  md5.Update((const char*)&x, sizeof(x));
642  md5.Update((const char*)&y, sizeof(y));
643  md5.Update((const char*)&width, sizeof(width));
644  md5.Update((const char*)&height, sizeof(height));
645  rect_hash = md5.GetHexSum();
646  }
647  if (m_ClippingRects.end() != m_ClippingRects.find(rect_hash))
648  return m_ClippingRects[rect_hash];
649 
650  string clipping_id("clipping-rect");
651  clipping_id += NStr::NumericToString(m_ClippingRects.size() + 1);
652  m_ClippingRects[rect_hash] = clipping_id;
653 
654  *m_SVG << svg::ClipRect(clipping_id, x, m_Height - y - 1, width, height);
655 
656  return clipping_id;
657 }
658 
659 void CSVGRenderer::x_GetGradientColors(vector<CVect2<float>> const& vertices, vector<CRgbaColor> const &colors, vector<CRgbaColor>& gradient)
660 {
661  vector<size_t> sorted_indices(vertices.size());
662  std::iota(std::begin(sorted_indices), std::end(sorted_indices), 0);
663  sort(sorted_indices.begin(), sorted_indices.end(),
664  [&vertices](const size_t& a, const size_t& b) -> bool
665  {
666  return vertices[a].Y() < vertices[b].Y();
667  });
668 
669  auto getColorAtY = [&vertices, &sorted_indices, &colors](float y)
670  {
671  size_t l{ 0 };
672  size_t r{ sorted_indices.size() - 1 };
673  while (l <= r) {
674  size_t m = l + (r - l) / 2;
675 
676  // Check if x is present at mid
677  if (vertices[sorted_indices[m]].Y() == y) {
678  return colors[sorted_indices[m]];
679  }
680  if ((r - l) <= 1) {
681  return CRgbaColor::Interpolate(colors[sorted_indices[l]], colors[sorted_indices[r]], 0.6f);
682  }
683 
684  if (vertices[sorted_indices[m]].Y() < y)
685  l = m + 1;
686  else
687  r = m - 1;
688  }
689  return CRgbaColor();
690  };
691 
692  gradient.push_back(colors[sorted_indices[0]]);
693  if (colors[sorted_indices[0]].ToHtmlString() == colors[sorted_indices[sorted_indices.size() - 1]].ToHtmlString()) {
694  float step = (vertices[sorted_indices[sorted_indices.size() - 1]].Y() - vertices[sorted_indices[0]].Y()) / 2;
695  auto color = getColorAtY(vertices[sorted_indices[0]].Y() + step);
696  gradient.push_back(color);
697  }
698  gradient.push_back(colors[sorted_indices[sorted_indices.size() - 1]]);
699 }
700 
701 inline void CSVGRenderer::x_GetLineStyle(CGlVboNode &node, GLushort &pattern, GLint &factor, double &width, svg::Stroke::ELineCapStyle &lcap, svg::Stroke::ELineJoinStyle &ljoin)
702 {
703  if (node.GetState().LineCapStyleSet()) {
704  lcap = (svg::Stroke::ELineCapStyle)(int)node.GetState().GetLineCapStyle();
705  }
706  if (node.GetState().LineJoinStyleSet()) {
707  ljoin = (svg::Stroke::ELineJoinStyle)(int)node.GetState().GetLineJoinStyle();
708  }
709  if (node.GetState().LineWidthSet()) {
710  width = node.GetState().GetLineWidth();
711  }
712  if (node.GetState().IsEnabled(GL_LINE_STIPPLE) && node.GetState().LineStippleSet()) {
713  node.GetState().GetLineStipple(factor, pattern);
714  }
715 }
716 
static int trunc
Definition: array_out.c:8
CGlVboNode A rendering node that holds a vertex buffer object.
Definition: glvbonode.hpp:64
static bool WriteImage(const CImage &image, CNcbiOstream &ostr, EType type, ECompress compress=eCompress_Default)
Definition: image_io.cpp:287
CImage –.
Definition: Image.hpp:66
@ eAlpha
Definition: image.hpp:81
@ eGreen
Definition: image.hpp:79
@ eBlue
Definition: image.hpp:80
@ eRed
Definition: image.hpp:78
Definition: md5.hpp:46
CGlVboNode m_RenderNode
vertex buffer node for rendering all Begin()/End() renders
CRgbaColor m_TextColor
color and alpha for text only (other GL options do not apply to text)
const CGlTextureFont * m_CurrentFont
text parameters
GLint m_Viewport[4]
current projection set by Viewport()
virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
virtual void Ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal)
virtual CMatrix4< float > GetModelViewMatrix() const
virtual void LoadMatrixf(const GLfloat *m)
virtual void PushMatrix()
virtual void MatrixMode(GLenum mode)
virtual void PopMatrix()
virtual CMatrix4< float > GetProjectionMatrix() const
class CRgbaColor provides a simple abstraction for managing colors.
Definition: rgba_color.hpp:58
Simple helper class to take a bunch of triangles and extract from that set, if possible,...
size_t AddTri(CVect2< float > &v1p, CVect2< float > &v2p, CVect2< float > &v3p)
std::vector< CVect2< float > > GetPerimiter() const
returns empty vec if no perimeter can be found.
size_type size() const
Definition: map.hpp:148
const_iterator end() const
Definition: map.hpp:152
void clear()
Definition: map.hpp:169
const_iterator find(const key_type &key) const
Definition: map.hpp:153
static const Colors colors
Definition: cn3d_colors.cpp:50
#define md5
Definition: compat-1.3.h:2022
#define NULL
Definition: ncbistd.hpp:225
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
void Set(T x, T y)
Definition: vect2.hpp:260
void Transpose()
Definition: matrix4.hpp:347
T & X()
Definition: vect2.hpp:107
const T * GetData() const
Definition: matrix4.hpp:103
T & Y()
Definition: vect2.hpp:109
GLenum GetShadeModel() const
Definition: glstate.hpp:240
GLdouble TModelUnit
Definition: gltypes.hpp:48
int gluProjectX(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *winx, GLdouble *winy, GLdouble *winz)
Definition: glutils.hpp:223
GLenum GetPolygonMode() const
Definition: glstate.hpp:276
void Get2DVertexBuffer(std::vector< CVect2< float > > &verts) const
Definition: glvbonode.cpp:159
bool GetDefaultColor(CRgbaColor &default_color, bool is_greyscale) const
Return default color from node in default_color.
Definition: glvbonode.cpp:207
bool LineWidthSet() const
Definition: glstate.hpp:231
T Height() const
Definition: glrect.hpp:90
bool GetColors(std::vector< CRgbaColor > &colors, bool is_greyscale) const
Definition: glvbonode.cpp:180
GLfloat GetLineWidth() const
Definition: glstate.hpp:230
T Width() const
Definition: glrect.hpp:86
CMatrix4< float > GetTransformedPosition(size_t idx)
return the position with rotation and pixel offset baked in
vector< CMatrix4< float > > & GetPositions()
return the current set of transformations for thisnode
GLfloat GetPointSize() const
Definition: glstate.hpp:235
CGlState & GetState()
bool LineCapStyleSet() const
Definition: glstate.hpp:345
bool IsEnabled(GLenum glstate) const
Return true if option is in m_Enabled list for this state.
Definition: glstate.cpp:371
void GetLineStipple(GLint &factor, GLushort &pattern) const
Definition: glstate.cpp:542
void BeginText() const
WriteText interface The WriteText functions produce the same results as TextOut but they are more eff...
bool PointSizeSet() const
Definition: glstate.hpp:236
bool LineJoinStyleSet() const
Definition: glstate.hpp:340
ELineCapStyle GetLineCapStyle() const
Definition: glstate.hpp:344
CRgbaColor GetColor() const
Definition: glstate.hpp:259
const GLubyte * GetPolygonStipple() const
Definition: glstate.hpp:286
void ProjectVertex(CVect2< float > &vertex) const
void EndText() const
Pops matrices and attributes after writing text.
virtual TModelUnit TextHeight(void) const
ELineJoinStyle GetLineJoinStyle() const
Definition: glstate.hpp:339
bool PolygonStippleSet() const
Definition: glstate.hpp:287
GLenum GetDrawMode() const
Return the current drawing mode (e.g.
Definition: glvbonode.hpp:90
ETruncate
Definition: glfont.hpp:62
string Truncate(const char *text, TModelUnit w, ETruncate trunc=eTruncate_Ellipsis) const
Truncate text to the secified width.
int TAlign
Definition: glfont.hpp:113
bool LineStippleSet() const
Definition: glstate.hpp:282
@ eAlign_Right
Definition: glfont.hpp:104
@ eAlign_VCenter
Definition: glfont.hpp:108
@ eAlign_HCenter
Definition: glfont.hpp:103
@ eTruncate_None
Definition: glfont.hpp:64
map< string, string > m_LinearGradients
void x_ProjectVertex(CVect2< float > &vertex)
virtual void Finalize()
virtual void Initialize(const TVPRect &viewport)
void x_ProjectVertices(vector< CVect2< float >> &vertices)
virtual void x_RenderBuffer(CGlVboNode *node)
string x_PolygonStippleToPattern(const GLubyte *stipple, const CRgbaColor &fill_rgba_color)
void x_PrintPointBuffer(CGlVboNode &node)
string x_LinearGradient(std::vector< CRgbaColor > const &colors)
virtual void WriteText(TModelUnit x, TModelUnit y, const char *text, TModelUnit rotate_degrees=0.0)
Write text at specified model coords.
std::stack< std::string > m_ClippingStack
virtual void EndClippingRect()
void x_PrintLineBuffer(CGlVboNode &node)
map< string, string > m_ClippingRects
map< string, string > m_PolygonStipplePatterns
virtual void Ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal)
virtual void EndText()
Pops matrices and attributes after writing text.
virtual void BeginText(const CGlTextureFont *font, const CRgbaColor &color)
Set OpenGL state needed for writing text (call before DrawText)
void x_GetGradientColors(vector< CVect2< float >> const &vertices, vector< CRgbaColor > const &colors, vector< CRgbaColor > &gradient)
void Write(CNcbiOstream &ostrm)
string x_ClippingRect(GLint x, GLint y, GLsizei width, GLsizei height)
void x_PrintQuadBuffer(CGlVboNode &node)
virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
virtual void BeginClippingRect(GLint x, GLint y, GLsizei width, GLsizei height)
void x_PrintTriBuffer(CGlVboNode &node)
std::string m_ClippingId
unique_ptr< svg::SVG > m_SVG
void x_GetLineStyle(CGlVboNode &node, GLushort &pattern, GLint &factor, double &width, svg::Stroke::ELineCapStyle &lcap, svg::Stroke::ELineJoinStyle &ljoin)
unsigned char GetRedUC(void) const
Get specific channels in unsigned char values.
Definition: rgba_color.hpp:345
string ToString(bool printAlpha=true, bool uchars=true) const
Return a string representation of the current color.
Definition: rgba_color.cpp:309
unsigned char GetGreenUC(void) const
Definition: rgba_color.hpp:351
unsigned char GetAlphaUC(void) const
Definition: rgba_color.hpp:363
static CRgbaColor Interpolate(const CRgbaColor &color1, const CRgbaColor &color2, float alpha)
Interpolate two colors.
Definition: rgba_color.cpp:444
unsigned char GetBlueUC(void) const
Definition: rgba_color.hpp:357
static string base64Encode(const string &str)
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
static string XmlEncode(const CTempString str, TXmlEncode flags=eXmlEnc_Contents)
Encode a string for XML.
Definition: ncbistr.cpp:4032
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
n background color
int i
CMD5 - class for computing Message Digest version 5 checksums.
static void text(MDB_val *v)
Definition: mdb_dump.c:62
constexpr auto sort(_Init &&init)
const struct ncbi::grid::netcache::search::fields::SIZE size
unsigned int a
Definition: ncbi_localip.c:102
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
static const GLdouble origin[]
#define _ASSERT
Modified on Fri Dec 01 04:51:13 2023 by modify_doxy.py rev. 669887