Как да позиционирате пръстен от кръгове с максимален радиус на пръстена

Опитвам се да създам пръстен от кръгове, ала:

Кръговете имат даден радиус, circleRadius. Пръстенът има максимален радиус, maxRingRadius. Броят на кръговете може да бъде всяко цяло число, circles, което трябва да се изчисли, заедно с действителния радиус на пръстена, ringRadius. Кръговете, когато центровете им са разположени на ringRadius единици от центъра на пръстена, трябва да се докосват точно, както е на диаграмата.

При дадени circleRadius и maxRingRadius, как може да се намери най-близкото (или следващото най-малко) ringRadius, което ще пасне на цяло число circles, и след това да позиционира тези кръгове?

    static Vector3[] RingOfCircles(float maxRingRadius, float circleRadius) {
        //int circles = ...; // calculate this?
        //float ringRadius = ...; // calculate this?

        //Edit: Solution. These three lines are adapted from InBetween's GetNextSmallerRingRadius function but Unity3d-ized and without validation
        int circles = Mathf.RoundToInt(Mathf.PI / Mathf.Asin(circleRadius / maxRingRadius)); 
        float centralAngle = 2 * Mathf.PI / (numberOfCircles - 1);
        float ringRadius = circleRadius / Mathf.Sin(centralAngle / 2);

        // create ring of center points
        float radsPerCircle = (Mathf.PI * 2) / circles;
        Vector3[] centerPoints = new Vector3[circles];
        for (int i=0; i < circles; i++) {
            float angle = i * radsPerCircle;
            centerPoints[i] = new Vector3(
                Mathf.Sin(angle) * ringRadius, 
                Mathf.Cos(angle) * ringRadius, 
                0);
        }

        return centerPoints;
    }
`

Забележка: maxRingRadius може също така да бъде minRingRadius или approximateRingRadius за моите цели. Но ringRadius трябва да дефинира следващия най-близък „пръстен“, който може да съдържа цял брой кръгове.


Решено: Визуално потвърждение на решениетоВизуално потвърждение на решението


person Qubei    schedule 08.10.2014    source източник


Отговори (1)


Ако съм разбрал правилно въпроса ви, това трябва да го направи:

 public static double GetNextSmallerRingRadius(double startingRingRadius, double circleRadius)
 {
     Debug.Assert(startingRingRadius >= 0);
     Debug.Assert(circleRadius > 0);

     int currentNumberOfCircles = GetCurrentNumberOfCircles(startingRingRadius, circleRadius);

     //Let's get trivial cases out of the way
     if (currentNumberOfCircles == 1)
         throw new ArgumentException();
     if (currentNumberOfCircles == 2)
         return 0; //trivial solution for 1 circle.
     if (currentNumberOfCircles == 3)
         return circleRadius; //trivial solution for 2 circles.

     double centralAngle = 2 * Math.PI / (currentNumberOfCircles - 1);
     return circleRadius / Math.Sin(centralAngle / 2);
 }

 public static double GetNextLargerRingRadius(double startingRingRadius, double circleRadius)
 {
     Debug.Assert(startingRingRadius >= 0);
     Debug.Assert(circleRadius > 0);

     int currentNumberOfCircles = GetCurrentNumberOfCircles(startingRingRadius, circleRadius);

     //Let's get trivial cases out of the way
     if (currentNumberOfCircles == 1)
         return circleRadius; //trivial solution for 2 circles.

     double centralAngle = 2 * Math.PI / (currentNumberOfCircles + 1);
     return circleRadius / Math.Sin(centralAngle / 2);
 }

 private static int GetCurrentNumberOfCircles(double startingRingRadius, double circleRadius)
 {
     if (startingRingRadius == 0)
     {
         return 1;
     }
     else
     {
         return (int)Math.Round(Math.PI / Math.Asin(circleRadius / startingRingRadius), 0); //There would need to be some logic to make sure input values are correct.
     }
 }

За да потвърдите въвеждането (дефинираните радиуси представляват валидно решение), можете да сравните закръглените и незакръглените numberOfcircles и да се уверите, че разликата е в даден толеранс. Не забравяйте, че с double не можете да проверите за равенство, тъй като винаги ще има грешка в представянето.

АКТУАЛИЗАЦИЯ Опа, не видях, че питате и за позиционирането на кръговете. След като знаете радиуса на пръстена и централния ъгъл, всичко е доста лесно.

person InBetween    schedule 08.10.2014
comment
Отлично. Благодаря ти! Работи чудесно. Вече имах кода за окончателното позициониране на кръговете в моя въпрос, така че тази част така или иначе беше излишна :) - person Qubei; 08.10.2014