private void Allocate(Point2D corner, double w, double h, int N)
        {
            if (w < 0 || h < 0)
                return;

            var N_max = Math.Min (N, (int) (2 * (w + h) / this.size));

            switch (N_max) {
                case 0 :
                    return;

                case 1 :
                    if (w < this.size / 2 || h < this.size)
                        return;

                    this.points.Add (corner + new Point2D (w, h / 2));
                    return;

                case 2 :
                    if (w < 2 * this.size || this.height < this.size)
                        return;

                    this.points.Add (corner + new Point2D (w, h / 2));
                    this.points.Add (corner + new Point2D (0, h / 2));
                    return;
            }

            for (var n = N_max; n > 2; -- n) {
                var l_0 = Math.Max (this.size, 2 * w / n);
                var l_1 = 2 * (w + h) / n;

                if (l_0 > l_1)
                    return;

                while (l_0 < l_1 && Math.Abs (l_0 - l_1) > 1.0) {
                    var l_c = (l_0 + l_1) / 2;
                    var delta_dist2 = DeltaDistance2 (this.PreAlloc (w, h, n, l_c));

                    if (DoubleEquals (delta_dist2, l_c * l_c))
                        l_0 = l_1 = l_c;

                    if (DoubleLess (delta_dist2, l_c * l_c))
                        l_1 = l_c;

                    if (DoubleGreater (delta_dist2, l_c * l_c))
                        l_0 = l_c;
                }

                var _points = this.PreAlloc (w, h, n, l_0);
                if (DoubleLess (DeltaDistance2 (_points), l_0 * l_0))
                    continue;

                foreach (var p in from p in _points
                                  select ((Point) (corner + p)))
                    this.points.Add (p);

                this.Allocate (corner + new Point2D (this.size, this.size), w - 2 * this.size, h - 2 * this.size, N - n);
                break;
            }
        }
        private void Allocate(Point2D center, double radius, int N)
        {
            if (N <= 0)
                return;

            if (radius <= 0)
                return;

            var phi = 2 * Math.Atan (this.size / (2 * radius));
            var n = (int) (2 * Math.PI / phi);

            if (N < n)
                n = N;

            phi = 2 * Math.PI / n;

            var phi_0 = 0.0;
            for (var i = 0; i < n; ++ i) {
                this.points.Add (center + CirclePoint (radius, phi_0));
                phi_0 += phi;
            }

            this.Allocate (center, radius - this.size, N - n);
        }
        private IEnumerable<Point2D> PreAlloc(double w, double h, int n, double l)
        {
            var point = new Point2D (w, h / 2);
            var vec = new Point2D (0, -1);
            yield return point;

            for (var i = 0; i < n - 1; ++i) {
                var _point = point + vec * l;

                if (_point.Y < 0 && DoubleEquals (_point.X, w)) {
                    _point = new Point2D (w - Cathetus (l, point.Y), 0);
                    vec = new Point2D (-1, 0);
                }

                if (_point.X < 0 && DoubleEquals (_point.Y, 0)) {
                    _point = new Point2D (0, Cathetus (l, point.X));
                    vec = new Point2D (0, 1);
                }

                if (_point.Y > h && DoubleEquals (_point.X, 0)) {
                    _point = new Point2D (Cathetus (l, h - point.Y), h);
                    vec = new Point2D (1, 0);
                }

                if (_point.X > w && DoubleEquals (_point.Y, h)) {
                    _point = new Point2D (w, h - Cathetus (l, w - point.X));
                    vec = new Point2D (0, -1);
                }

                point = _point;
                yield return point;
            }
        }