выборочно соединить точки на карте

Форум для самых маленьких, а так же тех, кому недосуг читать справку самостоятельно.

выборочно соединить точки на карте

Сообщение z-red 15 янв 2021, 09:46

Тут проблема даже хуже - не могу правильно сформулировать гуглу вопрос:
Нужно получить вот такое.
Изображение
Сами звезды есть, линий их соединяющих нет. Понимаю, что каждая точка должна содержать в себе ссылку на соседа, и по по координатам точки и выбранного соседа строится нить.
Подскажите пожалуйста, есть ли рекомендуемые (как а*-алгоритм для поиска пути) алгоритмы для этой задачи, чтобы не пришлось велосипедить.
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya

Re: выборочно соединить точки на карте

Сообщение samana 15 янв 2021, 10:37

По этой картинке непонятно по каким правилам соединены точки. Но визуально похожая паутинка нитей получается путём соединения точек, расстояние между которыми задаётся некой константой. Например проводим линию только к тем соседям, до которых не более десяти метров.
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: выборочно соединить точки на карте

Сообщение seaman 15 янв 2021, 13:05

Ну тут не все соединения нарисованы, так что действительно непонятны правила этих соединений.
Ну а если были бы все, то:
https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B8%D0%B0%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D0%94%D0%B5%D0%BB%D0%BE%D0%BD%D0%B5
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: выборочно соединить точки на карте

Сообщение z-red 15 янв 2021, 21:40

seaman писал(а):Ну тут не все соединения нарисованы, так что действительно непонятны правила этих соединений.
Ну а если были бы все, то:
https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B8%D0%B0%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D0%94%D0%B5%D0%BB%D0%BE%D0%BD%D0%B5

Спасибо, взял на вооружение. В вики-статье были еще ссылки на занимательные алгоритмы)
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya

Re: выборочно соединить точки на карте

Сообщение z-red 15 янв 2021, 21:44

samana писал(а):По этой картинке непонятно по каким правилам соединены точки. Но визуально похожая паутинка нитей получается путём соединения точек, расстояние между которыми задаётся некой константой. Например проводим линию только к тем соседям, до которых не более десяти метров.

Правила примерно такие, как мне показлось - формируются независимые созвездия в пределах заданного количества, а потом малым количеством перемычек соединяются между собой. На других картинках зметил позже.
Спасибо.
Как допишу - выложу, может кому пригодится.
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya

Re: выборочно соединить точки на карте

Сообщение z-red 15 янв 2021, 21:56

https://drive.google.com/file/d/14fyiWpBfCUfjxed_iBx0cmTe3ChDy6gi/view?usp=sharing
не получается вставить как картинку. ну пока так вот вышло.
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya

Re: выборочно соединить точки на карте

Сообщение samana 15 янв 2021, 22:02

z-red писал(а):ну пока так вот вышло

Почти получилось. Правда некоторые линии, которые пересекаются между собой, явно лишние. Но как он них избавится, не проверяя каждую линию на пересечение с другой линией я не знаю..
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: выборочно соединить точки на карте

Сообщение z-red 15 янв 2021, 23:20

samana писал(а):
z-red писал(а):ну пока так вот вышло

Почти получилось. Правда некоторые линии, которые пересекаются между собой, явно лишние. Но как он них избавится, не проверяя каждую линию на пересечение с другой линией я не знаю..

Мне кажется, нужно сократить максимальное количество исходящих из точки линий до трех - у треугольноков нет диагоналей.
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya

Re: выборочно соединить точки на карте

Сообщение z-red 22 янв 2021, 12:28

Пришлось использовать чужой код реализации триангуляции Делоне.
Получилось так: https://drive.google.com/file/d/1mev5QRCU6litWQ9bFLcVlBc0rTq6vWEG/view?usp=sharing
просто соединить точки было мало - они соединяются в созвездия, а сами созвездия уже между собой.
Синтаксис:
Используется csharp
using System.Collections.Generic;
using Delaunator;
//https://github.com/wolktocs/delaunator-csharp

public static class SpaceNetworkCreator
{
        private static int minSectorSize = 10;
        private static int maxSectorSize = 20;
        private static int sectorsAmount = Settings.Galaxy.STARS_AMMOUNT / ((minSectorSize + maxSectorSize) / 2);

        private static List<List<int>> hypersList;
        private static Sector[] sectorsArr;

        public static int[][] Create()
        {
                CreateHypers();
                UnlinkPeriphery();
                LinkPeriphery();
                InitSectors();
                Expansion();
                RemoveInterSectorConnection();
                AddIntersectorConnection();
                return GetResultArray();
        }

        private static void CreateHypers()
        {
                List<double> list = new List<double>();
                for (int i = 0; i < Galaxy.StarSystemsArr.Length; i++)
                {
                        list.Add(Galaxy.StarSystemsArr[i].position.x);
                        list.Add(Galaxy.StarSystemsArr[i].position.y);
                }
                Triangulation tr = new Triangulation(list);

                hypersList = new List<List<int>>();
                for (int i = 0; i < Galaxy.StarSystemsArr.Length; i++)
                {
                        hypersList.Add(new List<int>());
                }

                for (int i = 0; i < tr.triangles.Count - 3; i += 3)
                {
                        AddConnection(tr.triangles[i], tr.triangles[i + 1]);
                        AddConnection(tr.triangles[i + 1], tr.triangles[i + 2]);
                        AddConnection(tr.triangles[i + 2], tr.triangles[i]);
                }
        }

        private static void UnlinkPeriphery()
        {
                RemoveAllConnections(0);

                for (int i = 1; i < Galaxy.StarSystemsArr.Length; i++)
                {
                        if (Galaxy.Distances[0][i].distance > Settings.Galaxy.GALAXY_RADIUS)
                                RemoveAllConnections(i);
                }
        }

        private static void LinkPeriphery()
        {
                for (int i = 0; i < Galaxy.DistancesSortedNear[0].Length; i++)
                {
                        if (Galaxy.DistancesSortedNear[0][i].distance < Settings.Galaxy.GALAXY_RADIUS) continue;
                        AddOnceForClear(Galaxy.DistancesSortedNear[0][i].index);
                }
        }

        private static void AddOnceForClear(int id)
        {
                for (int i = 1; i < Galaxy.DistancesSortedNear[id].Length; i++)
                {
                        int idNeib = Galaxy.DistancesSortedNear[id][i].index;
                        if (hypersList[idNeib].Count > 0)
                        {
                                AddConnection(id, idNeib);
                                break;
                        }
                        if (Galaxy.Distances[0][idNeib].distance <= Settings.Galaxy.GALAXY_RADIUS)
                        {
                                AddConnection(id, Galaxy.DistancesSortedNear[id][i].index);
                                break;
                        }
                }
        }

        private static void InitSectors()
        {
                sectorsArr = new Sector[sectorsAmount];
                for (int i = 1; i < sectorsArr.Length; i++)
                {
                        Sector sector = new Sector
                        {
                                id = i,
                                isOpen = true,
                                members = new List<MemberSector>()
                        };
                        MemberSector member = new MemberSector
                        {
                                idSector = i,
                                idSystem = i,
                                isOpen = true
                        };
                        Galaxy.StarSystemsArr[member.idSystem].idSector = member.idSector;
                        sector.members.Add(member);
                        sectorsArr[i] = sector;
                }
        }

        private static void Expansion()
        {
                bool key = true;
                while (key)
                {
                        key = false;
                        for (int i = 1; i < sectorsArr.Length; i++)
                        {
                                if (!sectorsArr[i].isOpen) continue;
                                ExpansionSector(sectorsArr[i]);
                                key = true;
                        }
                }
        }

        private static void ExpansionSector(Sector sector)
        {
                for (int i = 0; i < sector.members.Count; i++)
                {
                        if (!sector.members[i].isOpen) continue;
                        int idNewMember = GetNewSystem(sector.members[i]);
                        if (idNewMember == 0)
                        {
                                sector.members[i].isOpen = false;
                                continue;
                        }
                        sector.members.Add(CreateNewMember(idNewMember, sector.id));
                        return;
                }
                sector.isOpen = false;
        }

        private static int GetNewSystem(MemberSector member)
        {
                for (int i = 0; i < hypersList[member.idSystem].Count; i++)
                {
                        int neibourId = hypersList[member.idSystem][i];
                        if (Galaxy.StarSystemsArr[neibourId].idSector == 0)
                        {
                                return neibourId;
                        }
                }
                return 0;
        }      

        private static MemberSector CreateNewMember(int idSystem, int idSector)
        {
                Galaxy.StarSystemsArr[idSystem].idSector = idSector;
                MemberSector member = new MemberSector
                {
                        idSector = idSector,
                        idSystem = idSystem,
                        isOpen = true
                };
                return member;
        }

        private static void AddConnection(int idA, int idB)
        {
                if (!hypersList[idA].Contains(idB))
                        hypersList[idA].Add(idB);
                if (!hypersList[idB].Contains(idA))
                        hypersList[idB].Add(idA);
        }

        private static void AddIntersectorConnection()
        {
                for (int i = 1; i < sectorsArr.Length; i++)
                {
                        for (int k = 0; k < sectorsArr[i].bestNeibourSectorMembersList.Count; k++)
                        {
                                AddConnection(
                                        sectorsArr[i].bestNeibourSectorMembersList[k].idOwnSys,
                                        sectorsArr[i].bestNeibourSectorMembersList[k].idExternSys
                                        );
                        }                      
                }
        }

        private static void RemoveConnection(int idA, int idB)
        {
                if (hypersList[idA].FindAll(x => x == idB).Count > 1) throw new System.Exception();
                if (hypersList[idB].FindAll(x => x == idA).Count > 1) throw new System.Exception();
                if (!hypersList[idA].Remove(idB)) throw new System.Exception();
                if (!hypersList[idB].Remove(idA)) throw new System.Exception();
                if (hypersList[idA].FindAll(x => x == idB).Count > 0) throw new System.Exception();
                if (hypersList[idB].FindAll(x => x == idA).Count > 0) throw new System.Exception();
        }

        private static void RemoveAllConnections(int id)
        {
                for (int i = 0; i < hypersList[id].Count; i++)
                {
                        var idNear = hypersList[id][i];
                        if (!hypersList[idNear].Remove(id))
                        {
                                throw new System.Exception();
                        }
                }
                hypersList[id].Clear();
        }

        private static void RemoveInterSectorConnection()
        {
                for (int i = 0; i < hypersList.Count; i++)
                {
                        for (int k = hypersList[i].Count - 1; k >= 0; k--)
                        {
                                int targetId = hypersList[i][k];
                                if (Galaxy.StarSystemsArr[i].idSector != Galaxy.StarSystemsArr[targetId].idSector)
                                {
                                        SaveBestConnection(i, targetId);
                                        RemoveConnection(i, targetId);
                                }
                        }
                        if (Galaxy.StarSystemsArr[i].idSector == 0) RemoveAllConnections(i);
                }
        }

        private static void SaveBestConnection(int idSysA, int idSysB)
        {
                Sector secA = sectorsArr[Galaxy.StarSystemsArr[idSysA].idSector];
                Sector secB = sectorsArr[Galaxy.StarSystemsArr[idSysB].idSector];

                secA.AddBest(idSysA, idSysB);
                secB.AddBest(idSysB, idSysA);
        }

        private static int[][] GetResultArray()
        {
                int[][] result = new int[hypersList.Count][];
                for (int i = 0; i < hypersList.Count; i++)
                {
                        result[i] = hypersList[i].ToArray();
                }
                return result;
        }

        private class Sector
        {
                public int id;
                public List<MemberSector> members;
                public bool isOpen;
                public List<BestNeibourSectorMember> bestNeibourSectorMembersList = new List<BestNeibourSectorMember>();

                public void AddBest(int idOwn, int idExtern)
                {
                        int oldIndex = bestNeibourSectorMembersList.FindIndex(x => x.idNeibourSector == Galaxy.StarSystemsArr[idExtern].idSector);
                        var addingBest = new BestNeibourSectorMember()
                        {
                                idNeibourSector = Galaxy.StarSystemsArr[idExtern].idSector,
                                idOwnSys = idOwn,
                                idExternSys = idExtern,
                                distance = Galaxy.Distances[idOwn][idExtern].distance
                        };
                        if (oldIndex < 0)
                        {
                                bestNeibourSectorMembersList.Add(addingBest);
                                return;
                        }
                        if (bestNeibourSectorMembersList[oldIndex].distance > Galaxy.Distances[idOwn][idExtern].distance)
                        {
                                bestNeibourSectorMembersList[oldIndex] = addingBest;
                        }
                }
        }
        private class MemberSector
        {
                public int idSystem;
                public int idSector;
                public bool isOpen;
        }

        private struct BestNeibourSectorMember
        {
                public int idNeibourSector;
                public int idOwnSys;
                public int idExternSys;
                public float distance;
        }
}

 

Лицензия чужого кода (MIT). Где мне в проекте ее правильно указать?
Аватара пользователя
z-red
UNец
 
Сообщения: 30
Зарегистрирован: 02 янв 2018, 18:48
Откуда: Zaporizhzhya


Вернуться в Почемучка

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 25