Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Can't use a Path as a clip mask in a Group #1788

Closed
keenancrane opened this issue Jun 10, 2024 · 1 comment
Closed

bug: Can't use a Path as a clip mask in a Group #1788

keenancrane opened this issue Jun 10, 2024 · 1 comment

Comments

@keenancrane
Copy link
Collaborator

Issue

[Note: this issue seems to have a one-line fix; see below.]

When trying to use a Path as a clip mask, the clipped shape does not appear. Here's an example program:

canvas {
  width = 400
  height = 400

  shape C = Circle {
    center: (0,0)
    r: 100
    fillColor: #ff0
    strokeColor: #f00
    strokeWidth: 1
  }
  shape P = Path {
    d: interpolatingSpline("closed", [ (112.508,119.145), (-34.327,78.639), (-112.209,-17.934), (4.291,-47.19), (104.491,-118.829), (80.272,12.394) ] )
      fillColor: #0a0
      strokeColor: #00f
      strokeWidth: 1
  }
  
   -- use the path as a clipping mask for the circle
   shape G = Group {
     shapes: [C]
     clipPath: clip(P)
   }
}

Basically this green shape should be used as a mask for the yellow circle:

shapes

But when we run the program, the canvas is blank.

Solution

Inspecting the SVG file, it seems that the Path (P) is wrapped in group tags <g> … </g>. These group tags are not generated by the Penrose renderer for other types of clipping masks (e.g., if we use a Rectangle rather than a Path for the clipping mask).

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 400 400" width="100%" height="100%">
 <g>
   <clipPath id="myClip">
     <g> <!-- THIS GROUP TAG SHOULDN'T BE HERE -->
       <path fill="#00aa00" fill-opacity="1" stroke="#0000ff" stroke-opacity="1" stroke-width="1" stroke-linecap="butt" d="M 312.508 80.855 C 283.85825 64.29375000000002 221.85225 87.09125 165.673 121.361 C 109.49375 155.63075 78.1365 186.47675 87.791 217.934 C 97.4455 249.39125 150.11599999999999 221.96625 204.291 247.19 C 258.466 272.41375 285.49575 333.725 304.491 318.829 C 323.48625 303.933 278.26775 247.0995 280.272 187.606 C 282.27625 128.1125 341.15774999999996 97.41625 312.508 80.855 Z "/>
       <title>canvas.B</title>
     </g> <!-- THIS GROUP TAG SHOULDN'T BE HERE -->
   </clipPath>
   <g clip-path="url(#myClip)">
     <circle fill="#ffff00" fill-opacity="1" cx="200" cy="200" stroke="#ff0000" stroke-opacity="1" stroke-width="1" r="100">
       <title>canvas.A</title>
     </circle>
   </g>
   <title>canvas.G</title>
 </g>
</svg>

Removing the group tags marked above (by editing the SVG) yields the proper image:

fixed

@keenancrane
Copy link
Collaborator Author

Now fixed in arc-mesh branch; see 00f0429

The issue was that we were using a self-closing <path/> tag, and putting it inside a group <g>...</g> so that we can also put markers for arrowheads within that group. Such grouping is not actually required by SVG! Rather, we were just doing it out of convenience: the RenderPath method (and other RenderShape methods) return only a single SVGGElement, rather than a list. So, as a kludge, we used an SVG group to effectively turn a list of elements. Naughty naughty.

For now, the solution is to only use a group if the path has arrowheads. This at least makes it possible to use a path as a clip mask, by omitting arrowheads. A better long-term fix would be to change these methods in our renderer so they return a list of SVGElements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants