About PQ Mesh, conjugate curvature network

Recently, I’m studying Pottmann’s Architectural Geometry. Actually, although I’m very interested in this topic, it is difficult for me. In the last chapter, I found PQ meshes have more nice properties. Does anyone have any example to show the workflow of generating PQ meshes according to conjugate curvature network from a discrete surface? And how to extract the conjugate curvature network from a discrete surface?



Hi Albert,

For making the quads of a mesh planar, there are some examples using kangaroo here:

It usually makes sense to build an initial coarse quad grid manually (informed by the curvature field), then subdivide it before planarization.

The latest Kangaroo release also includes components for generating circular, isothermic, and conical meshes, and for generating the panel offsets and beam layout.


Hi, Daniel
Sorry, I have tried your examples but it did not work on my mesh. I think I need to learn more about the optimization of panels. What are the advantages of torsion-free nodes? And another problem is how to optimized torsion-free nodes and planarity on a mesh model like this? (I consider this model cannot be optimized) I have watched these posts:

I know this topic is old. But could you please share more points about paneling optimization? I’m sorry to occupy your time and thank you a lot again!
Torsion-Free and PQ Mesh Please.3dm (79.1 KB)

Planarizing this works fairly simply-
planarize_AL.gh (18.5 KB)

Start with the anchor goal strength at 1 to keep the result close to the input mesh, then gradually slide it down to zero to allow the planarity constraint to be enforced strictly.

I think those threads you link to get a bit off track - Torsion free nodes can be fairly simple too, but because this starting mesh is a bit kinked it looks like it will need something to smooth the grid.


First to try and summarise the main advantages of torsion-free nodes/beam layouts-

Say we have some curved surface which we want to build as a structure of steel beams.
One geometrically easy way to do this is to simply extrude the grid lines all in a vertical direction:

This keeps the beams planar, and they intersect in a single line at each node, which can be simple to fabricate.

However, we might need the beams to be oriented more perpendicular to the surface, especially if we have surfaces that curve around to become more vertical.

If you simply offset the mesh by moving all the vertices along their normals, and connect corresponding edges between the original and offset mesh to form the beams, then in general without optimisation you get something like this - where the beams are all twisted, because the mesh normals at their start and end do not lie in a common plane:

To fabricate this, you’d need to either make twisted beams, or planar beams but with a complicated node where they join to resolve the twist, both of which increase the cost.

If instead you design or optimise your grid in the right way, to have certain geometric properties, it is possible to make a mesh where the faces are planar quads, which can also be offset along its vertex normals to give another mesh with planar quads, and when we connect the edges of the mesh and its offset, we get a torsion-free-beam-layout.

One particular type of mesh which does allow such a layout is a conical mesh, where all the quads around a vertex lie tangent to a common cone. These meshes also have the nice property that we can generate an offset mesh where corresponding faces are all a constant distance apart.


…and here’s an example definition showing a way to generate such a conical planar quad mesh, its constant distance face-face offset, and the corresponding torsion free beam layout, on a given target surface:
conical_demo.gh (52.0 KB)

In this example I’ve started with a simple regular flat square grid, and pulled it onto the surface. As you slowly slide up the strength of the planarization/conicalization constraints, it will naturally slide and rotate on the surface to find an orientation aligned with the curvature directions.

For surfaces with bigger variations in curvature, it won’t always be possible to use such a simple starting grid - you will sometimes need to include some irregular vertices.
The boundaries are easy in this example because we have a large surface which extends beyond the grid we are placing on it, so there is room for it to move around. When you need to constrain to a given boundary you will usually need some further goals.


Thanks sooooooooooooooo much! :grin::grin::grin: Really really useful! Appreciate your kangaroo and explanation you do for us!

Hi Daniel,

Thanks for sharing the amazing definition.
I can’t seem to be getting the process to work for a surface/grid that I thought would be much simpler than the one you showed.
Any pointer would be much appreciated!
GH file attached here and a screenshot below conical_v1.gh (40.0 KB) :

Looking at this surface with Rhino’s curvature circle command suggests that the grid needs to turn to a more diagonal orientation at the sides, and the starting configuration you have for the quads above is too far off from this to be able to wriggle its way into alignment without coming off the boundaries of the surface.

Perhaps using the goal I posted in the earlier discussion here that sticks vertices to a target mesh but lets them slide off the edges could help, but I think anyway it will be better to start with a better curvature aligned grid before trying to optimise


Here’s the result of applying that slide-off goal on this
quads_surf.gh (42.8 KB)


Hi Daniel,

Thank you very much!
I took that script (which was actually an answer to my other question before as well) and combined it with the conical one: conical_v2.gh (74.0 KB)

The first internalized mesh in the file is the result from the slideoff goal, which I then cull out some of the faces (I only care about covering the pink colored surface area in the screenshot) and input them into the conical portion.

The second internalized mesh all the way to the right of the script is the result from starting the slider at 0.1 and quickly bumps the strength up to 1e12. When I tried to slide the slider up slowly, it doesn’t seem to be able to converge before faces crumbling into each other eventually. In other words, it seems to be difficult to achieve the “conicalization” while ensuring the points lie on the surface. What might be the issuer here?

In addition, let’s say this result is satisfactory for now, how do I check for and output the underlying cone surface geometry of each mesh face?

Thank you very much!

The slide-off goal can be combined with the conical one, so you can do it all in one simpler combined relaxation:
conical_quads.gh (38.0 KB)

regarding the “underlying cone surface geometry of each mesh face”, I think there might be some misunderstanding of what is meant by the mesh being conical here - the 4 faces around each vertex lie tangent to a common cone. So there isn’t really a single underlying cone per face (since each face is tangent to the cones at all of its corners)

1 Like

Right, I just realized I misunderstood what it actually meant - although of course this is still super useful, thank you very much!

With regard to the other case -approximating an underlying surface with faces that all lie on (different) conical surfaces - what might be a good way to start?

ps. How do I split this topic?

I believe that for any planar quad where the opposite edges aren’t parallel you can define 2 separate 1 parameter families of cones with their tips where the extended edges intersect

You can just post a new discussion and link back to this one

1 Like

Hi Daniel,

Thank you for this example and for your explanation regarding conical meshes. I find this topic really interesting, I´m specially interested in the support structure generated between the two meshes, That´s why I tried to fabricate your conical demo by following two approaches. In the first one I succeed but in the second one I got stuck.

1.- In the first approach: I started from the resulting beams between the two meshes, clustering with Owl according to it´s face normal, in order to get both directions of stripes separately as stripes.

2.- In the second approach the idea is to get the mesh faces of the supporting structure and conform boxes with four faces, and then creating strips from this boxes and unrolling them in order to orient them in the horizontal plane for fabrication. Once the boxes are assembled, the idea is to put each box next to the corresponding one to conform the desired shape. But the problem I have is when unrolling the strip. Can you suggest any solution to this problem, please.



conical_demo_box.gh (65.0 KB)

Nice idea.
I should probably update the unroller component to work with closed loops.
Here’s a script to use for now though:
boxunroll.gh (40.2 KB)

Also - you’re maybe considering this already, but without anything filling in the top or bottom panels this structure of just the beams as loops won’t be very rigid.

For a paper model I think it could work better to make a sort of tray for each face (adding flaps to join them at the corners).


Here an example of the tray unfolding approach:

trayunfold.gh (24.3 KB)

1 Like

Awesome @DanielPiker! In the meantime, any chance to split your “StripsUnfold” in 2 c# (StripsGeneration and SortedUnfolding) like the unroller component but should be respecting the face order. I would like to test it with more complex strips but with sorted faces. thank you!

Hi @ThomasE
I’m not sure I follow what you’re asking.
The box unroll script outputs the strips in the same order as the faces of the input mesh, and the strip for each face follows the vertex ordering of that face.
Probably clearer if you post a file where you’re not getting the result you want and I’ll take a look at it tomorrow.

1 Like

Thank you @DanielPiker, well I recreated your strips mesh structure with their own seams,
I’d like to unfold in the same way that your BoxUnroll do.
_Anchor Points (Vertices 0,1)
_Respecting the face order.

In the case of your standard K2-Unroll, sometimes the anchor points are the last ones… I’d like to avoid that, please!

unroll_v2.gh (16.5 KB)