Проблемы с кругами и рендерингом линий ВороногоC#

Место общения программистов C#
Ответить
Anonymous
 Проблемы с кругами и рендерингом линий Вороного

Сообщение Anonymous »

При выравнивании по оси X
При выравнивании uo по оси Y
У меня есть сборный круг. Этот круг представляет собой средство рендеринга линий в форме круга. Вот что делает мой скрипт, прикрепленный к этим префабам:
  • Найти ближайшие круги
  • Сортировать ближайшие круги по углу
-используйте Mathf.Atan2() чтобы вычислить угол между каждым ближайшим кругом(ами) и текущим кругом
  • Удалить "сжатые" круги
-Для каждого круга в отсортированном списке ближайших флагов мы проверяем, зажат ли он между двумя другими, сравнивая расстояния между кругами
  • Найти пересечения между кругами
-вычислить пересечения каждого круга с текущим кругом
  • Сгладить кривую между точками пересечения
— изменяет окружность путем линейной интерполяции между две точки пересечения, создавая между ними прямой край.

[*]Повторите процесс для многократного пересечения
< /ol>
Как вы можете видеть на изображениях, я сглаживаю неправильную сторону только тогда, когда они имеют общую ось Z. И не оба, ВСЕГДА тот, у которого меньшее значение x.
Небольшой фрагмент относительного кода:

Код: Выделить всё

`private void FlattenBetweenIntersections(Vector3 intersection1, Vector3 intersection2)

    {

        float angle1 = GetAngleFromCenter(intersection1);

        float angle2 = GetAngleFromCenter(intersection2);

        if (angle1 > angle2)

        {

            float temp = angle1;

            angle1 = angle2;

            angle2 = temp;

        }

        FlattenCurveBetweenAngles(angle1, angle2);

    }

private void FlattenCurveBetweenAngles(float angle1, float angle2)

    {

        float angleStep = 360f / segments;

        int startIndex = Mathf.RoundToInt(angle1 / angleStep);

        int endIndex = Mathf.RoundToInt(angle2 / angleStep);

        Vector3 startPos = lineRenderer.GetPosition(startIndex);

        Vector3 endPos = lineRenderer.GetPosition(endIndex);

        for (int i = startIndex + 1; i < endIndex; i++)

        {

            float t = (float)(i - startIndex) / (endIndex - startIndex);

            Vector3 newPos = Vector3.Lerp(startPos, endPos, t);

            lineRenderer.SetPosition(i, newPos);

        }

    }`
Полный код ниже:
`с использованием System.Collections.Generic;
с использованием UnityEngine;
с использованием UnityEngine;
p>
публичный класс FlagController: MonoBehaviour
{

Код: Выделить всё

public float AOI = 25f;  // Max Area of Influence (radius)

public int segments = 50; // Number of segments for the circle

public LineRenderer lineRenderer;

// Unique identifier for each flag

public string flagID;

private static int flagCounter = 0; // Static counter to generate unique IDs

private void Start()

{

// Assign a unique ID based on the flagCounter

flagID = "Flag_" + flagCounter++;

// Setup the LineRenderer component

lineRenderer = GetComponent();

if (lineRenderer == null)

{

lineRenderer = gameObject.AddComponent();

}

// Set up the basic circle

lineRenderer.positionCount = segments + 1;

lineRenderer.useWorldSpace = false;

lineRenderer.loop = true;

lineRenderer.widthMultiplier = 0.2f;

// Generate the initial circular boundary

GenerateAOIBoundary();

// Find nearby flags automatically

List nearbyFlags = FindNearbyFlags();

// Sort by angle

SortByAngle(nearbyFlags);

// Cull squeezed flags

CullSqueezedFlags(ref nearbyFlags);

// Now calculate the Voronoi AOI based on nearby flags

if (nearbyFlags.Count > 0)

{

CalculateVoronoiAOI(nearbyFlags);

}

}

// Generates the initial circular boundary for the flag

public void GenerateAOIBoundary()

{

float angleStep = 360f / segments;

for (int i = 0; i 

{

float angleA = Mathf.Atan2(a.transform.position.z - transform.position.z, a.transform.position.x - transform.position.x);

float angleB = Mathf.Atan2(b.transform.position.z - transform.position.z, b.transform.position.x - transform.position.x);

return angleA.CompareTo(angleB);

});

}

// Cull flags that are squeezed out by others

private void CullSqueezedFlags(ref List nearbyFlags)

{

bool finishedCulling = false;

while (!finishedCulling && nearbyFlags.Count >= 3)

{

finishedCulling = true;

for (int i = 0; i < nearbyFlags.Count; i++)

{

FlagController flagA = GetLooped(nearbyFlags, i - 1);

FlagController flagB = GetLooped(nearbyFlags, i);

FlagController flagC = GetLooped(nearbyFlags, i + 1);

if (Vector3.Distance(transform.position, flagB.transform.position) > Vector3.Distance(flagA.transform.position, flagC.transform.position) &&

Vector3.Distance(flagA.transform.position, flagC.transform.position) > Vector3.Distance(flagA.transform.position, flagB.transform.position) &&

Vector3.Distance(flagA.transform.position, flagC.transform.position) > Vector3.Distance(flagB.transform.position, flagC.transform.position))

{

nearbyFlags.RemoveAt(i);

finishedCulling = false;

break;

}

}

}

}

// Calculate the Voronoi area of influence, considering nearby flags

public void CalculateVoronoiAOI(List nearbyFlags)

{

List intersections = new List();

foreach (FlagController nearbyFlag in nearbyFlags)

{

Vector3 intersection1, intersection2;

if (FindIntersections(this, nearbyFlag, out intersection1, out intersection2))

{

intersections.Add(intersection1);

intersections.Add(intersection2);

}

}

if (intersections.Count == 0)

{

GenerateAOIBoundary();  // No intersections, keep the full circle

}

else

{

FlattenCurveForIntersections(intersections);

}

}

// Find intersections between two flags' AOIs

private bool FindIntersections(FlagController flag1, FlagController flag2, out Vector3 intersection1, out Vector3 intersection2)

{

intersection1 = Vector3.zero;

intersection2 = Vector3.zero;

float d = Vector3.Distance(flag1.transform.position, flag2.transform.position);

if (d > flag1.AOI + flag2.AOI || d < Mathf.Abs(flag1.AOI - flag2.AOI))

{

return false; // No valid intersection

}

float a = (flag1.AOI * flag1.AOI - flag2.AOI * flag2.AOI + d * d) / (2 * d);

float h = Mathf.Sqrt(flag1.AOI * flag1.AOI - a * a);

Vector3 direction = (flag2.transform.position - flag1.transform.position).normalized;

Vector3 p2 = flag1.transform.position + a * direction;

intersection1 = new Vector3(p2.x + h * direction.z, flag1.transform.position.y, p2.z - h * direction.x);

intersection2 = new Vector3(p2.x - h * direction.z, flag1.transform.position.y, p2.z + h * direction.x);

return true;

}

// Flatten the curve between two intersection points

private void FlattenCurveForIntersections(List intersections)

{

intersections.Sort((a, b) => GetAngleFromCenter(a).CompareTo(GetAngleFromCenter(b)));

for (int i = 0; i < intersections.Count;  i += 2)

{

Vector3 intersection1 = intersections[i];

Vector3 intersection2 = intersections[i + 1];

FlattenBetweenIntersections(intersection1, intersection2);

}

}

// Helper function to get the angle from the center of the current flag

private float GetAngleFromCenter(Vector3 point)

{

Vector3 relativePoint = point - transform.position;

float angle = Mathf.Atan2(relativePoint.z, relativePoint.x) * Mathf.Rad2Deg;

if (angle < 0)

{

angle += 360f;

}

return angle;

}

// Helper function to flatten the curve between two intersection points

private void FlattenBetweenIntersections(Vector3 intersection1, Vector3 intersection2)

{

float angle1 = GetAngleFromCenter(intersection1);

float angle2 = GetAngleFromCenter(intersection2);

if (angle1 > angle2)

{

float temp = angle1;

angle1 = angle2;

angle2 = temp;

}

FlattenCurveBetweenAngles(angle1, angle2);

}

// Main function to flatten a curve between two angles

private void FlattenCurveBetweenAngles(float angle1, float angle2)

{

Debug.Log("{flagID} {angle1} {angle2}");

float angleStep = 360f / segments;

int startIndex = Mathf.RoundToInt(angle1 / angleStep);

int endIndex = Mathf.RoundToInt(angle2 / angleStep);

Vector3 startPos = lineRenderer.GetPosition(startIndex);

Vector3 endPos = lineRenderer.GetPosition(endIndex);

for (int i = startIndex + 1; i < endIndex; i++)

{

float t = (float)(i - startIndex) / (endIndex - startIndex);

Vector3 newPos = Vector3.Lerp(startPos, endPos, t);

lineRenderer.SetPosition(i, newPos);

}

}

// Helper function to get a looped element from the list

private FlagController GetLooped(List list, int index)

{

return list[(index + list.Count) % list.Count];

}
}`
Моя последняя попытка взяла центральную точку круга, а также получила позиции, которые, по ее мнению, должны были переместить круг (рендеринг линии) и проверил, находится ли там центральная точка, если нет, то мы поменяли местами отправленные углы, но это ничего не изменило.

Подробнее здесь: https://stackoverflow.com/questions/790 ... erer-issue
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»