001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package imagingbook.common.geometry.fitting.circle.utils;
010
011import imagingbook.common.geometry.basic.Pnt2d;
012import imagingbook.common.geometry.circle.GeometricCircle;
013
014import java.util.Random;
015
016import static imagingbook.common.math.Arithmetic.mod;
017import static java.lang.Math.PI;
018
019/**
020 * Defines utility methods for picking random points on a given circle.
021 * 
022 * @author WB
023 *
024 */
025public class CircleSampler {
026        
027        private final Random rg;        
028        private final GeometricCircle circle;
029        
030        public CircleSampler(GeometricCircle circle) {
031                this.circle = circle;
032                this.rg = new Random();
033        }
034        
035        public CircleSampler(GeometricCircle circle, long seed) {
036                this.circle = circle;
037                this.rg = new Random(seed);
038        }
039
040        /**
041         * Creates and returns an array of 2D points sampled on the circle associated with this {@link CircleSampler}.
042         * Random Gaussian noise (with standard deviation sigma) is added to the individual x/y coordinates.
043         *
044         * @param n number of points to sample
045         * @param startAngle initial angle (in radians)
046         * @param endAngle final angle (in radians)
047         * @param sigma sigma of Gaussian noise
048         * @return an array of sample points
049         */
050        public Pnt2d[] getPoints(int n, double startAngle, double endAngle, double sigma) {
051                double xc = circle.xc;
052                double yc = circle.yc;
053                double r = circle.r;
054                Pnt2d[] pts = new Pnt2d[n];
055                
056                startAngle = mod(startAngle, 2 * PI);
057                endAngle = mod(endAngle, 2 * PI);
058                double dAngle = (endAngle >= startAngle) ? 
059                                (endAngle - startAngle) :
060                                (endAngle + 2 * PI - startAngle);
061                
062                for (int i = 0; i < n; i++) {
063                        double alpha = startAngle + dAngle * i / n;
064                        double x = xc + r * Math.cos(alpha) + sigma * rg.nextGaussian();
065                        double y = yc + r * Math.sin(alpha) + sigma * rg.nextGaussian();
066                        pts[i] = Pnt2d.from(x, y);
067                }
068                return pts;
069        }
070
071}