Hi,

I’ve ported the `Population`

method from the Vector GHa lib, mentioned by @DavidRutten in this thread to GHPython. Now I’m looking for advice, on how to optimise the code in order to make it run faster, since I need it to produce about 10 000 to 20 000 points (tuples with 3 coordinates) for me.

Here are the current speeds of the Python component:

Population | Time | Percentage |
---|---|---|

10 | 6 ms | 28 % |

100 | 853 ms | 85 % |

1000 | 1.3 min | 100 % |

10 000 | 60 min | >100 % |

This is what the code looks like! The most interesting section to optimise might be the `populate()`

method of the `Population`

class.

```
import Rhino.Geometry as rg
import random
import math
import sys
class Population:
"""A population of random points within a region.
To use:
>>> ppl = Population(10, (25,25))
>>> ppl.populate()
>>> ppl.get_coordinates()
[(x0, y0, z0), (x1, y1, y2), ..., (x10, y10, z10)]
>>> ppl.get_points()
[Rhino.Geometry.Point3d, Rhino.Geometry.Point3d, ..., Rhino.Geometry.Point3d]
"""
def __init__(self, count, region):
self.count = int(count)
self.region = region
self.population = []
def distance_to(self, ptA, ptB):
"""Calculate the distance between two 3-dimensional points.
Args:
ptA: 3-dimensional point A (Rhino.Geometry.Point3d, tuple or list)
ptB: 3-dimensional point B (Rhino.Geometry.Point3d, tuple or list)
Returns:
The distance between point A and point B.
"""
dist = math.sqrt((ptA[0] - ptB[0])**2 + (ptA[1] - ptB[1])**2 + (ptA[2] - ptB[2])**2)
return dist
def next_point(self, domain):
"""Constructs a random 2-dimensional point coordinate.
Args:
domain: Tuple of 2 maximum values in x and y.
Returns:
Returns a tuple of random 2D point coordinates.
"""
maxX = domain[0]
minX = -maxX
maxY = domain[1]
minY = -maxY
return (random.uniform(minX, maxX), random.uniform(minY, maxY), 0)
def populate(self):
"""Populates a 2-dimensional region with random 2-dimensional points."""
distance_threshold = sys.maxint
for i in range(self.count):
if (len(self.population) == 0): # first point
pt = self.next_point(self.region)
self.population.append(pt)
else: # other points
attempts = int(max(50, math.sqrt(i)))
max_dist = -sys.maxint
max_pt = 0
for k in range(attempts):
if (k > 100) and (max_dist > distance_threshold * 0.9):
break
elif (k > 50) and (max_dist > distance_threshold * 0.92):
break
elif (k > 25) and (max_dist > distance_threshold * 0.95):
break
pt = self.next_point(self.region)
dist = sorted(self.distance_to(pt, prev_pt) for prev_pt in self.population)[0]
if dist == sys.maxint:
break
if dist > max_dist:
max_dist = dist
max_pt = pt
if (max_dist > distance_threshold * 1.25):
break
distance_threshold = max_dist
self.population.append(max_pt)
def get_coordinates(self):
"""Returns a list of random 2-dimensional point coordinates witihn a region."""
return self.population
def get_points(self):
"""Returns a list of Rhino.Geometry.Point3d witin a redion."""
pts = [rg.Point3d(c[0], c[1], c[2]) for c in self.population]
return pts
# Variables
count = 10 # number of random points to produce
domain = (5.0, 5.0) # max. extends of the region in x and y
# Initialise class
ppl = Population(count, domain)
ppl.populate()
# Output
a = ppl.get_points()
```

(To test the script, just copy and paste the python code into a GHPython component and run it.)

Any advice is welcome and appreciated!