[Python] Example using the Particle Class

Where can I find an example using the Particle Class?

https://developer.rhino3d.com/5/api/RhinoCommon/html/T_Rhino_Geometry_Particle.htm

There was some talk about it in this thread. Don’t expect too much though it’s pretty barebones

1 Like

Thanks for the link Lando.

Hi @stevebaer, during the last 4 years are there any working applicable examples of the Particle Class usage?

Preferably with python.

Thanks in advance.

Not really, though there isn’t much to it. You create a ParticleSystem instance and add Particles to it. You would typically subclass the Particle class to provide your own Update function.

It’s really just the basic particle/particle system framework that people start with to make something that actually works. The advantage that this class has over making one up from scratch is that the DisplayPipeline has a DrawParticles function that can quickly draw an entire particle system.

I’m sure for a professional programmer there isn’t, but for a script kiddie like myself (I’m sure many others, as well) not so much true. And this is exactly why I wish there were examples.

You state in the api and I quote:

Be it as it may, a small example showing it in action movement over time or frames would be great.

The only example was the one from the post (link above). in C#. :nauseated_face:

I tried to translate it myself into Python, and although I cleared the errors I still cannot see any of the particles on the viewport(s)

"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "zooid"
__version__ = "2019.02.17"

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino
sc.doc = Rhino.RhinoDoc.ActiveDoc

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    #file = ""
    
    def DrawForeground(DrawEventArgs):
        bm = Bitmap(file)
        dbm = DisplayBitmap(bm)
        e.Display.DrawParticles(ps, dbm)
        
psDisplay = PSDisplay()
if display:
    psDisplay.Enabled = True
    Rhino.RhinoDoc.ActiveDoc.Views.Redraw()
    
else:
    Rhino.RhinoDoc.ActiveDoc.Views.Redraw()


p = Particle()
a = []
for pt in pts:
    p.Location = pt
    p.Size = 10
    p.Color = Color.FromArgb(10,255,0,255)
    psDisplay.ps.Add(p)
    a.append(p)

Could anyone please give me a hint what is it that I’m doing wrong?

ParticleClass.gh (13.2 KB)

Anyone?

hey @ivelin.peychev i tried coding up an example for you just now but… i can’t get it to draw any bitmaps from my computer. When I create a bitmap in memory like in this example it kind of work’s, sometimes:
https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Display_DisplayPipeline_DrawBitmap.htm

In your script the only error I see is that you call “draw foreground wrong”.

It should be:

def DrawForeground (self, e):

Also as a tip: to see if your bitmap display is the problem or the particles itself, draw their boundingbox:

def DrawForeground(self, e):
    e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)

Writing this on my phone so formatting errors are bound to happen

Thanks for the suggestions Lando.

"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "zooid"
__version__ = "2019.02.17"

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino
sc.doc = Rhino.RhinoDoc.ActiveDoc

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    #file = ""
    
    def DrawForeground(self,e):#=DrawEventArgs
        bm = Bitmap(file)
        dbm = DisplayBitmap(bm)
        e.Display.DrawParticles(ps, dbm)
        
        
psDisplay = PSDisplay()
if display:
    psDisplay.Enabled = True
    Rhino.RhinoDoc.ActiveDoc.Views.Redraw()
    #e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)
else:
    Rhino.RhinoDoc.ActiveDoc.Views.Redraw()


p = Particle()
a = []
for pt in pts:
    p.Location = pt
    p.Size = 10
    p.Color = Color.FromArgb(10,255,0,255)
    psDisplay.ps.Add(p)
    
    a.append(p)
    

the result is:
image

and finally:
image

@stevebaer, any ideas?

I’m not sure if that can work in the GhPython context. Looking into it …

1 Like

Hi @Alain, @stevebaer,

What context is needed for this class?

Even when runnning the script below from RhinoPython it still crashes Rhino.

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino
sc.doc = Rhino.RhinoDoc.ActiveDoc

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    #file = ""
    
    def DrawForeground(self,e):#=DrawEventArgs
        bm = Bitmap(file)
        dbm = DisplayBitmap(r"Z:\zooid\IronPython\zShowOff\main.menu.icon.open.bmp")
        e.Display.DrawParticles(ps, dbm)
        #e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)
        
psDisplay = PSDisplay()

psDisplay.Enabled = True
Rhino.RhinoDoc.ActiveDoc.Views.Redraw()


p = Particle()



for pt in pts:
    p.Location = pt
    p.Size = 10
    p.Color = Color.FromArgb(10,255,0,255)
    psDisplay.ps.Add(p)
    
    #a.append(p)

Hi,
A few edits:

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem, Point3d
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    file = r"Z:\zooid\IronPython\zShowOff\main.menu.icon.open.bmp"
    
    def DrawForeground(self,e):#=DrawEventArgs
        bm = Bitmap(self.file)
        dbm = DisplayBitmap(bm)
        e.Display.DrawParticles(self.ps, dbm)
        #e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)
        
psDisplay = PSDisplay()

pts = [Point3d.Origin, Point3d(2,2,2), Point3d(1,1,1), Point3d(3,3,3)]
for pt in pts:
    p = Particle()
    p.Location = pt
    p.Size = 10
    psDisplay.ps.Add(p)
    
psDisplay.Enabled = True
rs.Redraw()
rs.GetString("wait ...")
psDisplay.Enabled = False
rs.Redraw()

Hi @Alain,

Thanks a lot now it doesn’t crash :slight_smile:

But I see only one image displayed. Shouldn’t this:

pts = [Point3d.Origin, Point3d(2,2,2), Point3d(1,1,1), Point3d(3,3,3)]

for pt in pts:
    p = Particle()
    p.Location = pt
    p.Size = 100
										  
    psDisplay.ps.Add(p)

Display 4 images or is it simply moving the image from one point to the next in a split-second?

You should see 4 images. I just ran the script to confirm.

I don’t know what to check, running the script results in this:

Hi @Alain,

Is it possible that Set is also added here?:

I modified a bit the code, but kept the behavior from your sample.

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem, Point3d
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    file = r"Z:\zooid\IronPython\zShowOff\main.menu.icon.open.bmp"
    
    def DrawForeground(self,e):#=DrawEventArgs
        bm = Bitmap(self.file)
        dbm = DisplayBitmap(bm)
        e.Display.DrawParticles(self.ps, dbm)
        #e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)

def create_particle(pt=None,idx=0):
    if pt is None:
        pt = Rhino.Geometry.Point3d.Origin
    p = Particle()
    #p.Color = Color.Yellow
    #p.DisplayBitmapIndex
    
    #p.ParentSystem
    p.Location = pt
    p.Size = 20
    psDisplay.ps.Add(p)
    print p.Index
    rs.Redraw()

psDisplay = PSDisplay()
print psDisplay.ps
"""
pts = [Point3d.Origin, Point3d(2,2,2), Point3d(1,1,1), Point3d(3,3,3)]#
for pt in pts:
    create_particle(pt)
"""
create_particle(Point3d.Origin,0)
create_particle(Point3d(1,1,1),1)
create_particle(Point3d(2,2,2),2)
create_particle(Point3d(3,3,3),3)

psDisplay.Enabled = True

rs.Redraw()

rs.GetString("wait ...")
psDisplay.Enabled = False
rs.Redraw()

I keep getting a single particle. And then I noticed this:

I fear when psDisplay.ps.Add(p) is used it is overwriting the same particle in the particle system, thus only a single particle exists at a time. Just it’s location is changed.

If we’re able to SET the index of the particles in the system then we’ll get them all. But this property of the class particle is read-only at the moment.

hmm :thinking:

On the other hand if I do this:

for particle in psDisplay.ps:
    print particle.Location

I get the four locations
image

Could the problem be graphics card related?

:slight_smile:

image

Something fishy is happenning. Particles have the same index in the particle system but different locations.

Hi @Alain,

Could you please test this:

import rhinoscriptsyntax as rs

from Rhino.Geometry import Particle, ParticleSystem, Point3d
from System.Drawing import Color, Bitmap
from Rhino.Display import DisplayConduit, DisplayBitmap, DrawEventArgs
import scriptcontext as sc
import Rhino

class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    file = r"Z:\zooid\IronPython\zShowOff\main.menu.icon.open.bmp"
    
    def DrawForeground(self,e):#=DrawEventArgs
        bm = Bitmap(self.file)
        dbm = DisplayBitmap(bm)
        e.Display.DrawParticles(self.ps, dbm)
        #e.Display.DrawBoundingBox(self.ps. BoundingBox, System.Drawing. Color.Black)

def create_particle(pt=None,idx=0):
    if pt is None:
        pt = Rhino.Geometry.Point3d.Origin
        
    p = Particle()
    #p.Color = Color.Yellow
    #p.DisplayBitmapIndex
    
    #p.ParentSystem
    p.Location = pt
    p.Size = 1
    psDisplay.ps.Add(p)
    #psDisplay.ps.Update()
    #print p.Index
    rs.Redraw()

psDisplay = PSDisplay()

"""
pts = [Point3d.Origin, Point3d(2,2,2), Point3d(1,1,1), Point3d(3,3,3)]#
for pt in pts:
    create_particle(pt)
"""
#create_particle(Point3d.Origin,0)
#create_particle(Point3d(1,1,1),1)
#create_particle(Point3d(2,2,2),2)
#create_particle(Point3d(3,3,3),3)

psDisplay.Enabled = True
for i in range(100):
    create_particle(Point3d(float(i),float(i),float(i)))
    rs.Redraw()




for particle in psDisplay.ps:
    
    print particle.Index, particle.Location

rs.GetString("wait ...")
psDisplay.Enabled = False
rs.Redraw()

Why does the size change?

@ivelin.peychev, I’m sorry for not noticing earlier but DrawParticles is broken in SR14. It was working before and is fixed in SR15 which is not available yet.

Also in the script I’m noticing that DisplayBitmap is called for every call to DrawForeground. You only want to create it once when instantiating the class. Something like:

...
class PSDisplay(DisplayConduit):
    ps = ParticleSystem()
    file = r"Z:\zooid\IronPython\zShowOff\main.menu.icon.open.bmp"
    bm = Bitmap(self.file)
    dbm = DisplayBitmap(bm)
    
    def DrawForeground(self,e):#=DrawEventArgs
        e.Display.DrawParticles(self.ps, self.dbm)
...
1 Like

Thanks for the reply @Alain.

I’m looking forward to test SR15.
Is there an estamate when it will be available RC?

The plan is to release SR14 next Tuesday - An RC 15 will then become available.