# Bug: Rhino reports false deviation values

**URL:** <https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490>\
**Category:** Rhino for Windows\
**Tags:** windows\
**Created:** [September 1, 2024, 11:33pm UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490 "2024-09-01T23:33:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rhino\_Bulgaria](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/rhino_bulgaria/32/505284_2.png) [@Rhino\_Bulgaria](https://discourse.mcneel.com/u/Rhino_Bulgaria)\
**Post date:** [September 1, 2024, 11:33pm UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/1 "2024-09-01T23:33:25Z")

</div>

I noticed that Rhino reports false minor deviation values that are nearly 10 times smaller than the actual huge deviation. These are highly misleading and give the user a false confidence about the quality and precision of the expected output surfaces.

[![](https://global.discourse-cdn.com/mcneel/uploads/default/original/4X/6/d/d/6dd6f43a05dfdd19b40df08031b1f5214f18f1b7.jpeg "Bug: Rhino reports false deviation values") ](https://www.youtube.com/watch?v=OBSQujaTIcE)

---

<div class="post-metadata">

**Author:** ![davidcockey](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/davidcockey/32/732604_2.png) [@davidcockey](https://discourse.mcneel.com/u/davidcockey)\
**Post date:** [September 2, 2024, 2:05am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/2 "2024-09-02T02:05:47Z")

</div>

Interesting. I have not noticed a discrepency that large but I also have not looked for it.

What does CrvDeviation report for the distance between the edges?

---

<div class="post-metadata">

**Author:** ![Rhino\_Bulgaria](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/rhino_bulgaria/32/505284_2.png) [@Rhino\_Bulgaria](https://discourse.mcneel.com/u/Rhino_Bulgaria)\
**Post date:** [September 2, 2024, 3:05am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/3 "2024-09-02T03:05:29Z")

</div>

I no longer keep that scene, but I just created another surface and the difference between expected maximum deviation and real deviation of the output surface is quite large (almost 10 times worse).  
I noticed this bug when I figured out that I can’t match surfaces that were supposed to be close enough within my file tolerance setting.

This file below contains two surfaces. The white surface is the original, whereas the cyan one is a rebuilt output using the following settings:

 ![Rhino reports false deviation values 1](https://global.discourse-cdn.com/mcneel/uploads/default/original/4X/d/1/b/d1b925fa3cf9563020ecd93e9b3d48889b1f6263.png)

[Rhino reports false deviation values.3dm](https://discourse.mcneel.com/uploads/short-url/3cQ0ytW62iJuHvUQv4ZS680v9hh.3dm) (222.4 KB)

According to Rhino, the expected maximum deviation should be 0,0856711 mm, but the actual maximum deviation is 0,7700593 mm.

---

<div class="post-metadata">

**Author:** ![davidcockey](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/davidcockey/32/732604_2.png) [@davidcockey](https://discourse.mcneel.com/u/davidcockey)\
**Post date:** [September 2, 2024, 8:07am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/4 "2024-09-02T08:07:46Z")

</div>

I tested @Rhino_Bulgaria example using Rhino Version 8 SR11 (8.11.24240.13481, 2024-08-27).

It appears that Rebuild of a surface uses a sparse set of locations to calculate the maximum deviation. In this examle those sparse locations are where the deviation is minimal.

In contrast Rebuild of a curve (for example the extracted edge of the white surface) reports the correct maximum deviation, presumably because Rebuild of a curve uses a much denser set of locations to calculate the maximum deviation.

PointDeviation between the two surfaces uses a much denser set of locations than Rebuild and provides the correct maximum deviation. There was a small but noticeable delay while PointDeviation calculated the deviation.

My guess is the use of sparse set of locations to calculate maximum deviation in Rebuild of a surface goes back to when the Rebuild command was introduced and CPU speed was a small fraction of what it is today. The choice of a sparse set may have been to minimize the time in calculate the “maximum deviation” during execution of Rebuild of a surface.

Unfortunately the “maximum deviation” shown during Rebuild of a surface can be very misleading and cause downstream problems. This should be fixed. In the meantime if knowing the actual maximimum deviation of a rebuilt surface is important then when rebuilding a surface the Delete input box should not be checked. After the surface is rebuilt use PointDeviation to check the deviation between the original surface and the rebuilt surface.

---

<div class="post-metadata">

**Author:** ![Rhino\_Bulgaria](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/rhino_bulgaria/32/505284_2.png) [@Rhino\_Bulgaria](https://discourse.mcneel.com/u/Rhino_Bulgaria)\
**Post date:** [September 2, 2024, 10:09am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/5 "2024-09-02T10:09:38Z")

</div>

Hopefully the sample locations used for the calculation of the deviation could be raised to minimize the error. I don’t mind waiting 1 extra second if that will give a more accurate prediction for the output surface.

---

<div class="post-metadata">

**Author:** ![David53](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/david53/32/770277_2.png) [@David53](https://discourse.mcneel.com/u/David53)\
**Post date:** [September 2, 2024, 10:16am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/6 "2024-09-02T10:16:54Z")

</div>

I wonder if this is the reason I have been sometimes struggling to sculpt surfaces properly. Especially when it comes to the matching process, I assume the CV changes should be very small relative to what I have just rebuilt. But then you see the surface go “crumble” in the viewport.

Sometimes I’ll keep going round and round rebuilding and matching for ages, wondering why the surface changes more drastically than the rebuild command suggests should happen.

---

<div class="post-metadata">

**Author:** ![Rhino\_Bulgaria](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/rhino_bulgaria/32/505284_2.png) [@Rhino\_Bulgaria](https://discourse.mcneel.com/u/Rhino_Bulgaria)\
**Post date:** [September 2, 2024, 11:20am UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/7 "2024-09-02T11:20:22Z")

</div>

I believe that this is the very reason for the unwanted high deviation that you noticed after rebuilding the surfaces. I had plenty of issues with rebuilt surfaces recently, this is why I ended up testing whether Rhino is reliable when it comes to calculating the expected deviation.

---

<div class="post-metadata">

**Author:** ![Willem](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/willem/32/554347_2.png) [@Willem](https://discourse.mcneel.com/u/Willem)\
**Post date:** [September 8, 2024, 10:22pm UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/8 "2024-09-08T22:22:40Z")

</div>

Hi @Rhino_Bulgaria, @davidcockey and @dale

This post caught my eye and I did some digging in our code and also found an old topic where @dale helped me calculate the deviation between 2 surfaces.

> [@Calculate surface deviation after rebuild](https://discourse.mcneel.com/t/calculate-surface-deviation-after-rebuild/56518):
>
> Hi, How would I go about calculating the maximum deviation from a rebuild surface and it’s original in RhinoCommon? To prevent costly calculations by brute-force sampling the deviations, I’d like to know if there are some mathematical rules that limit the number of points to sample and still get an accurate result. My first guess would be to sample only the deviations at both the surfaces ControlPoints, but I like to know if that assumption is correct. Basically I’m looking for a way to get…

The example provided by Dale is this one:

> <https://github.com/mcneel/rhino-developer-samples/blob/6/rhinopython/SampleRebuildSrfDeviation.py>

My conclusion on why the reported deviation in Rebuild Surface is incorrect, is that only one surface is tested against the other but not also the other way around. In the example Dale provided, relevant samples are based on the surface knot count, however as the original and the rebuild surface are different, their samplepoint locations are also different. So relevant samplepoints of both surfaces need to be used to find all the relevant deviations

I altered the above script to test it on selected surfaces and noticed that depending on the picking order another deviation was found. The below version will test both surfaces against each other and the reported deviations are:

```auto
deviation AB : 0.0856710647197
deviation BA : 0.795439709366

```

These correspond with the deviation in the dialog and the one you found (albeit the actual deviation is larger as the location you found is close to the max deviation found.  
As you can see the max deviation is at a samplepoint used by the script:  
 ![image](https://global.discourse-cdn.com/mcneel/uploads/default/original/4X/7/0/c/70c14d6358e12f37bc29382518082a0b00d5da70.png)

my script to test with:  
[test\_srf\_deviation.py](https://discourse.mcneel.com/uploads/short-url/vBe5uuyQCrMGritaohIZpjwATMZ.py) (2.6 KB)

```python
# coding=utf-8
from __future__ import division
import rhinoscriptsyntax as rs
import Rhino

def test_deviation(puv_samples , srf):
    
    r_domain = []
    for i in range(2):
        r_domain.append(srf.Domain(i))
    
    d_vecs = []
    for po, un, vn in puv_samples:
        uu = r_domain[0].ParameterAt(un)
        vv = r_domain[1].ParameterAt(vn)
        rc, ru, rv = srf.LocalClosestPoint(po, uu, vv)
        if rc:
            pr = srf.PointAt(ru, rv)
            d_vecs.append(Rhino.Geometry.Vector3d(pr-po))
    
    d_vecs.sort(key=lambda v : v.Length, reverse = True)
    
    return d_vecs[0].Length

def helper_srfsrf_deviation(srf1, srf2):
    
    def srf_samples(srf):
        f_domain = []
        for i in range(2):
            f_domain.append(srf.Domain(i))
        
        knot = []
        for i in range(2):
            k = srf.GetSpanVector(i)
            knot.append(k)
        
        puv = []
        doc_pts = []
        samples = 2
        for j0 in range(knot[0].Count - 1):
            u_interval = Rhino.Geometry.Interval(knot[0][j0], knot[0][j0 + 1])
            for j1 in range(knot[1].Count - 1):
                v_interval = Rhino.Geometry.Interval(knot[1][j1], knot[1][j1 + 1])
                for i0 in range(samples + 1):
                    for i1 in range(samples + 1):
                        if i0 == 0 and j0 > 0: continue
                        if i1 == 0 and j1 > 0: continue
                        u = u_interval.ParameterAt(i0 / samples)
                        v = v_interval.ParameterAt(i1 / samples)
                        po = srf.PointAt(u, v)
                        doc_pts.append(rs.AddPoint(po))
                        nu = f_domain[0].NormalizedParameterAt(u)
                        nv = f_domain[1].NormalizedParameterAt(v)
                        puv.append([po,nu,nv])
        return puv, doc_pts
    
    
    puv1, doc_pts1 = srf_samples(srf1)
    puv2, doc_pts2 = srf_samples(srf2)
    
    dev1 = test_deviation(puv1 , srf2)
    dev2 = test_deviation(puv2 , srf1)
    
    print 'deviation AB : {}'.format(dev1)
    print 'deviation BA : {}'.format(dev2)
    return doc_pts1, doc_pts2

if __name__ == ' __main__':

    id1 = rs.GetObject('surface A', 8)
    id2 = rs.GetObject('surface B', 8)
    
    srf1 = rs.coercesurface(id1)
    srf2 = rs.coercesurface(id2)
    
    
    pts1, pts2 = helper_srfsrf_deviation(srf1, srf2)
    rs.ObjectColor(pts1, rs.ObjectColor(id1))
    rs.ObjectColor(pts2, rs.ObjectColor(id2))
    
    rs.AddObjectToGroup(pts1, rs.AddGroup)
    rs.AddObjectToGroup(pts2, rs.AddGroup)

```

---

<div class="post-metadata">

**Author:** ![davidcockey](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/davidcockey/32/732604_2.png) [@davidcockey](https://discourse.mcneel.com/u/davidcockey)\
**Post date:** [September 8, 2024, 11:03pm UTC](https://discourse.mcneel.com/t/bug-rhino-reports-false-deviation-values/190490/9 "2024-09-08T23:03:25Z")

</div>

`PointDeviation` provides a good result for the maximum deviation between the surfaces, independent of which surface is selected to provide points. The deviation estimate for surfaces in `Rebuild` needs to use the same methodology, including number of points tested, as `PointDeviation`.
