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

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

Сообщение Anonymous »

При выравнивании по оси X
При выравнивании по оси Y
У меня есть сборный круг. Этот круг представляет собой средство рендеринга линий в форме круга. Вот что делает мой скрипт, прикрепленный к этим префабам:
  • Найти ближайшие круги
  • Сортировка соседних кругов по углу: используйте Mathf.Atan2(), чтобы вычислить угол между каждым ближайшим кругом(ами) и текущий круг
  • Отбраковывать «сжатые» круги: для каждого круга в отсортированном списке ближайших флагов мы проверяем, есть ли он втиснут между двумя другими путем сравнения расстояний между кругами.
  • Найти пересечения между кругами: вычислить пересечения между каждый круг с текущим кругом
  • Сгладить кривую между точками пересечения: изменяет круг путем линейной интерполяции между ними. точек пересечения, создавая между ними прямой край.
  • Повторите процесс для многократного пересечения
Как вы можете видеть на изображениях, я сглаживаю изнаночную сторону только тогда, когда они имеют общую ось 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);
    }
}
Полный код ниже:

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

using System.Collections.Generic;
using UnityEngine;

public class 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#»