Вычесть один круг из другого в SVG

Я пытаюсь найти способ вычесть одну фигуру из другой в SVG, создавая отверстие в середине или укус из его стороны. Что-то вроде обрезной дорожки, но вместо того, чтобы показывать пересечение, я хочу показать одну из частей вне пересечения. решение задействовано использование Adobe Flex, но я не знал, как его правильно реализовать. Я понимаю, что есть способ сделать это в Inkscape, используя логические операции путь, но я хочу сохранить круг элементы так, как они есть, вместо того, чтобы превращать их в элементы пути.

<defs>
    <subtractPath id="hole">
        <circle r="50" cx="100" cy="100" />
    </subtractPath>
</defs>
<circle id="donut" r="100" cx="100" cy="100" subtract-path="url(#hole)" />

4 ответов


маска-это то, что вы хотите. Чтобы создать <mask> делают вещи, которые вы хотите оставить белыми. То, что ты хочешь быть невидимым, становится черным. Цвета между ними приведут к прозрачности.

таким образом, результирующий SVG похож на вашу псевдо-разметку и выглядит так:

<svg width="200" height="200">
  <defs>
    <mask id="hole">
      <rect width="100%" height="100%" fill="white"/>
      <circle r="50" cx="100" cy="100" fill="black"/>
    </mask>
  </defs>

  <circle id="donut" r="100" cx="100" cy="100" mask="url(#hole)" />
    
</svg>

мы заполняем маску белым прямоугольником, а затем ставим черный круг там, где мы хотим, чтобы отверстие было.


фокус в том, чтобы использовать заполнить-правила для управления отображением пути клипа. Пример (квадратного) пончика будет

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg"
 width="300" height="300">
<defs>
</defs>
   <g transform="translate(50, 50)">
      <path d="M 0 0 L 0 200 L 200 200 L 200 0 z
               M 50 50 L 50 150 L 150 150 L 150 50 z" fill-rule="evenodd"/>
   </g>
</svg>

который использует свойство fill-rule фигур для удаления внутреннего квадрата - вы можете настроить это с помощью путей Безье, чтобы создать круг по мере необходимости.

после того, как вы создали основной путь отсечения, вы можете создать путь отсечения из него - см. эта запись MDN для получения информации о clip-path.


/ * / Mask: используется для вычитания объектов:

/ => fill= "white" = > блоки для отображения
/ = > fill= "black" = > блоки для удаления

/ => fill= "white" = > поместите блок отображения также внутри тега маски и заполните белым
|=> fill= "black" = > поместите блок удаления внутри тега маски и заполните черный

|:: / пример использования маски для удаления центральной малой прямой кишки из большой прямой кишки

<rect x="20" y="20" width="60" height="60" mask="url(#rmvRct)"/>
<mask id="rmvRct">
    <rect x="20" y="20" width="60" height="60" fill="white"/>
    <rect x="40" y="40" width="20" height="20" fill="black"/>
</mask>

|::| пример использования маски для удаления центр малого круга от большого круга:

<circle cx="50" cy="50" r="45" mask="url(#rmvCir)"/>
<mask id="rmvCir">
    <circle cx="50" cy="50" r="45" fill="white"/>
    <circle cx="50" cy="50" r="25" fill="black"/>
</mask>

два ответа предлагают (1) использовать или (2) использовать атрибут "fill-rule=evenodd" для вычитания фигуры B по форме на (A ∖ B).

оба предложенных ответа решают "дыру в середине"(B ⊆ A) часть вопроса, но только маска подход является разумным решением для части "укус из стороны"(B ⊈ A). С помощью evenodd fill-rule означает две фигуры обрабатываются одинаково, поэтому часть второй фигуры, которая не пересекает первую, будет частью результата. Чтобы откусить что-то от формы, "кусающая" форма должна была бы разделить часть своей границы с укушенной формой. На практике это может оказаться затруднительным.

пример: чтобы вычесть круг из другого круга, вам нужно будет создать" кусающую " форму, которая является пересечением двух кругов.

подход маски много более универсальный.