Iteration over non-sequence of type NoneType


#1

Hi all,

I am trying to write a script to let python to help to get panels in a row.
This script could be useful when you have thousands of panels.
The strategy is to provide the first panel in the row and specify a vector for selection then let python to select the rest on the row from the panel collection.


It is almost getting there but I got an error saying" Iteration over non-sequence of type NoneType".
I am not sure what does it mean but I am pretty sure it occur due to I have remove a panel from the list of panels.
Appreciate if someone can tell me why it would be a problem – why can’t I remove a panel? I thought a list should be dynamic and you can always modify it…

Select panels in a row.3dm (93.5 KB)
Select panels in a row.py (1.2 KB)

Thanks for any help,

Jack


#2

Hi @Jack_Zeng,

i think that this line:

pt = rs.VectorAdd(cpt,vect)

does not move the point closer to the panels, try it using rs.AddPoint(pt) in your loop. Would it be possible to just pick a line like in below example ?

import Rhino
import rhinoscriptsyntax as rs

def SelectPanelsNearLine():
    
    ids = rs.GetObjects("Select all panels", 8, True, True, False)
    if not ids: return
    
    pt_start = rs.GetPoint("Pick point on start of row")
    if not pt_start: return
    
    pt_end = rs.GetPoint("Pick point on end of row", pt_start)
    if not pt_end: return
    
    line = Rhino.Geometry.Line(pt_start, pt_end)
    curve = line.ToNurbsCurve()
    params = curve.DivideByCount(100, True)
    points = [curve.PointAt(param) for param in params]
    panels = set()
    
    for pt in points:
        pco = rs.PointClosestObject(pt, ids)
        if pco: panels.add(pco[0])
        
    if len(panels) != 0: rs.SelectObjects(list(panels))
    
SelectPanelsNearLine()

it is just an idea of course…

c.


#3

I can’t quite pin point where the error comes from but the iteration seems to go through the entire length of ‘panels’. Your centroid may move out of the length of the row pretty quickly. I’d use a while loop and make it stop when it reaches the end of that row.


(Willem Derks) #4

Hi Jack,

I can not test your code as I’m on my phone.
But I’d like to point out that placing a debug break at line 25 will allow you to step into the code and scrutinise what is being passed for the arguments pt and panels.

My suspision is that the error is caused by all panels being popped out of the panels list . So the closest point search has no objects to search.

If you place a print panels between line 24 and 25 you can check the command line after the crash to see what panels was before the crash.

HTH
-Willem


#5

Hi clement,

Thanks!! Your lines are so elegant and inspiring~~
I have go through every line and hope I understand it right:


But got a minor query: understand set() can remove duplicated panel ids but will it also jitter the panel sequence in the list since it sorts the sequence base on the ids’ alphabet / number?
untitled.py (1.5 KB)

Many thanks,

Jack


#6

Hi Will,

Thanks for your suggestion! you are right, I have amend the iteration count and seems the error doesn’t pop up again.

Cheers,

Jack


#7

Hi Willem,

yes, you are right, I guess I should not delete ids from the list otherwise the iteration will not match the number of panels…

Jack


#8

@Jack_Zeng,

your comments added above are correct. To answer the questions, the set does not allow duplicates and it may not keep the order of the elements added to it while it removes the duplicates. The order in which the objects are added are along the line but it may change, to keep the order, you might try using an OrderedSet or use a list which you parse later to remove consecutive duplicates. I’ve used 100 division points to make sure no panel is missed.

Do you need the previous order of the panels in the final list ?

c.


#9

Hi clement,

Thanks for your reply. Yes, I would like the panels maintain a certain sequence. OrderedSet( ) seems to be a class. Haven’t look into it yet…
I have modified the script a bit, seems it works. But just curious is there any other neat way(like a method) can eliminate duplicate items in a list but also maintain its original sequence.


01.py (1.2 KB)

Thanks,

Jack


#10

Hi @Jack_Zeng,

you can maintain the order in the panel ids by not adding the panels but only its indices to a list. Then iterate over the sorted list to select the panels:

    panel_indices = []
    for pt in points:
        pco = rs.PointClosestObject(pt, ids)[0]           
        index = ids.index(pco)
        if index not in panel_indices:                             
            panel_indices.append(index)

    for i in sorted(panel_indices):
        rs.SelectObject(ids[i])
        rs.Sleep(50)

This does not require additional classes and creates no duplicates.

c.


#11

Cool, thanks clement!!