How can I generate a set of points evenly distributed along the perimeter of an ellipse?

后端 未结 8 718
庸人自扰
庸人自扰 2020-12-15 22:28

If I want to generate a bunch of points distributed uniformly around a circle, I can do this (python):

r = 5  #rad         


        
8条回答
  •  爱一瞬间的悲伤
    2020-12-15 22:44

    I'm sure this thread is long dead by now, but I just came across this issue and this was the closest that came to a solution.

    I started with Dave's answer here, but I noticed that it wasn't really answering the poster's question. It wasn't dividing the ellipse equally by arc lengths, but by angle.

    Anyway, I made some adjustments to his (awesome) work to get the ellipse to divide equally by arc length instead (written in C# this time). If you look at the code, you'll see some of the same stuff -

        void main()
        {
            List pointsInEllipse = new List();
    
            // Distance in radians between angles measured on the ellipse
            double deltaAngle = 0.001;
            double circumference = GetLengthOfEllipse(deltaAngle);
    
            double arcLength = 0.1;
    
            double angle = 0;
    
            // Loop until we get all the points out of the ellipse
            for (int numPoints = 0; numPoints < circumference / arcLength; numPoints++)
            {
                angle = GetAngleForArcLengthRecursively(0, arcLength, angle, deltaAngle);
    
                double x = r1 * Math.Cos(angle);
                double y = r2 * Math.Sin(angle);
                pointsInEllipse.Add(new Point(x, y));
            }
        }
    
        private double GetLengthOfEllipse()
        {
            // Distance in radians between angles
            double deltaAngle = 0.001;
            double numIntegrals = Math.Round(Math.PI * 2.0 / deltaAngle);
    
            double radiusX = (rectangleRight - rectangleLeft) / 2;
            double radiusY = (rectangleBottom - rectangleTop) / 2;
    
            // integrate over the elipse to get the circumference
            for (int i = 0; i < numIntegrals; i++)
            {
                length += ComputeArcOverAngle(radiusX, radiusY, i * deltaAngle, deltaAngle);
            }
    
            return length;
        }
    
        private double GetAngleForArcLengthRecursively(double currentArcPos, double goalArcPos, double angle, double angleSeg)
        {
    
            // Calculate arc length at new angle
            double nextSegLength = ComputeArcOverAngle(majorRadius, minorRadius, angle + angleSeg, angleSeg);
    
            // If we've overshot, reduce the delta angle and try again
            if (currentArcPos + nextSegLength > goalArcPos) {
                return GetAngleForArcLengthRecursively(currentArcPos, goalArcPos, angle, angleSeg / 2);
    
                // We're below the our goal value but not in range (
            } else if (currentArcPos + nextSegLength < goalArcPos - ((goalArcPos - currentArcPos) * ARC_ACCURACY)) {
                return GetAngleForArcLengthRecursively(currentArcPos + nextSegLength, goalArcPos, angle + angleSeg, angleSeg);
    
                // current arc length is in range (within error), so return the angle
            } else
                return angle;
        }
    
        private double ComputeArcOverAngle(double r1, double r2, double angle, double angleSeg)
        {
            double distance = 0.0;
    
            double dpt_sin = Math.Pow(r1 * Math.Sin(angle), 2.0);
            double dpt_cos = Math.Pow(r2 * Math.Cos(angle), 2.0);
            distance = Math.Sqrt(dpt_sin + dpt_cos);
    
            // Scale the value of distance
            return distance * angleSeg;
        }
    

提交回复
热议问题