Find Parallel or Offset SVG path

此生再无相见时 提交于 2019-12-06 16:37:19

Algorithmic solution

Offsetting lines is relatively trivial. For arcs, it is solvable by changing both radii by the same value. (You still have to find the end points.)

The problem are Bezier curves. There is a library bezier.js that solves this mathematically. For background, look at the accompaigning "Primer on Bézier Curves" by Pomax, especially the chapter on curve offsetting.

As is pointed out there, it is impossible to find a single Bezier curve that offsets another single curve; you need to divide it in "simpler" sub-parts. The library implements a function that combines these parts again and gives back the offset path: .offset(d).

Grafical solution

Vector grafic GUIs implement this sort of thing. The following describes it for Inkscape, but I am sure Adobe Illustrator (and maybe Sketch) can do more or less the same.

  • Draw your path. Inkscape has an "XML editor" where you can enter the path definition string directly.
  • Remove the fill and define a stroke with a width that is double the offset you want to achieve.
  • Choose "Stroke to Path" from the "Path" menu.
  • Choose "Break Apart" from the "Path" menu.
  • Now you have two (filled) paths, one offset to the outside, on offset to the inside; discard the one you don't need.

Note btw that your path definition is invalid. The arc between points [50, 0] and [100, 50] is given with a radius of 20, but the two points are 70.71 apart. In accordance with the spec, the path is instead drawn as

M 0,0 H 50 A 35.3553,35.3553 0 1 0 100,50 V 75 C 50,125 0,85 0,85 Z

If I find a path inset by 2 with Inkscape, I get

M 2,2 H 45.7988 C 34.2583,16.6514 35.0764,37.9045 48.5859,51.4141 62.0955,64.9236 83.3486,65.7417 98,54.2012
V 74.1094 C 73.6278,98.1373 49.7442,100.409 31.6426,96.7891 14.9635,93.4533 3.8673,85.3962 2,83.9785 Z

Note that Inkscape has computed a cubic Bezier approximation for the arc segment. You can revert to an arc simply by increasing the radii by 2, changing the large arc flag and retaining the end points:

M 2,2 H 45.7988 A 37.3533 37.3533 0 0 0 98,54.2012
V 74.1094 C 73.6278,98.1373 49.7442,100.409 31.6426,96.7891 14.9635,93.4533 3.8673,85.3962 2,83.9785 Z

I understand you have this path and you need to draw a line inside following the border. My solution is using the <feMorphology> filter with the operator="erode". I hope this is what you need.

<svg viewBox="-10 -10 120 120" width="300">
 <defs>
   
<filter id="erode">
<feMorphology in="SourceAlpha" result="eroded"
operator="erode" radius="2"/>
<feFlood flood-color="white" result="white" />
<feComposite in ="white" in2="eroded" operator="in" />
</filter>

   
<filter id="erode1">
<feMorphology in="SourceAlpha" result="eroded1"
operator="erode" radius="3"/>


</filter>
<path id="g" d="M0, 0
         H50
         A20, 20, 0, 1, 0, 100, 50
         V75
         C50, 125, 0, 85, 0, 85" />
</defs>

<use xlink:href="#g" />
<use xlink:href="#g" filter="url(#erode)" /> 
<use xlink:href="#g" filter="url(#erode1)" /> 
</svg>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!