87
|
1 #!/usr/bin/env python
|
|
2
|
|
3 """
|
|
4 random points in a circle
|
|
5 """
|
|
6 # TODO: a `D`-sphere
|
|
7
|
|
8 import math
|
|
9 import random
|
|
10 import sys
|
|
11 from .cli import DatasetGenerationParser
|
|
12
|
|
13
|
|
14 class CircularRandom(object):
|
|
15
|
|
16 twopi = 2.*math.pi
|
|
17
|
|
18 def __init__(self, center, radius=1.):
|
|
19 """
|
|
20 center -- (x,y) center of circle
|
|
21 """
|
|
22
|
|
23 assert radius > 0
|
|
24 self.center = (x, y) = center
|
|
25 self.radius = radius
|
|
26
|
|
27 def __call__(self, n_points):
|
|
28 """samples `n_points`"""
|
|
29
|
|
30 return [self.point() for _ in xrange(n_points)]
|
|
31
|
|
32 def point(self):
|
|
33 """samples a single point"""
|
|
34 # TODO: because area grows as 1/r, this will bias
|
|
35 # points towards the center. This should be corrected
|
|
36
|
|
37 r = self.radius*random.random()
|
|
38 theta = self.twopi*random.random()
|
|
39 x = math.cos(theta)
|
|
40 y = math.sqrt(1. - x*x)
|
|
41 if theta > math.pi:
|
|
42 y = -y
|
|
43 return (self.center[0] + x*r,
|
|
44 self.center[1] + y*r)
|
|
45
|
|
46
|
|
47 def main(args=sys.argv[1:]):
|
|
48 """CLI"""
|
|
49
|
|
50 # parse command line
|
|
51 parser = DatasetGenerationParser(description=__doc__)
|
|
52 parser.add_argument('--center', dest='center',
|
|
53 nargs=2, metavar=('X', 'Y'),
|
|
54 type=float, default=(0., 0.),
|
|
55 help="center of circle [DEFAULT: %(default)s]")
|
|
56 parser.add_argument('-R', '--radius', dest='radius',
|
|
57 type=float, default=1.,
|
|
58 help="radius of circle [DEFAULT: %(default)s]")
|
|
59 options = parser.parse_args(args)
|
|
60
|
|
61 # instantiate sampler
|
|
62 circle = CircularRandom(options.center, options.radius)
|
|
63
|
|
64 # get writer
|
|
65 writer = parser.writer()
|
|
66
|
|
67 # sample
|
|
68 points = circle(options.number)
|
|
69
|
|
70 # output
|
|
71 writer.writerows(points)
|
|
72
|
|
73 if __name__ == '__main__':
|
|
74 main()
|