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

feat: renderer adds tightest viewbox metadata to SVG #1444

Merged
merged 7 commits into from
Jun 6, 2023
Merged

Conversation

rjainrjain
Copy link
Contributor

@rjainrjain rjainrjain commented Jun 1, 2023

Description

Resolves #1261.

This PR takes the approach described in #1261 of providing a way of

cropping a Penrose-generated diagram based on shape dimensions (e.g. bounding boxes)

by calculating the tightest cropped viewbox based on all shapes in the diagram and adding the viewbox values as metadata in the <penrose> tag in the exported SVG. Replacing the viewbox values with these cropped values will solve the problem of sub-production level diagram previews.

Implementation strategy and design decisions

Rather than modifying the generated SVG after the renderer is through with it, as initially planned, we calculate the cropped viewbox values using the bounding boxes of the shapes: Shape<Num> generated in RenderStatic, adding the metadata then as well. In DiagramPanel.tsx we add a check to create a new metadata tag if there is none, or simply to add children to the one ostensibly created in the RenderStatic step. In ExamplesBrowser.tsx we set the preview SVG's viewbox to the cropped values if the metadata is present, and display the SVG previews.

Examples with steps to reproduce them

In the Penrose editor, click on the first example and inspect the SVG. It should have the following metadata.

<penrose><croppedViewBox>32.315104085276914 0.7731797378698957 601.3836522786437 601.3836522786437</croppedViewBox></penrose>

After clicking the SVG download button in the editor, inspecting once more will show the following metadata.

<penrose><croppedViewBox>32.315104085276914 0.7731797378698957 601.3836522786437 601.3836522786437</croppedViewBox><version>0.1</version><variation>PlumvilleCapybara104</variation><sub>Set A, B, C, D, E, F, G

IsSubset(B, A)
IsSubset(C, A)
IsSubset(D, B)
IsSubset(E, B)
IsSubset(F, C)
IsSubset(G, C)

Not(Intersecting(E, D))
Not(Intersecting(F, G))
Not(Intersecting(B, C))

AutoLabel All
</sub><sty>canvas {
  width = 800
  height = 700
}

forall Set x {
  x.icon = Circle {
    strokeWidth : 0
  }

  x.text = Equation {
    string : x.label
    fontSize : "25px"
  }

  ensure contains(x.icon, x.text)
  encourage sameCenter(x.text, x.icon)
  x.textLayering = x.text above x.icon
}

forall Set x; Set y
where IsSubset(x, y) {
  ensure smallerThan(x.icon, y.icon)
  ensure disjoint(y.text, x.icon, 10)
  ensure contains(y.icon, x.icon, 5)
  x.icon above y.icon
}

forall Set x; Set y
where Not(Intersecting(x, y)) {
  ensure disjoint(x.icon, y.icon)
}

forall Set x; Set y
where Intersecting(x, y) {
  ensure overlapping(x.icon, y.icon)
  ensure disjoint(y.text, x.icon)
  ensure disjoint(x.text, y.icon)
}
</sty><dsl>type Set

predicate Not(Prop p1)
predicate Intersecting(Set s1, Set s2)
predicate IsSubset(Set s1, Set s2)
</dsl></penrose>

Checklist

  • I have commented my code, particularly in hard-to-understand areas
  • I have reviewed any generated registry diagram changes

Open questions

Whether to provide an option in the editor to switch to cropped view.

@github-actions
Copy link

github-actions bot commented Jun 1, 2023

± Registry diff

M	animation/center-shrink-circle.svg
M	atoms-and-bonds/one-water-molecule.svg
M	atoms-and-bonds/wet-floor.svg
M	curve-examples/blobs.svg
M	curve-examples/closed-elastic-curve.svg
M	curve-examples/cubic-bezier.svg
M	curve-examples/open-elastic-curve.svg
M	curve-examples/space-curves.svg
M	exterior-algebra/vector-wedge.svg
M	fake-3d-linear-algebra/projection.svg
M	geometric-queries/closest-point/test-group.svg
M	geometric-queries/closest-point/test.svg
M	geometric-queries/closest-silhouette-point/test.svg
M	geometric-queries/ray-intersect/test-group.svg
M	geometric-queries/ray-intersect/test.svg
M	geometric-queries/test.svg
M	geometry-domain/siggraph-teaser.svg
M	geometry-domain/textbook_problems/c01p01.svg
M	geometry-domain/textbook_problems/c03p01.svg
M	geometry-domain/textbook_problems/c05p01.svg
M	geometry-domain/textbook_problems/c05p13.svg
M	geometry-domain/textbook_problems/c11p12.svg
M	geometry-domain/textbook_problems/ex.svg
M	graph-domain/other-examples/arpanet.svg
M	graph-domain/other-examples/nyc-subway.svg
M	graph-domain/textbook/sec1/fig1.svg
M	graph-domain/textbook/sec1/fig10.svg
M	graph-domain/textbook/sec1/fig11.svg
M	graph-domain/textbook/sec1/fig12.svg
M	graph-domain/textbook/sec1/fig13.svg
M	graph-domain/textbook/sec1/fig2.svg
M	graph-domain/textbook/sec1/fig3.svg
M	graph-domain/textbook/sec1/fig4.svg
M	graph-domain/textbook/sec1/fig5.svg
M	graph-domain/textbook/sec1/fig6.svg
M	graph-domain/textbook/sec1/fig7.svg
M	graph-domain/textbook/sec1/fig8a.svg
M	graph-domain/textbook/sec1/fig8b.svg
M	graph-domain/textbook/sec1/fig9.svg
M	graph-domain/textbook/sec2/fig10a.svg
M	graph-domain/textbook/sec2/fig10b.svg
M	graph-domain/textbook/sec2/fig11a.svg
M	graph-domain/textbook/sec2/fig11b.svg
M	graph-domain/textbook/sec2/fig11c.svg
M	graph-domain/textbook/sec2/fig12.svg
M	graph-domain/textbook/sec2/fig13.svg
M	graph-domain/textbook/sec2/fig14.svg
M	graph-domain/textbook/sec2/fig16b.svg
M	graph-domain/textbook/sec2/fig3.svg
M	graph-domain/textbook/sec2/fig4.svg
M	graph-domain/textbook/sec2/fig5.svg
M	graph-domain/textbook/sec2/fig6.svg
M	graph-domain/textbook/sec2/fig9.svg
M	graph-domain/textbook/sec5/ex32.svg
M	group-theory/quaternion-cayley-graph.svg
M	group-theory/quaternion-multiplication-table.svg
M	hypergraph/hypergraph.svg
M	lagrange-bases/lagrange-bases.svg
M	linear-algebra-domain/two-vectors-perp.svg
M	logic-circuit-domain/half-adder.svg
M	matrix-ops/tests/matrix-matrix-addition.svg
M	matrix-ops/tests/matrix-matrix-division-elementwise.svg
M	matrix-ops/tests/matrix-matrix-multiplication-elementwise.svg
M	matrix-ops/tests/matrix-matrix-multiplication.svg
M	matrix-ops/tests/matrix-matrix-subtraction.svg
M	matrix-ops/tests/matrix-transpose.svg
M	matrix-ops/tests/matrix-vector-left-multiplication.svg
M	matrix-ops/tests/matrix-vector-right-multiplication.svg
M	matrix-ops/tests/scalar-vector-division.svg
M	matrix-ops/tests/scalar-vector-left-multiplication.svg
M	matrix-ops/tests/scalar-vector-right-multiplication.svg
M	matrix-ops/tests/vector-vector-addition.svg
M	matrix-ops/tests/vector-vector-division-elementwise.svg
M	matrix-ops/tests/vector-vector-multiplication-elementwise.svg
M	matrix-ops/tests/vector-vector-outerproduct.svg
M	matrix-ops/tests/vector-vector-subtraction.svg
M	minkowski-tests/maze/non-convex.svg
M	mobius/mobius.svg
M	molecules/glutamine.svg
M	molecules/nitricacid-lewis.svg
M	persistent-homology/persistent-homology.svg
M	random-sampling/test.svg
M	ray-tracing/bidirectional.svg
M	ray-tracing/next-event-estimation.svg
M	ray-tracing/path-trace.svg
M	set-theory-domain/continuousmap.svg
M	set-theory-domain/tree-tree.svg
M	set-theory-domain/tree-venn-3d.svg
M	set-theory-domain/tree-venn.svg
M	shape-distance/lines-around-rect.svg
M	shape-distance/points-around-line.svg
M	shape-distance/points-around-polyline.svg
M	shape-distance/points-around-star.svg
M	shape-spec/all-shapes.svg
M	shape-spec/arrowheads.svg
M	structural-formula/molecules/caffeine.svg
M	timeline/penrose.svg
M	triangle-mesh-2d/diagrams/angle-equivalence.svg
M	triangle-mesh-2d/diagrams/concyclic-pair.svg
M	triangle-mesh-2d/diagrams/cotan-formula.svg
M	triangle-mesh-2d/diagrams/halfedge-mesh.svg
M	triangle-mesh-2d/diagrams/relative-orientation.svg
M	triangle-mesh-2d/diagrams/triangle-centers.svg
M	triangle-mesh-3d/two-triangles.svg
M	walk-on-spheres/laplace-estimator.svg
M	walk-on-spheres/nested-estimator.svg
M	walk-on-spheres/offcenter-estimator.svg
M	walk-on-spheres/poisson-estimator.svg
M	word-cloud/example.svg

📊 Performance

Key

Note that each bar component rounds up to the nearest 100ms, so each full bar is an overestimate by up to 400ms.

     0s   1s   2s   3s   4s   5s   6s   7s   8s
     |    |    |    |    |    |    |    |    |
name ▝▀▀▀▀▀▀▀▀▀▚▄▄▄▄▄▄▄▄▞▀▀▀▀▀▀▀▀▀▀▚▄▄▄▄▄▄▄▄▄▖
      compiling labeling optimizing rendering

If a row has only one bar instead of four, that means it's not a trio and the bar just shows the total time spent for that example, again rounded up to the nearest 100ms.

Data

                                                          0s   1s   2s   3s   4s   5s   6s
                                                          |    |    |    |    |    |    |
set-theory-domain/tree-venn                               ▝▀▚▚
set-theory-domain/tree-tree                               ▝▀▄▚
set-theory-domain/tree-venn-3d                            ▝▚▚▖
group-theory/quaternion-multiplication-table              ▝▀▀▚▄▚▖
group-theory/quaternion-cayley-graph                      ▝▀▚▚
atoms-and-bonds/wet-floor                                 ▝▚▀▀▀▀▖
atoms-and-bonds/one-water-molecule                        ▝▞▖
set-theory-domain/continuousmap                           ▝▚▚
linear-algebra-domain/two-vectors-perp                    ▝▚▚
molecules/nitricacid-lewis                                ▝▀▀▀▞▀▚
exterior-algebra/vector-wedge                             ▝▚▚
shape-spec/all-shapes                                     ▝▚▚▄▄▄▖
shape-spec/arrowheads                                     ▝▚▚
graph-domain/textbook/sec1/fig1                           ▝▀▀▚▀▖
graph-domain/textbook/sec1/fig2                           ▝▀▀▀▞▀▚
graph-domain/textbook/sec1/fig3                           ▝▀▀▀▚▀▀▚
graph-domain/textbook/sec1/fig4                           ▝▀▀▀▀▚▀▀▖
graph-domain/textbook/sec1/fig5                           ▝▀▀▀▀▀▚▀▀▀▀▖
graph-domain/textbook/sec1/fig6                           ▝▀▀▀▀▀▀▀▀▀▀▀▀▀▞▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▚
graph-domain/textbook/sec1/fig7                           ▝▀▀▞▚
graph-domain/textbook/sec1/fig8a                          ▝▀▀▀▀▀▚▀▀▀▖
graph-domain/textbook/sec1/fig8b                          ▝▀▀▀▚▀▀▀▖
graph-domain/textbook/sec1/fig9                           ▝▀▀▚▀▄
graph-domain/textbook/sec1/fig10                          ▝▀▀▞▖
graph-domain/textbook/sec1/fig11                          ▝▀▀▀▀▞▀▖
graph-domain/textbook/sec1/fig12                          ▝▀▀▀▀▚▀▀▚
graph-domain/textbook/sec1/fig13                          ▝▀▀▀▚▀▀▖
graph-domain/textbook/sec2/fig3                           ▝▀▀▀▀▀▀▀▚▀▀▀▀▀▚
graph-domain/textbook/sec2/fig4                           ▝▀▀▀▀▀▞▀▀▚
graph-domain/textbook/sec2/fig5                           ▝▀▀▀▀▀▀▀▚▀▀▀▀▚
graph-domain/textbook/sec2/fig6                           ▝▀▀▀▀▀▀▀▀▚▀▀▀▀▚
graph-domain/textbook/sec2/fig9                           ▝▀▀▀▀▀▀▀▀▀▀▀▞▀▀▀▀▀▀▚
graph-domain/textbook/sec2/fig10a                         ▝▀▀▚▀▚
graph-domain/textbook/sec2/fig10b                         ▝▀▀▞▚
graph-domain/textbook/sec2/fig11a                         ▝▀▀▞▖
graph-domain/textbook/sec2/fig11b                         ▝▀▞▖
graph-domain/textbook/sec2/fig11c                         ▝▀▚▚
graph-domain/textbook/sec2/fig12                          ▝▀▞▖
graph-domain/textbook/sec2/fig13                          ▝▀▀▀▀▀▀▀▀▀▀▀▀▀▞▀▀▀▀▀▀▀▀▀▀▚
graph-domain/textbook/sec2/fig14                          ▝▀▀▚▚▖
graph-domain/textbook/sec2/fig16b                         ▝▀▀▞▄
geometry-domain/textbook_problems/c05p13                  ▝▀▀▞▖
geometry-domain/textbook_problems/c01p01                  ▝▀▚▚
geometry-domain/textbook_problems/c03p01                  ▝▀▚▚
geometry-domain/textbook_problems/c05p01                  ▝▀▀▞▖
geometry-domain/textbook_problems/ex                      ▝▀▀▚▀▖
triangle-mesh-3d/two-triangles                            ▝▚▚
random-sampling/test                                      ▝▀▀▀▚▚
geometry-domain/textbook_problems/c11p12                  ▝▀▀▞▖
word-cloud/example                                        ▝▀▞▚
geometry-domain/siggraph-teaser                           ▝▀▀▞▖
minkowski-tests/maze/non-convex                           ▝▚▚
lagrange-bases/lagrange-bases                             ▝▚▚
hypergraph/hypergraph                                     ▝▀▀▀▞▀▀▀▀▀▀▀▀▚
persistent-homology/persistent-homology                   ▝▀▀▞▀▀▀▀▀▀▄
walk-on-spheres/laplace-estimator                         ▝▀▚▀▖
walk-on-spheres/poisson-estimator                         ▝▀▚▀▀▚
walk-on-spheres/nested-estimator                          ▝▀▀▞▀▖
walk-on-spheres/offcenter-estimator                       ▝▀▚▀▀▚
shape-distance/points-around-star                         ▝▀▀▀▀▚▚▖
shape-distance/points-around-polyline                     ▝▀▀▞▖
shape-distance/points-around-line                         ▝▀▚▚
shape-distance/lines-around-rect                          ▝▚▚
fake-3d-linear-algebra/projection                         ▝▞▖
animation/center-shrink-circle                            ▝▞▖
structural-formula/molecules/caffeine                     ▝▀▀▞▚▖
mobius/mobius                                             ▝▞▖
molecules/glutamine                                       ▝▀▞▖
matrix-ops/tests/matrix-matrix-addition                   ▝▚▚
matrix-ops/tests/matrix-matrix-division-elementwise       ▝▀▞▖
matrix-ops/tests/matrix-matrix-multiplication-elementwise ▝▀▞▖
matrix-ops/tests/matrix-matrix-multiplication             ▝▚▚
matrix-ops/tests/matrix-matrix-subtraction                ▝▚▚
matrix-ops/tests/matrix-transpose                         ▝▚▚
matrix-ops/tests/matrix-vector-left-multiplication        ▝▚▚
matrix-ops/tests/matrix-vector-right-multiplication       ▝▚▚
matrix-ops/tests/scalar-vector-division                   ▝▀▞▖
matrix-ops/tests/scalar-vector-left-multiplication        ▝▚▚
matrix-ops/tests/scalar-vector-right-multiplication       ▝▚▚
matrix-ops/tests/vector-vector-addition                   ▝▚▚
matrix-ops/tests/vector-vector-division-elementwise       ▝▚▚
matrix-ops/tests/vector-vector-multiplication-elementwise ▝▚▚
matrix-ops/tests/vector-vector-outerproduct               ▝▚▚
matrix-ops/tests/vector-vector-subtraction                ▝▚▚
logic-circuit-domain/half-adder                           ▝▀▞▖
curve-examples/cubic-bezier                               ▝▚▀▀▚
triangle-mesh-2d/diagrams/cotan-formula                   ▝▀▚▀▀▖
triangle-mesh-2d/diagrams/concyclic-pair                  ▝▀▚▀▖
triangle-mesh-2d/diagrams/halfedge-mesh                   ▝▀▚▚
triangle-mesh-2d/diagrams/relative-orientation            ▝▀▚▚
triangle-mesh-2d/diagrams/triangle-centers                ▝▀▚▚
triangle-mesh-2d/diagrams/angle-equivalence               ▝▀▀▚▀▀▀▖
timeline/penrose                                          ▝▀▀▚▚
graph-domain/textbook/sec5/ex32                           ▝▀▀▀▀▚▀▀▀▀▀▀▖
curve-examples/open-elastic-curve                         ▝▀▚▀▚
curve-examples/closed-elastic-curve                       ▝▀▚▀▀▖
graph-domain/other-examples/arpanet                       ▝▀▀▀▀▀▀▀▀▀▚▀▀▀▀▀▀▀▀▀▀▀▀▚
graph-domain/other-examples/nyc-subway                    ▝▀▀▀▀▀▚▀▀▀▀▖
curve-examples/blobs                                      ▝▀▀▀▀▀▀▚▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▚
curve-examples/space-curves                               ▝▀▀▀▀▀▀▚▀▀▀▀▚
solid/example                                             ▐
geometric-queries/ray-intersect/test-group                ▝▀▀▀▀▀▀▀▀▀▞▄
ray-tracing/path-trace                                    ▝▀▀▞▖
ray-tracing/bidirectional                                 ▝▀▀▞▖
ray-tracing/next-event-estimation                         ▝▀▀▞▖
geometric-queries/test                                    ▝▀▚▚
geometric-queries/closest-point/test-group                ▝▚▚▄
geometric-queries/closest-point/test                      ▝▚▚
geometric-queries/closest-silhouette-point/test           ▝▚▚
geometric-queries/ray-intersect/test                      ▝▀▀▀▀▀▀▚▚▄▖

@rjainrjain rjainrjain changed the title RenderStatic adds metadata for tightest viewbox feat: RenderStatic adds tightest viewbox metadata to SVG Jun 2, 2023
@rjainrjain rjainrjain changed the title feat: RenderStatic adds tightest viewbox metadata to SVG feat: RenderStatic adds tightest viewbox metadata to SVG Jun 2, 2023
@rjainrjain rjainrjain changed the title feat: RenderStatic adds tightest viewbox metadata to SVG feat: renderer adds tightest viewbox metadata to SVG Jun 2, 2023
@cloudflare-pages
Copy link

cloudflare-pages bot commented Jun 2, 2023

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: cf67f70
Status: ✅  Deploy successful!
Preview URL: https://8cef8431.penrose-72l.pages.dev
Branch Preview URL: https://rijul-crop.penrose-72l.pages.dev

View logs

@rjainrjain rjainrjain requested a review from wodeni June 5, 2023 15:47
@wodeni wodeni marked this pull request as ready for review June 5, 2023 19:57
@wodeni
Copy link
Member

wodeni commented Jun 5, 2023

The PR was still a draft when @rjainrjain requested reviews. Marked it as ready just now :P.

Copy link
Member

@wodeni wodeni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job on this PR @rjainrjain 💯! Very nice PR description and clean implementation. Looking forward to your future PRs :D. I had an optional suggestion below about null checking.

Also noting a weird thing about previews with imported SVGs. Don't have to solve this in this PR, but perhaps this has something to do with #1288.
image

packages/editor/src/components/ExamplesBrowser.tsx Outdated Show resolved Hide resolved
const cropped = svgDoc.querySelector("croppedViewBox")?.innerHTML;
const svgNode = svgDoc.querySelector("svg")!;
if (!(cropped === undefined)) {
svgNode.setAttribute("viewBox", cropped!);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
svgNode.setAttribute("viewBox", cropped!);
svgNode.setAttribute("viewBox", cropped.innerHTML);

This should typecheck without the assertions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I tried this out, along with the suggestion below — it still requires the assertion at some point because cropped is still possibly null when passing cropped.innerHTML to setAttribute.

example.preview!,
"image/svg+xml"
);
const cropped = svgDoc.querySelector("croppedViewBox")?.innerHTML;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const cropped = svgDoc.querySelector("croppedViewBox")?.innerHTML;
const cropped = svgDoc.querySelector("croppedViewBox");

See below for doing stuff after undefined check

@wodeni
Copy link
Member

wodeni commented Jun 5, 2023

Should've suggested just one change instead of 3 :(. My bad! Hopefully you can use the "Add suggestion to batch" feature, which is kinda new?

Co-authored-by: Wode "Nimo" Ni <wn2155@columbia.edu>
@rjainrjain rjainrjain merged commit 0c7b9f0 into main Jun 6, 2023
10 checks passed
@rjainrjain rjainrjain deleted the rijul/crop branch June 6, 2023 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crop gallery SVGs for preview in editor
2 participants