Rhino script exceptions or bug?

script
python

#1

Hi,

Today I tried to repeat a python script by Jose Sanchez on Vimeo https://vimeo.com/29321808 and I found a bug in rhino script. The script actually works with any numbers except 50. It is about a tangent line distribution on a curve. It was fine with 10,20,40,49,51,150 but not with 50. Is it possible?

The error message was the following:

Message:

Could not convert None to a Vector3d

Traceback:
** line 398, in coerce3dvector, “C:\Users\An\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\utility.py”**
** line 467, in VectorUnitize, “C:\Users\An\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\pointvector.py”**
** line 20, in tanPoints, “C:\Users\An\AppData\Roaming\McNeel\Rhinoceros\5.0\scripts\Rhino Python Tutorial 11 - TangentsCrv_Parameters.py”**
** line 31, in , “C:\Users\An\AppData\Roaming\McNeel\Rhinoceros\5.0\scripts\Rhino Python Tutorial 11 - TangentsCrv_Parameters.py”**

import rhinoscriptsyntax as rs

class TanLines:
    
    def __init__(self, _curve, _numOfDivs):
        self.curve = _curve
        self.numOfDivs = _numOfDivs
    def tanPoints(self):
#        print("check")
        doms = rs.CurveDomain(self.curve)
#        print (doms)
        minDom = doms[0]
        maxDom = doms[1]
        
        for i in range (0,self.numOfDivs +1):
            
            param = (maxDom - minDom)/self.numOfDivs * i
            
            tan = rs.CurveTangent(self.curve, param)    #3D Vector
            tan = rs.VectorUnitize(tan)
            tan = rs.VectorScale(tan, 3)
            pt = rs.EvaluateCurve(self.curve, param)     
            rs.AddPoint(pt)

            tanPt = rs.VectorAdd(tan, pt)

            rs.AddLine(pt,tanPt)

curve = rs.GetObject("pick curve", 4)
obj01 = TanLines(curve,50)
obj01.tanPoints()

(Willem Derks) #2

Hi onrender,

Without testing the code on your curve it’s guessing what the issue is.

However, I do see this line that is a recipe for failure:

param = (maxDom - minDom)/self.numOfDivs * i

There should be an additional addition with the lower minDomain to prevent the parameter from falling out the curve domain.
If the domain start = 0 there is no problem but it can be any other number, causing the evaluation to return None.
To prevent this you can set it up like this:

param = minDom + ( (maxDom - minDom)/self.numOfDivs * i )

This omission is maybe the cause for the next line to return None, cascading errors down the line. What is the domain of the curve?

I do not see however how your code did work on both smaller and larger values than 50. If you provide the curve the scipt failed on it might be possible to detremine the cause of the failure.

-Willem


#3

I have uploaded the file. test script bug.3dm (29.3 KB)


(Willem Derks) #4

Hi onrender,

This is a floatingpoint error: the calculations on the curvedomain delta division and multiplication with ‘i’ result in a value for parm exceeding the curve domain by a tiny amount (7.1054273576e-15)
Yet this is enough to cause the evaluation to return None, causing cascading errors downstream.
Below is a ‘hack’ to make sure the (last) value is always the end of the domain instead of a calculated theoretical domain end


            param = (maxDom - minDom)/self.numOfDivs * i
            if param > maxDom : param = maxDom

alternative:

            param = (maxDom - minDom)/self.numOfDivs * i
            if i == self.numOfDivs :  param = maxDom

HTH
-Willem


#5

OK, it is interesting. Thanks Willem !