Selecting same radius circles


#1

Hi,

here is simple script to select all the circles of a certain radius. It should be pretty straight forward. However, when I run it I find it only finds SOME of the circles of that radius. When I look at the ones it doesn’t select, they seem to have an identical radius to the ones it did select.

rs.UnselectAllObjects()
diam = rs.GetReal("Diameter to search", 5.0 )
srchrad = diam/2.0
objs = rs.ObjectsByType (4, select=False)
info = 0
for object_id in objs:
	if rs.IsCircle(object_id):
		if rs.CircleRadius(object_id) == (srchrad):
			rs.SelectObject(object_id)
			info += 1
print str(info) + " objects selected"

I’m wondering if it has something to do with rounding, or if the object has been scaled or moved or copied or something. Any suggestions?

Thanks
Peter


#2

Hi Peter,

to find out if it is related to rounding, you could print to the commandline which radius value rs.CircleRadius(object_id) returned. With your comparison operator ==, it would fail eg. if variable srchrad has different amount of digits compared to the returnvalue. You might use float(YourValue) before doing the comparison, or alternatively, include the absolute unit tolerance in the comparison:


import rhinoscriptsyntax as rs

def CircleByRadius():
    rs.UnselectAllObjects()
    diam = rs.GetReal("Diameter to search", 5.0 )
    if diam:
        srchrad = diam/2.0
        objs = rs.ObjectsByType (4, select=False)
        info = 0
        tol = rs.UnitAbsoluteTolerance()
        for object_id in objs:
            if rs.IsCircle(object_id):
                radius = rs.CircleRadius(object_id)
                if radius <= srchrad+tol and radius >= srchrad-tol:
                    rs.SelectObject(object_id)
                    info += 1
        print str(info) + " objects selected"

if __name__=="__main__":
    CircleByRadius()

Note that rs.IsCircle(object_id) returns only real circles. (it fails on rebuild ones regardless of the tolerance)

c.


#3

Thanks Clement!

It was the decimal places, I think the ‘first generation’ ones had 2 decimal places while the copies had about 8.
Rounding both to 4 decimal places before comparison fixed it.
Strangely, just casting them both with float() didn’t work, as the number of decimal places didn’t change as a result.

cheers Peter


#4

Casting double to float will help if your values differ in places beyond the precision of float, which is about 7 decimals.

In general, you should avoid == comparisons with any floating point number. Always do a @clement suggested and compare the difference against a tolerance.


(Willem Derks) #5

Hi Peter,

How about checking like this ( pseudo code)

(rs.CircleRadius(object_id) - (srchrad)) < radius_tolerance

-Willem


#6

Yeah, sorry i´ve not been testing the float thing. Your way seemed much better to use round like eg.:

round(number: float, ndigits: int) -> float

c.


#7

I normally write it a bit different.

if abs(radius-srchrad) <= tol:

I think its a bit cleaner :smile:

M


#8

I think to do the check as you suggest it would be necessary to compare the ABSOLUTE VALUE of the left-hand-side to the radius_tolerance:

ABS((rs.CircleRadius(object_id) - (srchrad))) < radius_tolerance (I didn’t confirm the actual rs syntax for the absolute value function)


#9

Yep… --Mitch


#10

Yes, less code is always welcome ! :wink:

c.


#11

Thanks for all of that guys!
Given how intolerant == is, using abs() and tolerance looks like the way to go!
cheers Peter