Cutting out intersecting lines in SVG files using python - python-3.x

I am attempting to generate svgs where all the stuff in the middle of the outer ring of circles is removed. Ideally I would like this to all be in one path. So far I have tried calculating arcs and merging them with circle paths but that gets kinda messy. Is there a way to go through and collapse this all down to just one path or a clean series of paths.
[1]: https://i.stack.imgur.com/72PoK.png
Edit: Added The code for the svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" fill-rule="evenodd" height="1024" version="1.1" width="1024">
<defs/>
<polyline fill="none" points="512,312 512.0,512.0 668,387 512.0,512.0 707,557 512.0,512.0 599,692 512.0,512.0 425,692 512.0,512.0 317,557 512.0,512.0 356,387 512.0,512.0" stroke="green" stroke-width="1"/>
<polygon fill="none" points="512,312 668,387 707,557 599,692 425,692 317,557 356,387" stroke="green" stroke-linejoin="bevel" stroke-width="1"/>
<circle cx="512.0" cy="512.0" fill="none" r="200" stroke="purple" stroke-width="1"/>
<circle cx="512" cy="312" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="668" cy="387" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="707" cy="557" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="599" cy="692" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="425" cy="692" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="317" cy="557" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="356" cy="387" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
</svg>
Im using a module called Svgwrite to generate this

Here's a modified version of your SVG, where a mask has been used to blank out the interior of all your small outer circles.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" fill-rule="evenodd" height="1024" version="1.1" width="1024">
<defs>
<mask id="blank-circles">
<rect width="100%" height="100%" fill="white"/>
<!-- Holes where each of the outer circles are. -->
<!-- We are using <use> elements so we don't need to define the circles twice. -->
<use xlink:href="#c1" fill="black"/>
<use xlink:href="#c2" fill="black"/>
<use xlink:href="#c3" fill="black"/>
<use xlink:href="#c4" fill="black"/>
<use xlink:href="#c5" fill="black"/>
<use xlink:href="#c6" fill="black"/>
<use xlink:href="#c7" fill="black"/>
</mask>
</defs>
<!-- Mask is applied to all the elements via a parent <g> element -->
<g mask="url(#blank-circles)">
<polyline fill="none" points="512,312 512.0,512.0 668,387 512.0,512.0 707,557 512.0,512.0 599,692 512.0,512.0 425,692 512.0,512.0 317,557 512.0,512.0 356,387 512.0,512.0" stroke="green" stroke-width="1"/>
<polygon fill="none" points="512,312 668,387 707,557 599,692 425,692 317,557 356,387" stroke="green" stroke-linejoin="bevel" stroke-width="1"/>
<circle cx="512.0" cy="512.0" fill="none" r="200" stroke="purple" stroke-width="1"/>
<g fill="none" stroke="purple" stroke-width="1">
<!-- fill and stroke properties are moved to a parent <g> so that they
aren't applied when referenced from the <mask>. -->
<circle id="c1" cx="512" cy="312" r="66.66666666666667"/>
<circle id="c2" cx="668" cy="387" r="66.66666666666667"/>
<circle id="c3" cx="707" cy="557" r="66.66666666666667"/>
<circle id="c4" cx="599" cy="692" r="66.66666666666667"/>
<circle id="c5" cx="425" cy="692" r="66.66666666666667"/>
<circle id="c6" cx="317" cy="557" r="66.66666666666667"/>
<circle id="c7" cx="356" cy="387" r="66.66666666666667"/>
</g>
</g>
</svg>

Related

SVG using non-repetitive pattern as fill

I'm trying to use different SVG elements with a pattern as a fill, but the pattern doesn't get repeated for every element. I'm not sure if there's the possibility to repeat the pattern, but right now it looks as if there's a pattern and three circles create a mask over the pattern. What I want to achieve is the three circles clearly looking differently because each pattern resets for each circle and then it doesn't look 'cut out'.
I suppose a last-resort solution would be to create multiple patterns with different names for every element I use, then it'll work, but I'm hoping there's a less cumbersome way.
I tried:
Wrapping each element in a different SVG container
Appending ids to the elements and then in css target every id separately with the fill being the url
I made a codesandbox which shows my problem:
https://codesandbox.io/s/busy-ives-hv3rr?file=/index.html
The solution #herrstrietzel posted is one way to go.
Another solution is to create variants of your original pattern, but with a different origin. You specify the origin using the x and y attributes.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="a" patternUnits="userSpaceOnUse" width="65" height="65" patternTransform="scale(2) rotate(0)">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)"/>
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)"/>
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z"
stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)"/>
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)"/>
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)"/>
</pattern>
<pattern id="a2" href="#a" x="20" y="20"/>
<pattern id="a3" href="#a" x="45" y="50"/>
</defs>
<svg height="200" width="200">
<circle cx="50" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="100" cy="50" r="40" fill="url(#a2)" />
</svg>
<svg height="200" width="200">
<circle cx="50" cy="100" r="40" fill="url(#a3)" />
</svg>
</svg>
Another alternative is to switch to objectBoundingBox units. So that the pattern is relative the the object it is applied to.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="a" patternUnits="objectBoundingBox" width="65" height="65">
<g transform="scale(2)">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)"/>
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)"/>
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z"
stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)"/>
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)"/>
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)"/>
</g>
</pattern>
<pattern id="a2" href="#a" x="20" y="20"/>
<pattern id="a3" href="#a" x="45" y="50"/>
</defs>
<svg height="200" width="200">
<circle cx="50" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="100" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="50" cy="100" r="40" fill="url(#a)" />
</svg>
</svg>
Applying transforms like transform="translate(50 50)" (instead of fixed x/y positioning would do the trick.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="pattern-0" patternUnits="userSpaceOnUse" width="65" height="65" patternTransform="scale(2) rotate(0)" >
<g id="patternInner">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)" />
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)" />
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z" stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)" />
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)" />
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)" />
</g>
</pattern>
<pattern id="pattern-1" href="#pattern-0" x="80" y="80" patternTransform="scale(2) rotate(45)" />
</defs>
<circle cx="50" cy="50" r="40" fill="url(#pattern-0)" />
<circle cx="50" cy="50" r="50" fill="url(#pattern-0)" transform="translate(50 33)" />
<circle cx="50" cy="50" r="50" fill="url(#pattern-1)" transform="translate(50 33)" />
<rect x="0" y="0" width="50" height="50" stroke="#fff" stroke-width="1" transform="translate(10 60)" fill="url(#pattern-0)" />
</svg>
Worth noting: duplicating patterns for slightly modified usage is pretty straight forward, since the <pattern> element supports referencing/reusing previously defined patterns via href attribute (similar to <use>):
<pattern id="pattern-1" href="#pattern-0" x="80" y="80" patternTransform="scale(2) rotate(45)" />
Would result in a rotated pattern sharing all properties of the initially defined pattern.

Make a path get cut off by a circle

Is there a way to cut off a path when it is outside of a circle?
<svg width="100" height="100">
<circle cx="50" cy="50" r="50" fill="red" />
<path d="M0 0 L100 100" stroke-width="1px" stroke="black" />
</svg>
Is it possible to make that line stay inside the circle (and not be visible off of the circle) without changing the d="M200 175 L696 880" in the path?
You can use a clipPath to prevent things drawing outside another shape.
<svg width="100" height="100">
<clipPath id="clip">
<circle cx="50" cy="50" r="50" fill="red" />
</clipPath>
<circle cx="50" cy="50" r="50" fill="red" />
<path d="M0 0 L100 100" stroke-width="1px" stroke="black" clip-path="url(#clip)"/>
</svg>

Add a stroke to a clipped path

I'd like to display a stroke around the intersection of two circles.
Here's my code:
<clipPath id="clip">
<circle cx="100" cy="100" r="50" />
</clipPath>
<circle cx="150" cy="100" r="50" fill="red" clip-path="url(#clip)" stroke="black" />
The stroke of the clipped circle is getting clipped by the clipPath as well, but I'd like it to wrap around the intersection of both circles.
Just add half the stroke width to the radius of the clipping circle.
For instance, we have circles of radius 50 and stroke width 10. So we make the clipping circle have a radius of (50 + 5) = 55.
<svg>
<clipPath id="clip1">
<circle cx="100" cy="100" r="55" stroke="black" fill="none" stroke-width="5"/>
</clipPath>
<clipPath id="clip2">
<circle cx="150" cy="100" r="55" stroke="black" fill="red" stroke-width="5"/>
</clipPath>
<circle cx="150" cy="100" r="50" stroke="black" fill="red" stroke-width="10" clip-path="url(#clip1)" />
<circle cx="100" cy="100" r="50" stroke="black" fill="none" stroke-width="10" clip-path="url(#clip2)" />
</svg>
One option would be to have both circles act both as clip paths and as stroked circles.
<clipPath id="clip1">
<circle cx="100" cy="100" r="50" id="circle1" stroke="black" fill="none"/>
</clipPath>
<clipPath id="clip2">
<circle cx="150" cy="100" r="50" id="circle2" stroke="black" fill="red"/>
</clipPath>
<use xlink:href="#circle2" clip-path="url(#clip1)"/>
<use xlink:href="#circle1" clip-path="url(#clip2)"/>
Make sure the second <use> element is not filled because it would cover half of the stroke of the first <use> element.

How to Exclude Area inside of clippath in Svg

I want to hide anything that outside a rectangle. (this i have achieved with clipping successfully). but another condition is that, 'also hide anything that comes inside the black big circle'. Now how i can achieve that?
in below example, 'yellow circle' must be eliminated'.
see below images for detail
Original:-
Desired:-
Below is my Svg code:-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
</clipPath>
</svg>
Erik Dahlström is right, your clip can include the entire rectangle and the cutout for the circle. This way, anything you associate with #clip1 as the clip-path will not be visible inside your circle area. Here is what it looks like for your example:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<path d="M 50,50 l200 0 l0 200 l-200 0z M150,150 a30,30 1 0,0 60,0z M210,150 a30,30 1 0,0 -60,0z"/>
</clipPath>

invert SVG clip (show only outside path)

Is it possible to invert the action of a clip with SVG? I'd like to show the path between the two circles rather than inside the circles:
<svg width="50%" height="50%" viewbox="0 0 985 740" xmlns="http://www.w3.org/2000/svg">
<g>
<clipPath id="re8-clip" clip-rule="nonzero">
<rect id="sa11" x="763.0" y="176.5" width="70.0" height="25.0" rx="50" ry="50" fill="ForestGreen"/>
<rect id="sa12" x="516.0" y="127.5" width="70.0" height="25.0" rx="50" ry="50" fill="ForestGreen"/>
</clipPath>
<rect id="sa11" x="763.0" y="176.5" width="70.0" height="25.0" rx="50" ry="50" fill="ForestGreen"/>
<rect id="sa12" x="516.0" y="127.5" width="70.0" height="25.0" rx="50" ry="50" fill="ForestGreen"/>
</g>
<path stroke="Black" stroke-width="1.5" fill="none" d="M 798.0 189.0 551.0 140.0" clip-path="url(#re8-clip)"/>
</svg>
Following the link in Duopixel's comment, the problem can be solved using a mask:
<svg width="50%" height="50%" viewbox="0 0 985 740" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<defs>
<rect id="sa11" x="763.0" y="176.5" width="70.0" height="25.0" rx="50" ry="50" />
<rect id="sa12" x="516.0" y="127.5" width="70.0" height="25.0" rx="50" ry="50" />
</defs>
<mask id="re8-clip">
<rect id="bg" x="0" y="0" width="100%" height="100%" fill="white"/>
<use xlink:href="#sa11" fill="Black" />
<use xlink:href="#sa12" fill="Black" />
</mask>
<use xlink:href="#sa11" fill="ForestGreen" />
<use xlink:href="#sa12" fill="ForestGreen" />
<path stroke="Black" stroke-width="1.5" fill="none" d="M 798.0 189.0 551.0 140.0" mask="url(#re8-clip)"/>
</svg>
As a minor aside, does anybody know if it is possible for a mask to default to white, so the 'bg' rectangle is not necessary?

Resources