Mercurial > octave
changeset 31798:82128f652585 stable
print: Add option to merge only subsequent triangles with SVG toolchain (bug #63646).
Trying to merge all triangles that are sharing an edge might take a long time.
But that might be necessary to avoid hairlines in figures containing patch or
surface graphics objects. Allow selecting if no, all, or only subsequent
triangles sharing an edge should be merged into a polygon.
* src/octave-svgconvert.cc (main): Distinguish between merging no (0), only
consecutive (1), or all (2) triangles into polygons.
(octave_polygon::reconstruct): Skip numerically expensive part of trying to
merge all polygons that are sharing an edge unless it was selected.
* scripts/plot/util/print.m: Document new options "-polymerge", "-nopolymerge",
and "-polymerge-all" for polygon merging with the SVG toolchain.
(svgconvert): Call "octave-svgconvert" with the selected polygon merge mode.
* scripts/plot/private/__print_parge_opts__.m: Select default value and parse
input for new options.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Tue, 31 Jan 2023 20:06:43 +0100 |
parents | 8b869c5d6ce8 |
children | 8825cedf5482 ed47b16ff624 |
files | scripts/plot/util/print.m scripts/plot/util/private/__print_parse_opts__.m src/octave-svgconvert.cc |
diffstat | 3 files changed, 45 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/plot/util/print.m Mon Jan 30 18:54:27 2023 +0100 +++ b/scripts/plot/util/print.m Tue Jan 31 20:06:43 2023 +0100 @@ -157,6 +157,20 @@ ## Caution: If Octave was built against Qt version earlier than 5.13, ## @option{-svgconvert} may lead to inaccurate rendering of image objects. ## +## @item -polymerge +## @itemx -nopolymerge +## @itemx -polymerge-all +## When using the SVG based backend @option{-svgconvert}, faces are rendered +## as triangles. In some cases, some viewers might display fine lines where +## those triangles share an edge. These options control whether all triangles +## that share edges are merged into polygons (@option{-polymerge-all} which +## might take some time for graphics consisting of many triangles -- including +## line markers), only consecutive polygons are merged (@option{-polymerge}), +## or no triangles are merged at all (@option{-no-polymerge}). By default, +## only consecutive triangles sharing an edge are merged, unless the printed +## figure contains patch or surface graphics objects in which case all +## triangles that are sharing an edge are merged. +## ## @item -portrait ## @itemx -landscape ## Specify the orientation of the plot for printed output. @@ -1160,7 +1174,8 @@ cmd = sprintf ('%s - %%s %3.2f "%s" %d "%%s"', ... undo_string_escapes (opts.svgconvert_binary), ... get (0, "screenpixelsperinch"), ... - undo_string_escapes (fullfile (fontdir, "FreeSans.otf")), 1); + undo_string_escapes (fullfile (fontdir, "FreeSans.otf")), + opts.polymerge); if (opts.debug) fprintf ("svgconvert command: '%s'\n", cmd);
--- a/scripts/plot/util/private/__print_parse_opts__.m Mon Jan 30 18:54:27 2023 +0100 +++ b/scripts/plot/util/private/__print_parse_opts__.m Tue Jan 31 20:06:43 2023 +0100 @@ -59,6 +59,7 @@ arg_st.ghostscript.antialiasing_textalphabits = 4; arg_st.ghostscript.antialiasing_graphicsalphabits = 1; arg_st.lpr_binary = __quote_path__ (__find_binary__ ("lpr")); + arg_st.polymerge = 1; arg_st.name = ""; arg_st.orientation = ""; arg_st.pstoedit_binary = __quote_path__ (__find_binary__ ("pstoedit")); @@ -88,6 +89,11 @@ varargin(1) = []; endif + if (! isempty (findall (arg_st.figure, "type", "patch", ... + "-or", "type", "surface"))) + arg_st.polymerge = 2; + endif + for i = 1:numel (varargin) if (! ischar (varargin{i}) && ! iscellstr (varargin{i})) error ("print: input arguments must be a graphics handle or strings."); @@ -127,6 +133,12 @@ arg_st.svgconvert = true; elseif (strcmp (arg, "-nosvgconvert")) arg_st.svgconvert = false; + elseif (strcmp (arg, "-polymerge")) + arg_st.polymerge = 1; + elseif (strcmp (arg, "-nopolymerge")) + arg_st.polymerge = 0; + elseif (strcmp (arg, "-polymerge-all")) + arg_st.polymerge = 2; elseif (strcmp (arg, "-textspecial")) arg_st.special_flag = "textspecial"; elseif (strcmp (arg, "-fillpage"))
--- a/src/octave-svgconvert.cc Mon Jan 30 18:54:27 2023 +0100 +++ b/src/octave-svgconvert.cc Tue Jan 31 20:06:43 2023 +0100 @@ -165,10 +165,12 @@ void reset (void) { m_polygons.clear (); } - QList<QPolygonF> reconstruct (void) + QList<QPolygonF> reconstruct (int reconstruct_level) { if (m_polygons.isEmpty ()) return QList<QPolygonF> (); + else if (reconstruct_level < 2) + return m_polygons; // Once a polygon has been merged to another, it is marked unsuded QVector<bool> unused; @@ -753,7 +755,7 @@ parent_elt.removeChild (orig.at (ii)); } -void reconstruct_polygons (QDomElement& parent_elt) +void reconstruct_polygons (QDomElement& parent_elt, int reconstruct_level) { QDomNodeList nodes = parent_elt.childNodes (); QColor current_color; @@ -791,7 +793,8 @@ if (color != current_color) { // Reconstruct the previous series of triangles - QList<QPolygonF> polygons = current_polygon.reconstruct (); + QList<QPolygonF> polygons + = current_polygon.reconstruct (reconstruct_level); collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> > (replaced_nodes, polygons)); @@ -810,19 +813,20 @@ { if (current_polygon.count ()) { - QList<QPolygonF> polygons = current_polygon.reconstruct (); + QList<QPolygonF> polygons = current_polygon.reconstruct (reconstruct_level); collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> > (replaced_nodes, polygons)); replaced_nodes.clear (); current_polygon.reset (); } - reconstruct_polygons (elt); + reconstruct_polygons (elt, reconstruct_level); } } // Finish collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> > - (replaced_nodes, current_polygon.reconstruct ())); + (replaced_nodes, + current_polygon.reconstruct (reconstruct_level))); for (int ii = 0; ii < collection.count (); ii++) replace_polygons (parent_elt, collection[ii].first, collection[ii].second); @@ -880,7 +884,10 @@ * fmt: format of the output file. May be one of pdf or svg\n\ * dpi: device dependent resolution in screen pixel per inch\n\ * font: specify a file name for the default FreeSans font\n\ -* reconstruct: specify whether to reconstruct triangle to polygons (0 or 1)\n\ +* reconstruct: specify whether to reconstruct triangle to polygons\n\ + 0: no reconstruction (merging) of polygons\n\ + 1: merge consecutive triangles if they share an edge\n\ + 2: merge all triangles that share edges (might take a long time)\n\ * outfile: output file name\n"; if (strcmp (argv[1], "-h") == 0) @@ -981,8 +988,9 @@ } // Do basic polygons reconstruction - if (QString (argv[5]).toInt ()) - reconstruct_polygons (root); + int reconstruct_level = QString (argv[5]).toInt (); + if (reconstruct_level) + reconstruct_polygons (root, reconstruct_level); // Add custom properties to SVG add_custom_properties (root);