@Willem wrote:
Hi All,
I’ve been wanting to post an example of using classes in RhinoPython for a long time.
Inspired by the recent contamination simulations I found a good example of using a class.At least I hope so, as understanding classes takes some time and maybe these examples are already too complex. Let me know if you have any questions or add comments to help others.
The first script is a simple random population “walking around”
contamination_simulation_01.py (4.3 KB)
Building on that first script I made a random person contaminated and let all walk around.
If someone comes too close to a contaminated person the contamination extends to them.
contamination_simulation_02.py (5.6 KB)
In the last version I added avoidance: everyone that is contaminated tries to avoid proximity to others by adjusting their course.
contamination_simulation_03.py (7.2 KB)
-Willem
Below the full code of the last version (contamination_simulation_03.py)
import rhinoscriptsyntax as rs import scriptcontext as sc import Rhino import random import System # script by willemderks march 2020 # the script is an attempt to visualize the spread of a virus in a community # based on the behaviour of the individuals in that community # goal is to give an example of how classes can be used in RhinoPython class Person(object): """ this defines a class object that represents a person inside the simulation this object will have spatial properties a position (.point) a direction (.vector) a speed (.speed) this object will have virus related properties contaminated True/False symptomatic True/False immune True/False there are additional properties that influence the behaviour carelessness 0.0 ~ 1.0 """ #these are some class global variables #changing these will affect all class instances color_dict = {} #dictionary with colors for states color_dict['healty'] = System.Drawing.Color.FromArgb(80,120,80) color_dict['contaminated'] = System.Drawing.Color.FromArgb(140,50,50) color_dict['immune'] = System.Drawing.Color.FromArgb(190,220,190) infection_distance = 10 #distance for contamination infection_duration = 150 #frames it takes to fight infection and become immune def __init__(self, point, vector, speed): #this method is called when creating the instance #the self variable represents the instance itself self.point = point self.vector = vector self.speed = speed self.state = 'healty' #by default all persons are healty self.prepared_point = None self.color = self.color_dict[self.state] self.others = [] self.contaminated_frames = 0 def add_others(self, others): #add others exclusing self self.others = [other for other in others if not other == self] def distance_to(self,other): #calculate the distance to another person return self.point.DistanceTo(other.point) def future_position(self): return self.point + (self.vector*self.speed) def do_contamination(self): #check if others in proximity and pass contamination if self.state == 'contaminated' : for other in self.others: if other.state == 'healty': if self.distance_to(other) <= self.infection_distance: other.state = 'contaminated' def adjust_course(self): #predict the position of others for the next frame #if they are contaminated and too close adjust direction if self.state != 'contaminated': return my_future_position = self.future_position() avoidance_vectors = [] for other in self.others: if other.state == 'contaminated': continue #test if the next frame I'm too close other_future_position = other.future_position() other_future_distance = my_future_position.DistanceTo(other_future_position) if other_future_distance <= self.infection_distance: #create vector away from future position away_vec = Rhino.Geometry.Vector3d(my_future_position-other_future_position) away_vec.Unitize() #set the length of the vector little over the safe distance away_vec = away_vec * 1.1 * (self.infection_distance*other_future_distance) avoidance_vectors.append(away_vec) if not avoidance_vectors : return #get the mean vector of all avoidances all_vec = Rhino.Geometry.Vector3d(0,0,0) for vec in avoidance_vectors: all_vec = all_vec + vec mean_vec = all_vec/len(avoidance_vectors) mean_vec.Unitize() self.vector = mean_vec def prepare_frame(self): #if infected, contaminate all that are close self.do_contamination() if self.state == 'contaminated': self.contaminated_frames += 1 if self.contaminated_frames > self.infection_duration: self.state = 'immune' self.adjust_course() self.prepared_point = self.future_position() #simple bounce at limits when out of bounds self.vector = do_bounce_vector(self.prepared_point, self.vector) def set_frame(self): self.point = Rhino.Geometry.Point3d(self.prepared_point) self.color = self.color_dict[self.state] # utilities def get_random_point(): x = -100 + random.random()*200 y = -100 + random.random()*200 return Rhino.Geometry.Point3d(x,y,0) def get_random_vector(): x = (-0.5+random.random()) y = (-0.5+random.random()) vector = Rhino.Geometry.Vector3d(x,y,0) vector.Unitize() return vector def get_random_speed(): base_speed = 2 speed_factor = 5 random_speed = random.random() return (base_speed + random_speed)/speed_factor def do_bounce_vector(point,vector): if not -100 < point.X < 100 : vector.X = -vector.X if not -100 < point.Y < 100 : vector.Y = -vector.Y return vector #runner def do_run(): rs.EnableRedraw(False) people = [] total = 100 for i in range(total): pt = get_random_point() vec = get_random_vector() spd = get_random_speed() new_person = Person(pt,vec,spd) people.append(new_person) # we add the population to each individual # this allows for each individual to 'see' the others for person in people: person.add_others(people) # we now have 100 random people # we infect 1 of them people[0].state = 'contaminated' #lets make them move for 300 frames #a colorized pointcloud to visualize them point_cloud = Rhino.Geometry.PointCloud() _ = [point_cloud.Add(person.point,person.color) for person in people] cloud_id = sc.doc.Objects.AddPointCloud(point_cloud) frames = 1500 for i in range(frames): #use a generator to let all people caluculate their next frame _ = [person.prepare_frame() for person in people] #use a generator to set the prepared state as the new state _ = [person.set_frame() for person in people] #use a generator to fill the new pointcloud point_cloud = Rhino.Geometry.PointCloud() _ = [point_cloud.Add(person.point,person.color) for person in people] #replace the old pountcloud geometry with the new one sc.doc.Objects.Replace(cloud_id, point_cloud) #update the viewports rs.Redraw() rs.DeleteObject(cloud_id) rs.EnableRedraw(True) if( __name__ == '__main__' ): do_run()
Posts: 3
Participants: 2