Подтвердить что ты не робот

Вычесть один круг из другого в 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)" />
4b9b3361

Ответ 1

Маска - это то, что вы хотите. Чтобы создать <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>

Ответ 2

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

<?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 для фигур для удаления внутреннего квадрата - вы можете настроить это, чтобы сделать это с помощью bezier-путей, чтобы создать круг по мере необходимости.

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

Ответ 3

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

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

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

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

<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>

Ответ 4

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

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

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

Подход маски гораздо более универсален.