Curvature matching in the new Patch command

In the latest WIP version, the new Patch command has a new method to match surface curvature continuously, also known as G2 matching. The new method uses two tolerances for curvature matching:

  • relative curvature tolerance
  • zero curvature tolerance

In this post, I will go into some depth of what surface curvature is, how this new method works, what sensible defaults are for the two tolerances, and why it was introduced.

Curvature

Let’s start out by saying that surface curvature can be a difficult topic - I struggle with it regularly :slight_smile: Having said that, let’s dive right in:
Curvature is a measure for how the surface curves in a direction in the tangent plane of a point on the surface. When you use the Curvature command in Rhino on a curved surface, you can see the minimum and maximum curvature radius as two arcs that change as you move the point around on the surface.


Minimum (green) and maximum (red) curvature on a point of a surface. The arrow and yellow plane indicate the normal direction and plane at the point.

The curvature changes from minimum to maximum radius as the direction is rotated around the surface normal. Curvature is obtained as a vector K, and the length of that vector, k, is inversely related to the radius of curvature:

|K| = k = (1/r)

curvature 360

The pringle-like shape indicates how the curvature changes around the normal

Because the k-value is related to the radius of curvature, scaling an object by a factor of 3 will also increase the radius of curvature by a factor of 3, and because of the formula above, decrease the curvature k-value by a factor of 3. In other words, curvature is dependent on the size of the object.

Curvature evaluated at the same position on a curve scaled by a factor of three: The radius increases, k-value decreases.

Comparing curvature

When Patch is matching the curvature, it tries to match these curvature k-values, so there are always two curvature values in play: let’s call them k0 (on the edge being matched) and k1 (on the patch). To compare these values in a way that does not depend on the size of the object, we calculate the relative curvature deviation (let’s assume that both k-values are not equal to zero, we’ll get to zero curvature below):

d_rel = |k1 - k0|/max(k0,k1)

If k0 and k1 are equal, d_rel will be zero, and if k0 is 5 times larger than k1, d_rel will be 0.8. As k0 and k1 become more different, d_rel will get closer to 1. What is nice about this way of comparing curvature is that it is independent of the scale of an object: if an object is scaled by a factor of 10, both k-values will be scaled by a factor (1/10) and these will be canceled in the fraction in the formula for d_rel:

d_rel = |0.1*k1 - 0.1*k0|/(0.1*max(k0,k1)) 
      = (0.1)*|k1 - k0|/(0.1)*max(k0,k1) 
      = (0.1/0.1)*|k1 - k0|/max(k0,k1) 
      = |k1 - k0|/max(k0,k1)`

Zero curvature

The formula for the relative curvature deviation d_rel (see above) is not suitable if one or both of the k-values is equal to zero. If one of them is zero, d_rel is always equal to 1.0, independent of the value of the other, and if both are zero, a division by zero occurs and that is always problematic.

This is where the zero curvature tolerance comes in: when comparing curvature, we first check if the values are less than the zero curvature tolerance, and if so, their values are set to zero. Only if both values are not zero, do we use the formula for d_rel.

Detailed steps

So, it comes together in the following prodecure:

  1. Check if the k-values are zero
    k0 = k0 < curvature-zero-tolerance ? 0 : k0
    k1 = k1 < curvature-zero-tolerance ? 0 : k1

  2. Use the following table to decide what to do for calculating the curvature match:

curvature-match? |  k0 = 0      |  k0 > 0       |
-------------------------------------------------
          k1 = 0 |   yes        |   no          |
-------------------------------------------------
          k1 > 0 |   no         |   see below   |
-------------------------------------------------
  1. If the table above did not give a yes/no answer, continue.
  2. Now k0 and k1 are both larger than zero, so we can safely use the formula for d_rel. If the value of d_rel is larger than the curvature relative tolerance, there is no curvature match. If the value is smaller than d_rel there is one more check: the direction of the curvature vectors should also match:
  3. A curvature match is only found if d_rel(k0,k1) < curvature-relative-tolerance and if angle(K0, K1) < angle-tolerance.

Sensible defaults

Curvature relative tolerance
The current Patch command uses a default relative curvature tolerance of 0.05, which means that the k-values may have a difference of up to 5%. If your curvature continuity requirements are not very strict, you can increase this to 0.1 without losing a nice-looking light lines flow.

Curvature zero tolerance
This is still a scale-dependent parameter, which says something about the curvature radius above which a surface can be considered flat. The current default is to use the same value as the document absolute tolerance. If this value is 0.001, it means that curvature radii above 1000 are considered flat. A good choice depends on the scale of your model and your curvature continuity requirements.

Why this change?

Up until now, Patch in G2-matching mode required you to come up a tolerance for the difference in curvature k-value d_abs = |k0 - k1| and if the absolute difference between k0 and k1 was below that threshold, the curvature was said to be matched. As explained above, the values of curvature are dependent on the scale of the object, so you had to come up with a value that you thought was suitable, both for the scale you’re working at, and for the curvature continuity requirements of your project.

We think that using a relative curvature tolerance is easier to understand (even if we need this wall of text to explain it all) and thinking of a curvature zero tolerance for the model you’re working with is easier than coming up with a scale-dependent value for d_abs.

Analyzing curvature continuity

There are a few ways to analyze curvature continuity in Rhino:

  • Zebra
  • CurvatureAnalysis
  • EdgeContinuity
  • GlobalEdgeContinuity

The first two are visual analysis modes, showing light lines and color-mapped curvature values. The last two are numerical analysis modes. These latter two do not (yet) have the method of comparing curvature as explained above.

(i appreciate the post above - thanks for sharing)
i try to comment with a craftsman’s attitude / beyond any math - and it s just a rough idea - happy to discuss:

I would love to have a absolute value-pair:
a diagnostic setting “bricolage rail distance”
and a resulting “sandpaper-post-production” distance / thickness:

failed G1,G2 seam

the following surfaces seam is of by 2 degree and the radius is of by 10%
(Radius 20 and 22mm)


failed for a typical class A surface.
(and the 2 degree will be visible on a glossy/polished part for sure)

sandpaper

but now, if i grab my sandpaper and allow a 10mm section (“bricolage rail distance”) (blue) to work over the surface, i have to “grind” 0.035 mm (“sandpaper postproduction thickness”).


0.035 is less then half the thickness of a 80g paper, or 1/10 to 1/5 of a typical coating / paint. My guess: for many applications this is still an acceptable result.

This 0.035 will say: the ideal surface is 0.035mm away - and maybe this is much easier to understand / read for most users ?
not as a replacement, but maybe as an addition ?

… my 2 cents - kind regards -tom

@Tom_P How would you (manually) calculate the 0.035 mm deviation without creating that transition surface?

would do you meant by “manually” ?

physically ?

for mold making and surface finishing there is a lot of processes where you apply a layer of color / ink and sand or press … the first picture shows “tuschierfarbe” of injection molding part.
block sanding and using a coat guide …



cad-ish

at a point of the edge

intersect perpendicular to the edge (used a disk hier with d = 10)
result is a red kinked curve (red)
build a inner blendCrv G2-G2 and distribute the CV’s to have nice flow ( see curvaturegraph)
meassure curve deviation between both curves

along an edge


yes - the transition surface is needed:
a simple pipetrim with blendsurface and (oldschool / outdated, missing nice rainbow) PointDeviation

… it s just an idea
for most people it s hard to judge a 1%, 5% or 10% curvature deviation..
you need to sand / or to fill 0.01 mm on a 10mm wide stripe seams more hands on…

At my company I’ve got a guy named Yuri — he’s my G2 continuity between imperfect surfaces. He turns every 3D model made by clients into silky-smooth geometry. Honestly, a master of sanding. I call him the human version of Rhinoceros3D software,

Then we need to do something about visualizing that in examples. I am sure that every industry has its own specifics for what is considered good enough. When matching for G2 continuity, first of all there needs to be a reasonable G1 match before you even can look at G2.

either manually constructing it, or in code. What you are suggesting is that the software creates a virtual pipe trim and blend surface and then measures the distance between that surface and the edge.
I don’t know how feasible this.

RH-92584 GEC: Implement new G2 relative tolerance
RH-92585 EdgeContinuity: Implement new G2 relative tolerance