svg: generate 'outline path'

半腔热情 提交于 2019-12-17 16:14:03

问题


I have a set of coordinates that I turn into an svg path (using cubic beziers to make it smooth). When I apply a certain stroke width, I get the following result (the blue dots are my coordinates)

What I am interested in is to get a path that runs around the gray shape (like: pick any point on the gray/white border, and round around the shape until you're back at the starting point).

How would I go about computing such a path?

for reference, this is my svg info:

 <g>
  <title>number 3</title>
  <path d="m238,50c5.67569,-1.01351 11.8327,-3.8229 20.92029,-2.14724c8.68106,0.69732 14.21173,4.90255 18.07971,7.14724c6.23697,3.61945 13.47556,9.5931 15,18c1.07056,5.90372 1.17343,10.97649 -4,16c-6.76816,6.57204 -19.45392,9.57738 -25.69687,10.59046c-3.94836,0.64074 4.73492,3.29883 10.69687,5.40954c8.05417,2.85142 15,8 21,14c6,6 5.26578,10.94739 5.26578,17.03015c-2.4541,7.30975 -4.23343,11.08675 -11.26578,12.96985c-3.98279,1.0665 -11.92578,3.49756 -17,4c-8.95618,0.88684 -15.80411,2.97838 -26,0l-9.19197,-3.44464" id="svg_1" opacity="0.5" stroke-width="10" stroke-linejoin="round" stroke="#000000" fill="none"/>
 </g>

回答1:


I created the svgContour function that is thought for scenarios similar to this,
the resulting contour offset is not related to the stroke-width value and must be set as a parameter to the function.

At the moment it will find one offset side at a time, but running it once per sides you can solve this issue.

TLDR
Actually through svgContour you can find the contour of any svg shapes, currently it doesn't support fill-modes but one of the next goals is to implement that. it relies on getPathData() to get the pathData of any SVGGeometryElement, then this data goes through three phases:

  • redrawSteepCurve
    Premise: drawing a beizer-curve parallel to another isn't obtained just offsetting the points/control-points of the curve unless the curve is sufficiently flat (in this case the visual rendering will be fine); this method takes a SVGPathData and in case it finds a steep curve it splits it up until it's flat enough (return a visually equivalent SVGPathData).

  • contourPathData
    In this stage the pathData is dissambled in points, points are connected in segments, each segment is offsetted, an intersection point is then found for each contiguous segment ( what we get back is a list of offsetted points).

  • drawLine
    This phase places the points from step 2 in the pathData coming from step 1, and finally draws the contour.

An example:

const path = document.querySelector('path')

svgContour(path, 5)
svg {
  width: 100vw;
  height: 100vh
}
<script src="https://cdn.rawgit.com/fracalo/svg-contour/master/dist/svg-contour.js"></script>

<svg viewBox='300 0 100 200'>
  <g>
    <title>number 3</title>
    <path d="m238,50c5.67569,-1.01351 11.8327,-3.8229 20.92029,-2.14724c8.68106,0.69732 14.21173,4.90255 18.07971,7.14724c6.23697,3.61945 13.47556,9.5931 15,18c1.07056,5.90372 1.17343,10.97649 -4,16c-6.76816,6.57204 -19.45392,9.57738 -25.69687,10.59046c-3.94836,0.64074 4.73492,3.29883 10.69687,5.40954c8.05417,2.85142 15,8 21,14c6,6 5.26578,10.94739 5.26578,17.03015c-2.4541,7.30975 -4.23343,11.08675 -11.26578,12.96985c-3.98279,1.0665 -11.92578,3.49756 -17,4c-8.95618,0.88684 -15.80411,2.97838 -26,0l-9.19197,-3.44464"
    id="svg_1" opacity="0.5" stroke-width="10" stroke-linejoin="round" stroke="#000000" fill="none" />
  </g>
</svg>

the contour is traced !




回答2:


I'm not sure whether this solves your problem. It depends on what you want to do with the outline path.

PostScript has functionality for computing an outline for stroked paths which, when filling it, will produce the same visual output as stroking the original path. However, the resulting path data might be less elegant than you'd expect.

The following PostScript program (let's call it path2outlines.ps turns a PostScript path into a "fillable" SVG path:

%!
% First, we're converting to outlines.
strokepath

% This is just a string buffer
/S 99 string def

% This defines a procedure for printing coordinates to stdout
/printCoordinates {     % coord* number command
  print                 % coord* number
  array astore          % array
  {                     % coord
    ( )print            % coord
    //S cvs             % string
    print               % 
  }forall
  (\n)print
} bind def

% This iterates over the path segments and prints the SVG path data.
{2(M) printCoordinates}
{2(L) printCoordinates}
{6(C) printCoordinates}
{(Z\n)print}
pathforall

quit

You have to feed it data files like this (% starts a comment). Let's call this data.ps:

%!
% First, set up the graphics state parameters
% Equivalent to stroke-width="10"
10 setlinewidth 

% Equivalent to stroke-linejoin="round" (0 = miter, 1 = round, 2 = bevel)
1 setlinejoin

% Now, we're defining the path.
% Use postfix notation, i.e. first coordinates, then command.
% m/M = moveto
% l = rlineto
% L = lineto
% c = rcurveto
% C = curveto

238 50 moveto
5.67569 -1.01351 11.8327 -3.8229 20.92029 -2.14724 rcurveto
8.68106 0.69732 14.21173 4.90255 18.07971 7.14724 rcurveto
6.23697 3.61945 13.47556 9.5931 15 18 rcurveto
1.07056 5.90372 1.17343 10.97649 -4 16 rcurveto
-6.76816 6.57204 -19.45392 9.57738 -25.69687 10.59046 rcurveto
-3.94836 0.64074 4.73492 3.29883 10.69687 5.40954 rcurveto
8.05417 2.85142 15 8 21 14 rcurveto
6 6 5.26578 10.94739 5.26578 17.03015 rcurveto
-2.4541 7.30975 -4.23343 11.08675 -11.26578 12.96985 rcurveto
-3.98279 1.0665 -11.92578 3.49756 -17 4 rcurveto
-8.95618 0.88684 -15.80411 2.97838 -26 0 rcurveto
-9.19197 -3.44464 rlineto

Depending on the platform you're using, you can use Ghostscript to invoke it somewhat similar to:

gs -q data.ps path2outlines.ps > outlinePath.txt

Give it a try, but I'm not sure whether you will be satisfied. The complexity of the output might give a hint about the actual complexity of the problem. Especially self-intersecting paths are a problem.

Edit (speaking of problems): I believe that in general it's mathematically not possible to create a Bézier curve that is perfectly "parallel" to a given Bézier curve.




回答3:


This is very demanding. Honestly I doubt that you will able to write a sorce code that will do that, whithout a lib that will do it for you.

This technic is sometimes called "buffer". Like create a buffer around an object.

If you can use Programming lang C then you should look at LEDA library. In java I dont know anything, maybe the GeoTools lib.



来源:https://stackoverflow.com/questions/13416693/svg-generate-outline-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!