Author Topic: Drawing a sine wave without going all gothic  (Read 31244 times)

0 Members and 1 Guest are viewing this topic.

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6911
  • Country: fi
    • My home page and email address
Re: Drawing a sine wave without going all gothic
« Reply #25 on: February 23, 2022, 05:08:08 am »
When doing contour fills to an arbitrary polygon or curve, things get really interesting when the contour curve (offset curve) intersects itself.

If you start each contour with the base polygon or curve having a specific direction (say, counterclockwise), then you only need to remove the parts of the contour curve that are drawn in the other direction (between intersection points; or the entire contour curve, if there are no self-intersections).

Another way is to test a single point in the contour curve (for the entire contour if no self-intersections, or a point per segment between two consecutive self-intersections) for the distance to the base polygon or curve.  If the distance is less than the contour offset, then one removes that contour curve segment.

At one point, I worked out the math needed for offsetting vinyl cutter blades for polygon shapes.  (The blade drags behind the actual device point/head, but rotates freely.)
I even wrote a script in Awk to do that for HPGL input and output, and it is used with a certain vinyl cutting software.  (The author is a friend, who I haven't been able to contact at all in a year and a half; about a third of a world away.)

For just drawing this kind of stuff, I warmly recommend Inkscape.  (Any other vector graphics application works fine, though.)
They all tend to use piecewise cubic Bézier curves for, well, curves; because that is the one that tends to be accelerated and widely used, from PostScript to SVG.
Obviously, there you can simply choose how you wish to stroke the curve.  The easiest way to control the shape of the circle/ellipse of the stroking "pen", is to simply do it with a circular pen and then scale the rectangular region containing the curve to match the circle aspect ratio.  If the stroke shape is angled, rotate the curve first by the stroke angle in the opposite direction, then scale, and then rotate back.

If one wanted to do this in SVG by hand, the coordinates are not difficult to calculate.  The only thing is to how to split the sine curve into cubic Béziers: quarter or half-waves, or something else.  The definition of the "best" approximation is the difficult thing, because one can measure the deviation in several different ways: most commonly the deviation is only measured along one axis only (since that then corresponds to the error of a single variable function at that point), but distance (numerically) or distance squared (linear least squares fitting) can also be used.  Since the SVG format internally supports linear transformations on a per-element basis, one could trivially support circular or ellipse shaped stroke "pens" at different stroke angles and radiuses.
 
The following users thanked this post: Someone

Offline RenateTopic starter

  • Super Contributor
  • ***
  • Posts: 1460
  • Country: us
Re: Drawing a sine wave without going all gothic
« Reply #26 on: February 23, 2022, 10:51:30 am »
When I'm generating static images I don't worry much about efficiency. All of the images in this thread were generated with code that uses SVG line segments for all the curves. I used to use Inkscape export to render to PNG. Just to be contradictory, I do begrudge how long an invocation on the command line of Inkscape takes. It also generates a 32 bit PNG with alpha, even when no alpha is required. I wrapped up Window's Direct2D renderer in a command and use my own PNG output routines to output minimal PNG files. Direct2D support of SVG is minimal, as in, it doesn't support <text>. :palm:
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6911
  • Country: fi
    • My home page and email address
Re: Drawing a sine wave without going all gothic
« Reply #27 on: February 23, 2022, 01:52:15 pm »
In Inkscape, I convert all texts to paths, by selecting a text thingy, then Edit > Select Same > Object type, then Path > Object to path, then Object > Ungroup, then Edit > Select Same > Fill and Stroke, and finally Path > Combine.

A lot of generated SVG files can be optimized in a similar fashion, by first repeatedly ungrouping all groups until no groups are left, then doing the above for all non-Path/Circle/Rectangle objects.  I've written some Inkscape extensions, but automatizing the above does not really work, because it also changes the element display order.

For batch conversion of SVG files to PNG, I recommend ImageMagick's convert, optionally followed by pngcrush -brute.

In Linux, I often use NetPBM tools to optimize PNG images:
    pngtopnm -background '#ffffff' -mix source.png | pnmquant N | pnmtopng -compress 9 > temp.png
    pngcrush -brute temp.png result.png >/dev/null 2>/dev/null
    rm -f temp.png
(via a script).  This also removes any unnecessary PNG chunks and the alpha channel.  All italic parts vary as needed.  Powers of two N work best in PNG, but sometimes the color quantizer needs a couple of extra entries to use the full power of two N.  Even with the pngcrush brute-force optimization stage, running it a few different times with different N and comparing the result to the original, is fast enough for me.

My scripts use an autodeleted temporary directory, via
Code: [Select]
#!/bin/bash
Work=$(mkdir -d) || exit 1
trap "rm -f '$Work'" EXIT

# use "$Work/" for temporary files, it will be autodeleted
so I can trivially run a couple of different conversions in parallel.
 
The following users thanked this post: SilverSolder


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf