Mismatched 3D and 2D domains in Brep.CreatePlanarBreps

Given a brep (typically in 3D) I’m creating a planar counterpart of the brep using this method:

var planarBreps = Brep.CreatePlanarBreps(brep.Trims, epsilon);

a 3D brep and it’s planar counterpart

I’m using the pair of these to create a planar mesh which represents the 3D brep. I populate the planar brep with vertices, using two approaches together:

  • transferring on-surface points from the 3D brep to the planar brep
  • subdividing the planar brep’s trims/edges into points

“transferring on-surface points” means get the UV on the 3D brep then construct a planar point using the same UV but now on the planar brep.

_ = brep3D.Faces[0].ClosestPoint(point, out var u, out var v);
return planarBrep.Faces[0].PointAt(u, v);

So you can see, I need the brep’s trims and projected points to be in the same 2D area. Here are the results of a unit sphere- All 3 of these properties of the planar brep do not align: trims, edges, projected points. (The projected points don’t even lie on the surface of the planar brep?) The domains appear to be the same scale, just mis-translated.

So I found one fix: transfer the domain from the 3D to the planar brep.

_ = planarBrep.Faces[0].SetDomain(0, brep3D.Faces[0].Domain(0));
_ = planarBrep.Faces[0].SetDomain(1, brep3D.Faces[0].Domain(1));

this aligns all 3: Trims, Edges, and projected points, all lie within the planar brep.

I thought I was done!- until I started working with breps formed via. a boolean difference operation. As it turns out this solution does not work with more complex breps.

Here is a sliced sphere (now we have two 3D breps, ignore the top circle face for now, I’ll only populate the spherical face)

before transferring the domains (as expected, nothing is aligned):

And now here is the result after applying the “fix” (transferring the 3D domain to the planar). What worked before with the sphere no longer works. The trims, edges, and projected points are not perfectly aligned (almost, but the scale is off).

In the case of these more complex breps, it feels like:

  • before the “fix”: translation wrong, scale correct
  • after the “fix”: translation correct, scale wrong.

After that lengthy description (thank you for reading this far) my question is: can someone suggest an alternate solution or help me amend my “fix”, the code copied again below.

_ = planarBrep.Faces[0].SetDomain(0, brep3D.Faces[0].Domain(0));
_ = planarBrep.Faces[0].SetDomain(1, brep3D.Faces[0].Domain(1));

I did try normalizing 3D brep domains, the same scale issue exists, only, it’s all bounded inside the 0…1 unit square. It’s almost like, the domain of the 3D face remembers its former domain before the boolean difference was performed, and is confused about what to pass along, or it gets corrupted in the transmission. Is there an operation to perform on a boolean-difference-brep to “clean up” its domain?

Thank you!

Hi @Maya8,

From what I read, you’re trying to do the equivalent CreateUVCrv and PlanarSrf in RhinoCommon. Is my understanding correct?

– Dale

Hi @dale,
I did a little comparison. In theory yes that’s what I’m doing (taking 3D brep’s 2D trims and creating a new planar brep). But for whatever reason those Rhino commands you mention, and the C# Rhino Common commands that I’m using (myBrep.Trims and Brep.CreatePlanarBreps()) create different results. the CreateUVCrv result is much wider.

a 3D sliced-cylinder brep. Rhino command CreateUVCrv resulted in the yellow. Rhino Common C# brep.Trims resulted in the green

there are 2 greens because of the issue in my post (one is the 3D’s brep.Trims, one is planar brep.Trims formed via the CreatePlanarBreps command)

So it appears those commands you mention are not exactly equivalent with the RhinoCommon C# commands I’m calling.

The CreateUVCrv command uses loops, not trims.

I’m not sure I understand what domain issue you’re having. You can, of couse, set the domain yourself.

Ideally, the domains of a surface is close to is average breadth in the appropriate direction.

– Dale

Thank you so much for your help as always, @dale. I really struggled with how best to explain this. It’s my fault.

I’ve built an illustrative GH file: (1) Choose a brep and (2) choose a projection method, and the result is on the right- all points/trims/edges should align. Note how there is no single projection method which works for all breps.

Also I can more concisely restate the issue:

The goal: to have a robust planar brep copy of any given brep, one which allows for the transfer of geometry back and forth using UV coordinates and segmentation of trims/edges. (trims or edges, and UV-projected points should align).

The issue: finding a projection algorithm that works for all breps. As you say I can transfer the domain, and the way I’m doing this seems to be the issue. What I’m doing works in all cases except breps which have undergone some boolean-difference operation, and the reason is that the way I’m transferring domains applies the trimmed surface’s domain into the space inhabited by the untrimmed surface.

The solution: I assume this is this code is the issue. Here’s my code to create a planar UV copy of a brep.

var planarBreps = Brep.CreatePlanarBreps(brep.Trims, 1e-3);

// trying this
_ = planarBreps[0].Faces[0].SetDomain(0, brep.Faces[0].Domain(0));
_ = planarBreps[0].Faces[0].SetDomain(1, brep.Faces[0].Domain(1));
// or this
_ = planarBreps[0].Surfaces[0].SetDomain(0, brep.Surfaces[0].Domain(0));
_ = planarBreps[0].Surfaces[0].SetDomain(1, brep.Surfaces[0].Domain(1));
// or something else...

If that code looks correct, it apparently doesn’t work with boolean-subtracted breps. You should be able to see this clearly in the GH file, let me know if the GH file is unclear.

And thanks again for your help!
-Maya
rhino-forum-question.gh (24.5 KB)