Ejemplo n.º 1
0
 internal async Task Initialize(IEnumerable <MyVector2> areaSizings, MyColor[][][] sprites, IAreaEnumerator enumerator)
 {
     var sizingsList = areaSizings.ToList();
     await Task.Run(() =>
     {
         Parallel.For(0, sizingsList.Count, i =>
         {
             var sizing        = sizingsList[i];
             var newSizingDict = new ConcurrentDictionary <int, List <int> >();
             _mapOfEmptiness.AddOrUpdate(sizing, newSizingDict, (_, __) => newSizingDict);
             Parallel.For(0, sprites.Length, j =>
             {
                 var newSpriteDict = new List <int>();
                 newSizingDict.AddOrUpdate(j, newSpriteDict, (_, __) => newSpriteDict);
                 enumerator.EnumerateThroughSprite(sizing, j, (sprite, spriteIndex, x, y) =>
                 {
                     var area = MyArea.CreateFromSprite(sprite, spriteIndex, x, y, sizing);
                     if (area.OpaquePixelsCount == 0)
                     {
                         newSpriteDict.Add(x + y *_yMultiplier);
                     }
                 });
             });
         });
     });
 }
    private static void getUniqueAreas(MyVector2 areaResolution, MyColor[][] sprite, int spriteIndex, ConcurrentDictionary <int, MyArea> areas, ConcurrentDictionary <int, long> areaDirtyScores, bool[][] mapOfEmptiness)
    {
        var areaSquare = areaResolution.X * areaResolution.Y;

        for (int x = 0; x < sprite.Length - areaResolution.X; x++)
        {
            for (int y = 0; y < sprite[x].Length - areaResolution.Y; y++)
            {
                ProcessedAreas++;
                if (mapOfEmptiness[x][y])
                {
                    continue;
                }
                var area = MyArea.CreateFromSprite(sprite, spriteIndex, x, y, areaResolution);
                var hash = area.GetHashCode();
                if (areas.TryAdd(hash, area))
                {
                    UniqueAreas++;
                }

                var dirtyScore = (int)(Mathf.Pow(area.OpaquePixelsCount, 3f) / areaSquare);
                areaDirtyScores.AddOrUpdate(hash, dirtyScore, (key, existingValue) => existingValue + dirtyScore);
            }
        }
        CurrentOp++;
    }
Ejemplo n.º 3
0
        private void ChaoticPointGeneration(MyArea area, List <MyNode> result, int count, double h = -1)
        {
            MyRectangle rect      = MyRectangle.GetAreaRectangle(area);
            int         maxNodes  = count;
            Random      generator = new Random((int)DateTime.Now.Ticks);

            for (int i = 0; result.Count < maxNodes; i++)
            {
                int triesCount = (int)nudTriesCount.Value;
                do
                {
                    double x = rect.minX + generator.NextDouble() * rect.Width;
                    double y = rect.minY + generator.NextDouble() * rect.Height;
                    MyNode p = new MyNode(x, y);
                    if (PointFits(area, result, p, h))
                    {
                        p.Id = ++nodesCount;
                        result.Add(p);
                        break;
                    }
                } while (--triesCount > 0);
                if (triesCount == 0)
                {
                    break;
                }
            }
        }
Ejemplo n.º 4
0
        public void InitializeGameBoardWithCharacters(int gameLevel)
        {
            int d6 = random.Next(1, 7);

            MyArea.SetInvisible(MonsterList);
            MonsterList.Clear();
            MyArea.ResetPositionToZero(MyHero);
            for (int i = 0; i < 3; i++)
            {
                int randomNumber = random.Next(MyArea.FreeTiles.Count);
                MonsterList.Add(new Skeleton(gameLevel, MyArea.FreeTiles[randomNumber], random.Next(1, 7)));
                if (i == 0)
                {
                    ((Skeleton)MonsterList[i]).HasTheKey = true;
                }
                MyArea.DrawCharacter(MonsterList[i]);
            }
            int randomNumber2 = random.Next(MyArea.FreeTiles.Count);
            var boss          = new Boss(gameLevel, MyArea.FreeTiles[randomNumber2], d6);

            MonsterList.Add(boss);
            MyArea.DrawCharacter(boss);
            MyTextBlock.Text = "Hero (Level " + MyHero.Level + ") HP: " + MyHero.CurrentHP + "/" + MyHero.MaxHP + " | DP: "
                               + MyHero.DefendPoint + " | SP: " + MyHero.StrikePoint;
        }
Ejemplo n.º 5
0
        static void Main(string[] args)
        {
            /*
             * delegate는 또한 클래스의 필드나 속성에 사용될 수 있다. 일종의 함수 포인터를 필드나 속성에 저장 하는 것과 비슷한 맥락이다.
             * 메서드 파라미터로 전달하던, 필드로 저장하던 클래스 객체의 입장에서는 전달된 delegate를 필요에 따라 자신의 클래스 내에서 사용하면 된다.
             *
             * 아래 예는 delegate 필드(MyClick)를 정의한 후, 클래스 내부 함수(MyAreaClicked)에서 delegate 필드가 NULL이 아니면,
             * 해당 delegate를 실행하는( MyClick(this); ) 코드를 보여준다. delegate 실행은 메서드를 호출하는 것과 같은데,
             * 델리게이트 필드 자신이 마치 메서드명인 것처럼 사용하면 된다.
             */

            /*
             * C# delegate는 여러 개의 메서드들을 할당하는 것이 가능하다. C# 연산자 += 을 사용하면 메서드를 계속 delegate 에 추가하게 되는데,
             * 내부적으로는 .NET MulticastDelegate 클래스에서 이 메서드들의 리스트(이를 InvocationList 라고 한다)를 관리하게 된다.
             *
             * 복수개의 메서드들이 한 delegate에 할당되면, 이 delegate가 실행될 때, InvocationList로부터 순서대로 메서드를 하나씩 가져와 실행한다.
             * 아래 예제는 복수 개의 메서드를 한 delegate에 계속 추가하는 예이다.
             */
            area = new MyArea();

            //복수개의 메서드를 delegate에 할당
            area.MyClick += Area_Click;
            area.MyClick += AfterClick;

            area.ShowDialog();
        }
Ejemplo n.º 6
0
    // Update is called once per frame
    new void Update()
    {
        Duration += Time.deltaTime;
        //Debug.Log(this.NAmbulances);
        if (this.NAmbulances == 0)
        {
            if (NPeopleInvolved < 1)
            {
                //notify area + central
                //Debug.Log(successRate);

                //Destroy(this.gameObject);
            }
            else
            {
                IncreaseSeverity();

                this.NAmbulances = -1;
                MyArea.ReOpenEmergency(this);
            }
        }

        else
        {
            if (this.NPeopleInvolved >= 1)
            {
                CheckIfDead();
            }

            IncreaseSeverity();
        }
    }
Ejemplo n.º 7
0
    // Update is called once per frame
    new void Update()
    {
        Duration += Time.deltaTime;
        if (this.DevastationLife <= 0 && NFiretrucks == 0)
        {
            //Destroy(this.gameObject);
        }
        else
        {
            Regain           = Math.Min(regainEnergyPercentage * DevastationLife, MaxRegain);
            DevastationLife += Regain;

            IncreaseSeverity();

            var p = UnityEngine.Random.Range(0f, 1f);
            if (p < 0.5)
            {
                AffectedArea += regainEnergyPercentage * AffectedArea;
            }

            if (this.NFiretrucks == 0)
            {
                this.NFiretrucks = -1;
                MyArea.ReOpenEmergency(this);
            }
        }
    }
Ejemplo n.º 8
0
    /// <returns>(Overall areas, Unique areas)</returns>
    private (int total, int unique) getUniqueAreas(MyVector2 areaSizing, int spriteIndex, ConcurrentDictionary <string, MyArea> areas, IAreaEnumerator areaEnumerator, ProgressReport progressReport)
    {
        var areasTotal  = 0;
        var areasUnique = 0;

        areaEnumerator.EnumerateThroughSprite(areaSizing, spriteIndex, (sprite, index, x, y) =>
        {
            if (!_mapOfEmptiness.Contains(areaSizing, index, x, y))
            {
                var area = MyArea.CreateFromSprite(sprite, spriteIndex, x, y, areaSizing);
                var hash = area.UniqueString;
                if (areas.TryAdd(hash, area))
                {
                    areasUnique++;
                }
                area = areas[hash];

                area.Correlations.TryAdd(area.Correlations.Count, new MyAreaCoordinates(index, x, y, areaSizing.X, areaSizing.Y));

                areasTotal++;
            }
        });
        progressReport.OperationsDone++;
        return(areasTotal, areasUnique);
    }
Ejemplo n.º 9
0
        private bool PointFits(MyArea area, List <MyNode> existingNodes, MyNode p, double h = -1)
        {
            double x = p.X, y = p.Y;

            if (h < 0)
            {
                h = (double)nudMinDistance.Value;
            }
            bool inside = Mathematics.ContainsPoint(area.Nodes, x, y) ||
                          area.StraightLines.Find(l => Mathematics.pointOnLine(x, y, l)) != null ||
                          area.Arcs.Find(a => Mathematics.pointFitsArc(p, a, 0.01)) != null;

            if (!inside)
            {
                return(false);
            }

            foreach (MyStraightLine line in area.StraightLines)
            {
                MyPoint cp;
                if (Mathematics.pointOnLine(x, y, line))
                {
                    cp = p;
                }
                else
                {
                    cp = Mathematics.crossPoint(p, line);
                }
                if (Mathematics.FindDist(cp, p) < h)
                {
                    if (existingNodes.TrueForAll(n => Mathematics.FindDist(n, cp).MoreOrEqual(h)))
                    {
                        p.X = cp.X; p.Y = cp.Y;
                        return(true);
                    }
                }
            }

            MyArc arc = area.Arcs.Find(a => Mathematics.pointFitsArc(p, a, h - 0.001));

            if (arc != null)
            {
                MyPoint cp = new MyPoint();
                double  k  = Mathematics.FindDist(arc.EndPoint, arc.CenterPoint) / Mathematics.FindDist(p, arc.CenterPoint);
                cp.X = arc.CenterPoint.X + (p.X - arc.CenterPoint.X) * k;
                cp.Y = arc.CenterPoint.Y + (p.Y - arc.CenterPoint.Y) * k;
                if (existingNodes.TrueForAll(n => Mathematics.FindDist(n, cp).MoreOrEqual(h)))
                {
                    p.X = cp.X; p.Y = cp.Y;
                    return(true);
                }
            }

            if (existingNodes.TrueForAll(n => Mathematics.FindDist(n, p).MoreOrEqual(h)))
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 10
0
        public static void DuplicateNodes(this MyArea area, List <MyVertex> nodes, int nbDuplicate)
        {
            Dictionary <MyVertex, List <MyVertex> > jobs = new Dictionary <MyVertex, List <MyVertex> >();

            var graph = area.LogicCore.Graph;

            foreach (var node in nodes)
            {
                jobs.Add(node, new List <MyVertex>());

                var newnodes = node.Duplicate(nbDuplicate);
                foreach (var newnode in newnodes)
                {
                    area.AddJob(newnode);
                    jobs[node].Add(newnode);
                }
            }


            foreach (var node in nodes)
            {
                int i = 0;
                foreach (var newnode in jobs[node])
                {
                    foreach (var inedge in graph.InEdges(node))
                    {
                        if (!nodes.Contains(inedge.Source))
                        {
                            area.AddLink(inedge.Source, newnode);
                        }
                        else
                        {
                            var source = jobs[inedge.Source][i];
                            area.AddLink(source, newnode);
                        }
                    }

                    foreach (var outedge in graph.OutEdges(node))
                    {
                        if (!nodes.Contains(outedge.Target))
                        {
                            area.AddLink(newnode, outedge.Target);
                        }
                        else
                        {
                            var target = jobs[outedge.Target][i];
                            area.AddLink(newnode, target);
                        }
                    }

                    i++;
                }
            }

            area.GenerateGraph();

            MessageBox.Show("Duplication Finished");
        }
Ejemplo n.º 11
0
 public override void SendStatistics()
 {
     ratio = InitialAffectedArea / AffectedArea;
     //Debug.Log("hi");
     //Debug.Log(InitialAffectedArea);
     //Debug.Log(AffectedArea);
     MyArea.Ratio(AffectedArea / InitialAffectedArea);
     MyArea.AddEmergencyStatistics(this, ratio);
 }
Ejemplo n.º 12
0
        public void Area_10and20_100returned()
        {
            //arrange
            int bottom   = 10;
            int height   = 20;
            int expected = 100;
            //act
            MyArea s      = new MyArea();
            int    actual = s.Area(bottom, height);

            //assert
            Assert.AreEqual(expected, actual);
        }
Ejemplo n.º 13
0
 public override void SendStatistics()
 {
     ratio = InitialAffectedArea / AffectedArea;
     //Debug.Log("hi");
     //Debug.Log(InitialAffectedArea);
     //Debug.Log(AffectedArea);
     MyArea.Ratio(AffectedArea / InitialAffectedArea);
     if (successRate > ratio)
     {
         successRate = ratio;
     }
     //notify area +central
     MyArea.AddEmergencyStatistics(this, successRate);
 }
Ejemplo n.º 14
0
        /*
모든 이벤트(event)는 특수한 형태의 delegate이다. C#의 delegate 기능은 경우에 따라 잘못 사용될 소지가 있다.
예를 들어, 우리가 Button 컨트롤을 개발해 판매한다고 하자. 이 컨트롤은 delegate 필드를 가지고 있고,
버튼 클릭시 InvocationList에 있는 모든 메서드들을 차례로 실행하도록 하였다. 그런데, Button 컨트롤을 구입한 개발자가
한 컴포넌트에서 추가 연산(+=)을 사용 하지 않고 실수로 할당 연산자(=)를 사용하였다고 가정하자.
이 할당연산은 기존에 가입된 모든 메서드 리스트를 지워버리고 마지막에 할당한 메서드 한개만 InvocationList에 넣게 할 것이다.
즉, 누구든 할당 연산자를 한번 사용하면 기존에 가입받은 모든 메서드 호출요구를 삭제하는 문제가 발생한다.

이러한 문제점과 더불어 또다른 중요한 문제점은 delegate는 해당 클래스 내부에서 뿐만 아니라, 외부에서도 누구라도 메서드를 호출하듯 (접근 제한이 없다면)
해당 delegate를 호출할 수 있다는 점이다. 아래 예제는 할당연산자를 사용해서 기존 delegate를 덮어쓰는 예와 delegate를 외부에서 호출하는 예를 보여준다.
*/

        private static void Main(string[] args)
        {
            MyArea area = new MyArea();

            area.MyClick += Area_Click;
            area.MyClick += AfterClick;

            area.Show();

            // 덮어쓰기: MyClick은 Area_Click메서드만 갖는다
            area.MyClick = Area_Click;

            // C# delegate는 클래스 외부에서 호출할 수 있다.
            // C# event는 불가
            area.MyClick(null);
        }
Ejemplo n.º 15
0
        private void ChaoticWithDensityGeneration(MyArea area, List <MyNode> result)
        {
            int         density = (int)nudNodesCount.Value;
            double      h       = (double)nudMinDistance.Value;
            AreaDensity aDens   = settingsForm.areaDensity.Find(a => a.areaId == area.Id);

            if (aDens != null)
            {
                density = aDens.density;
                h       = aDens.h;
            }

            if (density > 8)
            {
                ChaoticPointGeneration(area, result, density, h);
            }
        }
Ejemplo n.º 16
0
    public override bool TreatEmergency(Ambulance a)
    {
        float salvationProb = UnityEngine.Random.Range(0f, 1f);

        if (salvationProb <= this.SalvationProb)
        {
            NPeopleInvolved -= 1;
            savedPeople     += 1;
            successRate      = savedPeople / totalPeople;
            MyArea.Saved();
            return(true);
        }
        NPeopleInvolved -= 1;
        successRate      = savedPeople / totalPeople;
        MyArea.NotSaved();
        return(false);
    }
Ejemplo n.º 17
0
    // Update is called once per frame
    new void Update()

    {
        Duration += Time.deltaTime;

        if (this.NPeopleInvolved <= 0 && this.DevastationLife <= 0 && this.NAmbulances == 0 && this.NFiretrucks == 0)
        {
            //Destroy(this.gameObject);
        }

        else
        {
            if (this.NAmbulances == 0 && this.NPeopleInvolved >= 1)
            {
                this.NAmbulances = -1;
                MyArea.ReOpenMedicalEmergency(this);
            }

            if (this.NFiretrucks == 0 && this.DevastationLife >= 1)
            {
                this.NFiretrucks = -1;
                MyArea.ReOpenDisasterEmergency(this);
            }

            if (this.NPeopleInvolved >= 1)
            {
                CheckIfDead();
            }

            if (this.DevastationLife > 0)
            {
                Regain           = Math.Min(regainEnergyPercentage * DevastationLife, MaxRegain);
                DevastationLife += Regain;

                var p = UnityEngine.Random.Range(0f, 1f);
                if (p < 0.8)
                {
                    AffectedArea += regainEnergyPercentage * AffectedArea;
                }
            }

            IncreaseSeverity();
        }
    }
Ejemplo n.º 18
0
 private void GeneratePoints(MyArea area, List <MyNode> result)
 {
     if (ddlGenerationMethod.SelectedIndex == 0)
     {
         ChaoticPointGeneration(area, result, (int)nudNodesCount.Value + 8);
     }
     else if (ddlGenerationMethod.SelectedIndex == 1)
     {
         ChaoticWithDensityGeneration(area, result);
     }
     else if (ddlGenerationMethod.SelectedIndex == 2)
     {
         RegularPointGeneration(area, result);
     }
     else if (ddlGenerationMethod.SelectedIndex == 3)
     {
         EqualAngleGeneration(area, result);
     }
 }
Ejemplo n.º 19
0
        private void RegularPointGeneration(MyArea area, List <MyNode> result)
        {
            MyRectangle rect = MyRectangle.GetAreaRectangle(area);

            double h = (double)nudMinDistance.Value;

            for (double x = rect.minX; x.LessOrEqual(rect.maxX); x += h)
            {
                for (double y = rect.minY; y.LessOrEqual(rect.maxY); y += h)
                {
                    MyNode p = new MyNode(x, y);
                    if (PointFits(area, result, p))
                    {
                        p.Id = ++nodesCount;
                        result.Add(p);
                    }
                }
            }
        }
Ejemplo n.º 20
0
    public override void CheckIfDead()
    {
        float dyingProb = UnityEngine.Random.Range(0f, 1f);

        if (Severity == E_Severity.Medium)
        {
            if (dyingProb <= 0.001)
            {
                NPeopleInvolved -= 1;
                MyArea.NotSaved();
            }
        }
        else if (Severity == E_Severity.Severe)
        {
            if (dyingProb <= 0.005)
            {
                NPeopleInvolved -= 1;
                MyArea.NotSaved();
            }
        }
    }
Ejemplo n.º 21
0
        private void EqualAngleGeneration(MyArea area, List <MyNode> result)
        {
            MyRectangle rect = MyRectangle.GetAreaRectangle(area);
            double      h    = (double)nudMinDistance.Value;
            bool        odd  = false;
            double      hy   = h * Math.Pow(3.0, 0.5) / 2.0;

            for (double y = rect.minY; y.LessOrEqual(rect.maxY); y += hy)
            {
                for (double x = rect.minX; x.LessOrEqual(rect.maxX); x += h)
                {
                    MyNode p = new MyNode(odd ? x + h / 2 : x, y);
                    if (PointFits(area, result, p))
                    {
                        p.Id = ++nodesCount;
                        result.Add(p);
                    }
                }
                odd = !odd;
            }
        }
Ejemplo n.º 22
0
    private static void getUniqueAreas(MyVector2 areaResolution, int spriteIndex, MyColor[][] sprite, ConcurrentDictionary <string, MyArea> areas, bool[][] mapOfEmptiness, ProgressReport progressReport)
    {
        var areaSquare = areaResolution.X * areaResolution.Y;

        for (int x = 0; x < sprite.Length - areaResolution.X; x++)
        {
            for (int y = 0; y < sprite[x].Length - areaResolution.Y; y++)
            {
                if (mapOfEmptiness[x][y])
                {
                    continue;
                }
                var area = MyArea.CreateFromSprite(sprite, spriteIndex, x, y, areaResolution);
                if (area.Score == 0)
                {
                    continue;
                }
                //var hash = area.GetHashCode();
                var hash = area.UniqueString;
                areas.TryAdd(hash, area);
            }
        }
        progressReport.OperationsDone++;
    }
Ejemplo n.º 23
0
 public bool Battle(Monster monster)
 {
     while (true)
     {
         Strike(MyHero, monster);
         if (monster.CurrentHP <= 0)
         {
             MyArea.SetInvisible(monster);
             MonsterList.Remove(monster);
             MyHero.Level++;
             MyHero.MaxHP       += random.Next(1, 7);
             MyHero.DefendPoint += random.Next(1, 7);
             MyHero.StrikePoint += random.Next(1, 7);
             return(true);
         }
         Strike(monster, MyHero);
         if (MyHero.CurrentHP <= 0)
         {
             MyArea.SetInvisible(MyHero);
             MessageBox.Show("Hero HP: 0 \n Game over");
             return(false);
         }
     }
 }
Ejemplo n.º 24
0
        public static void restoreArraysForOldMethods(this MyFiniteElementModel model, MyGeometryModel geomModel)
        {
            // Восстанавливаем закрепленные узлы
            List <MyNode> boundedNodes = model.Nodes.FindAll(n => n.BoundType != 0);

            // Восстанавливаем закрепленные узлы
            model.NBC.Clear();
            model.NB  = boundedNodes.Count;
            model.NBC = boundedNodes.ConvertAll(n => n.Id);
            model.NBC.Insert(0, 0);

            // Типы закреплений
            model.NFIX.Clear();
            model.NFIX = boundedNodes.ConvertAll(n => n.BoundType);
            model.NFIX.Insert(0, 0);

            // Нагрузки
            model.R.Clear();
            model.Nodes.ConvertAll(n => new double[] { n.ForceX, n.ForceY }).ForEach(pair => model.R.AddRange(pair));
            model.R.Insert(0, 0.0);

            // Сами узлы
            model.NP = model.Nodes.Count;
            model.Nodes.Sort((n, m) => n.Id.CompareTo(m.Id));
            model.CORD.Clear();
            model.Nodes.ConvertAll(n => new double[] { n.X, n.Y }).ForEach(pair => model.CORD.AddRange(pair));
            model.CORD.Insert(0, 0.0);

            // Конечные элементы
            model.NE = model.FiniteElements.Count;
            model.NOP.Clear();
            model.NOP.Insert(0, 0);
            if (model.IMAT.Count == 0)
            {
                model.IMAT = new List <int>();
            }
            for (int i = 0; i <= model.NE; i++)
            {
                model.IMAT.Add(0);
            }
            foreach (MyFiniteElement elem in model.FiniteElements)
            {
                List <MyNode> nodes = new List <MyNode>(elem.Nodes);
                // сортировка узлов КЭ против часовой стрелке //
                double[] angle = new double[3];
                for (int i = 1; i < 3; i++)
                {
                    angle[i] = Math.Atan2(nodes[i].Y - nodes[0].Y, nodes[i].X - nodes[0].X);
                    if (angle[i] < 0)
                    {
                        angle[i] += Math.PI * 2;
                    }
                }
                model.NOP.Add(nodes[0].Id);
                if (angle[1] > angle[2])
                {
                    if (angle[1] - angle[2] < Math.PI)
                    {
                        model.NOP.Add(nodes[2].Id);
                        model.NOP.Add(nodes[1].Id);
                    }
                    else
                    {
                        model.NOP.Add(nodes[1].Id);
                        model.NOP.Add(nodes[2].Id);
                    }
                }
                else
                {
                    if (angle[2] - angle[1] < Math.PI)
                    {
                        model.NOP.Add(nodes[2].Id);
                        model.NOP.Add(nodes[1].Id);
                    }
                    else
                    {
                        model.NOP.Add(nodes[2].Id);
                        model.NOP.Add(nodes[1].Id);
                    }
                }
            }

            // восстанавливаем принадлежность к зонам
            foreach (MyFiniteElement elem in model.FiniteElements)
            {
                elem.DefineArea(geomModel.Areas);
            }

            model.INOUT.Clear();
            model.INOUT.Add(1);
            foreach (MyNode node in model.Nodes)
            {
                int nodeCount = model.INOUT.Count;
                foreach (MyFiniteElement elem in node.finiteElements)
                {
                    MyArea inspectArea = geomModel.Areas.Find(area => area.Id == elem.areaId + 1);
                    double precision   = (model.baseType == MyFiniteElementModel.GridType.Delauney || model.type == MyFiniteElementModel.GridType.FrontalMethod) ? 0.01 : -1;
                    if (inspectArea.StraightLines.Find(line => Mathematics.pointOnLine(node, line) && line.Areas.Count == 1) != null)
                    {
                        model.INOUT.Add(1);
                    }
                    else if (inspectArea.Arcs.Find(arc => Mathematics.pointFitsArc(node, arc, precision) && arc.Areas.Count == 1) != null)
                    {
                        model.INOUT.Add(1);
                    }
                    if (model.INOUT.Count != nodeCount)
                    {
                        break;
                    }
                }
                if (nodeCount == model.INOUT.Count)
                {
                    model.INOUT.Add(0);
                }
            }
        }
Ejemplo n.º 25
0
 public override void SendStatistics()
 {
     MyArea.AddEmergencyStatistics(this, successRate);
 }
    private static Chunk[][] goGetEm(MyVector2 area, MyColor[][][] sprites /*, out Texture optimizedSpritesheet*/)
    {
        //optimizedSpritesheet = new Texture2D(1, 1);
        //Debug.Log("goGetEm . ......");
        int pixelsTotal;
        int opaquePixelsTotal;

        countOpaquePixels(sprites, out pixelsTotal, out opaquePixelsTotal);

        UnoptimizedPixelsCount = opaquePixelsTotal;
        //Debug.Log($"pixelsTotal = {pixelsTotal}, opaquePixelsTotal = {opaquePixelsTotal}");

        var areaVariants = getAreaVariants(area);
        //Debug.Log("Area variants:");
        //for (int i = 0; i < areaVariants.Length; i++)
        //    Debug.Log($"    {areaVariants[i].ToString()}");

        //var areas = new Dictionary<int, MyArea>();
        //for (int i = 0; i < areaVariants.Length; i++)
        //{
        //    CurrentVariant++;
        //    CurrentSprite = 0;
        //    for (int j = 0; j < sprites.Length; j++)
        //    {
        //        CurrentSprite++;
        //        getUniqueAreas(areaVariants[i], sprites[j], areas);
        //    }
        //}

        var mapsOfEmptiness = new Dictionary <MyVector2, bool[][][]>();

        for (int i = 0; i < areaVariants.Length; i++)
        {
            var currentAreaVariant    = areaVariants[i];
            var currentMapOfEmptiness = new bool[sprites.Length][][];
            for (int j = 0; j < sprites.Length; j++)
            {
                var sprite = sprites[j];
                var spriteMapOfEmptiness = new bool[sprite.Length - currentAreaVariant.X][];
                for (int x = 0; x < sprite.Length - currentAreaVariant.X; x++)
                {
                    spriteMapOfEmptiness[x] = new bool[sprite[x].Length - currentAreaVariant.Y];
                    for (int y = 0; y < sprite[x].Length - currentAreaVariant.Y; y++)
                    {
                        spriteMapOfEmptiness[x][y] = !MyArea.ContainsOpaquePixels(sprite, x, y, currentAreaVariant);
                    }
                }
                currentMapOfEmptiness[j] = spriteMapOfEmptiness;
            }
            mapsOfEmptiness.Add(currentAreaVariant, currentMapOfEmptiness);
        }

        var map = new Dictionary <MyArea, List <(int, int, int)> >();

        var sw = new Stopwatch();

        while (UnoptimizedPixelsCount > 0)
        {
            sw.Reset();
            sw.Start();
            ProcessedAreas = 0;
            UniqueAreas    = 0;

            var areas           = new ConcurrentDictionary <int, MyArea>(); //Тут мы храним все уникальные области по их хешам
            var areaDirtyScores = new ConcurrentDictionary <int, long>();   //А тут - их счет по их хешам
            //Dirty - потому что мы не удаляем пиксели по-настоящему, так что счет может быть выше чем на самом деле из-за повторов.
            //Так что это рассчет грубый и неточный, но пойдет для первичного отсева.

            //Сейчас мы идем заполнять эти два словаря, и это можно делать параллельно - слава TPL
            var overallOpsCount = areaVariants.Length * sprites.Length;

            CurrentOpsTotal = overallOpsCount;
            CurrentOp       = 0;

            try
            {
                Parallel.For(0, overallOpsCount, (int index, ParallelLoopState state) =>
                {
                    if (state.IsExceptional)
                    {
                        Debug.Log("Exception!");
                    }
                    var areaVariantIndex = Mathf.FloorToInt(index / sprites.Length);
                    var spriteIndex      = index - areaVariantIndex * sprites.Length;
                    var targetArea       = areaVariants[areaVariantIndex];
                    var mapOfEmptinessForAreaAndSprite = mapsOfEmptiness[targetArea][spriteIndex];
                    getUniqueAreas(targetArea, sprites[spriteIndex], spriteIndex, areas, areaDirtyScores, mapOfEmptinessForAreaAndSprite);
                });
            }
            catch (AggregateException ae)
            {
                Debug.Log("catch");
                ae.Handle((inner) =>
                {
                    Debug.Log(inner.Message);
                    return(true);
                });
            }

            Debug.Log($"unique areas count = {areas.Count}");

            /*
             * Итак, что мы тут делаем. Мы имеем грязный словарь, с примерными значениями полезности. Что мы должны сделать в идеальном мире -
             * - пройтись с каждым из нескольких миллионов областей по потенциально многомиллионопиксельному спрайту и проанализировать каждый в плане
             * полезности. И сделать это надо для каждого шага. Ясно, что сложность тут нереальная. Поэтому, я думаю, надо иметь некий буфер, выборку
             * возможных кандитатов, например, 100. Берем 100 самых достойных областей (первые 100 из грязного словаря), проходимся с ними по спрайтам,
             * и смотрим какой из них удаляет больше всего пикселей. Его и забираем и действительно удаляем все пиксели с ним. У нас осталось на 1 область
             * грязного списка меньше. Повторять покуда остались пиксели.
             */

            var orderedDirtyKvpArray = areaDirtyScores.ToArray().OrderByDescending(kvp => kvp.Value).ToArray();
            Debug.Log($"The winner is {orderedDirtyKvpArray[0].Key} with highest score of {orderedDirtyKvpArray[0].Value}!");
            for (int i = 0; i < _bestOfTheDirtyBufferSize; i++)
            {
                Debug.Log($"    {i + 1}. {orderedDirtyKvpArray[i].Key}. Score: {orderedDirtyKvpArray[i].Value}");
            }


            //var imageCopy = CopyArrayOfColors(sprites);
            //var same = true;
            //for (int i = 0; i < imageCopy.Length; i++)
            //{
            //    for (int j = 0; j < imageCopy[i].Length; j++)
            //    {
            //        for (int m = 0; m < imageCopy[i][j].Length; m++)
            //        {
            //            if (imageCopy[i][j][m].GetHashCode() != sprites[i][j][m].GetHashCode())
            //                same = false;
            //        }
            //    }
            //}

            //if (same)
            //    Debug.Log($"Clone of image is same"); //Same!
            //else
            //    Debug.Log($"Clone of image isn't the same");

            /*
             * Ок, дальше мы идем делать чистую проверку самых вероятных победителей - с пробным удалением пикселей.
             */

            CurrentOpsTotal = _bestOfTheDirtyBufferSize;
            CurrentOp       = 0;

            var partialCleanScore = new ConcurrentDictionary <int, long>(); //Это и есть словарь с чистым счетом - при пробном удалении пикселей

            Parallel.For(0, _bestOfTheDirtyBufferSize, index =>
            {
                var imageCopy      = CopyArrayOf(sprites);
                var candidateHash  = orderedDirtyKvpArray[index].Key;
                var candidate      = areas[candidateHash];
                var areaDimensions = candidate.Dimensions;

                var emptinessMapCopy = CopyArrayOf(mapsOfEmptiness[areaDimensions]);

                var deletedOpaquePixels = 0;
                for (int i = 0; i < imageCopy.Length; i++)
                {
                    var spriteCopy = imageCopy[i];
                    var spritesMapOfEmptinessCopy = emptinessMapCopy[i];
                    for (int x = 0; x < spriteCopy.Length - areaDimensions.X; x++)
                    {
                        for (int y = 0; y < spriteCopy[x].Length - areaDimensions.Y; y++)
                        {
                            if (spritesMapOfEmptinessCopy[x][y])
                            {
                                continue;
                            }
                            var comparedArea = MyArea.CreateFromSprite(spriteCopy, i, x, y, areaDimensions);
                            if (comparedArea.GetHashCode() == candidate.GetHashCode())
                            {
                                MyArea.EraseAreaFromSprite(spriteCopy, x, y, areaDimensions);
                                deletedOpaquePixels += comparedArea.OpaquePixelsCount;
                                MyArea.EraseUpdateEmptinessMap(spriteCopy, spritesMapOfEmptinessCopy, x, y, areaDimensions, areaDimensions); //т.к. мы сейчас смотрим только на эффективность текущей области в плане удаления пикселей, нам не нужно оптимизировать другие области
                            }
                        }
                    }
                }

                var cleanScore = ((long)(Mathf.Pow(candidate.OpaquePixelsCount, 2f) / candidate.Dimensions.Square)) * deletedOpaquePixels;
                partialCleanScore.AddOrUpdate(candidateHash, cleanScore, (key, _) => cleanScore);
                CurrentOp++;
            });

            var orderedCleanKvpArray = partialCleanScore.ToArray().OrderByDescending(kvp => kvp.Value).ToArray();

            Debug.Log($"");
            Debug.Log($"It's time for clean results everybody!");
            Debug.Log($"The winner is {orderedCleanKvpArray[0].Key} with highest score of {orderedCleanKvpArray[0].Value}!");
            for (int i = 0; i < orderedCleanKvpArray.Length; i++)
            {
                Debug.Log($"    {i + 1}. {orderedCleanKvpArray[i].Key}. Score: {orderedCleanKvpArray[i].Value}");
            }

            /*
             * Ок, теперь мы имеем чистый список и победителя - забираем его из areas, удаляем его пиксели с картинки, наносим на карту его id,
             * и после этого мы должны пойти по новой - пересчитать areaDirtyScores, взять buffer лучших, посчитать Clean, взять лучшего, и т.д..
             * Но вообще я могу сделать по-другому. Взять старый areaDirtyScores и пересчитать только те области, которые были затронуты предыдущим
             * удалением. Для этого мне надо иметь карту размером с картинку, где каждый пиксель будет содержать инфу о том, частью какого хеша он является.
             * Поэтому при удалении пикселей победителя чистого списка с картинки, мы сохрянем все уникальные хеши удаленных пикселей, и потом пересчитываем
             * области с соответствующими хешами - может оказаться, что эти области вообще больше не существуют и надо их тогда удалить из грязного списка.
             * Если же они существуют - обновляем их рейтинг в грязном списке. А затем уже можно пойти по новой итерации цикла.
             *
             * С другой стороны, карта размером с картинку - это потенциально много миллионов List'ов, каждый из которых будет содержать потенциально сотни
             * значений. В ххудшем случае, если у нас 4к текстура и какая-нибудь большая в пределах разумного область, допустим, 8х8, то у нас 16 миллионов
             * листов, и, несколько сотен хешей, размером, допустим 40 байт. В общем, не знаю, может я неправильно рассчитал, но у меня получилось, что мне
             * понадобятся несколько сотен гигабайт оперативки для всего это счатья. Так что наверное, лучше все же смещать баланс в сторону вычислительной
             * сложности.
             *
             * Нет, все-таки мне нужно как-то это дело оптимизировать. Так оставлять нельзя, очень долго будет обрабатываться. Я думаю, нужно сделать карту,
             * содержащую информацию о пустых областях, чтобы можно было скипнуть проходы цикла.
             */

            var winnerAreaHash         = orderedCleanKvpArray[0].Key;
            var winnerArea             = areas[winnerAreaHash];
            var winnerAreaDimensions   = winnerArea.Dimensions;
            var winnerAreaEmptinessMap = mapsOfEmptiness[winnerAreaDimensions];

            var mappedAreas = new List <(int, int, int)>();

            var opaquePixelsDeletedByWinner = 0;
            for (int i = 0; i < sprites.Length; i++)
            {
                var sprite = sprites[i];
                var spritesMapOfEmptiness = winnerAreaEmptinessMap[i];
                for (int x = 0; x < sprite.Length - winnerAreaDimensions.X; x++)
                {
                    for (int y = 0; y < sprite[x].Length - winnerAreaDimensions.Y; y++)
                    {
                        if (spritesMapOfEmptiness[x][y])
                        {
                            continue;
                        }
                        var comparedArea = MyArea.CreateFromSprite(sprite, i, x, y, winnerAreaDimensions);
                        if (comparedArea.GetHashCode() == winnerArea.GetHashCode())
                        {
                            MyArea.EraseAreaFromSprite(sprite, x, y, winnerAreaDimensions);
                            opaquePixelsDeletedByWinner += comparedArea.OpaquePixelsCount;

                            mappedAreas.Add((i, x, y));

                            /*
                             * Сообщаем всем мапам пустот, что в данной конкретной области на данном конкретном спрайте прибавилось пустоты, поэтому их
                             * надо обновить. Это действует на все варианты областей и только на 1 конкретный спрайт.
                             */

                            for (int v = 0; v < areaVariants.Length; v++)
                            {
                                var currentAreaVariant = areaVariants[v];
                                MyArea.EraseUpdateEmptinessMap(sprite, spritesMapOfEmptiness, x, y, winnerAreaDimensions, currentAreaVariant);
                            }
                        }
                    }
                }
            }

            map.Add(winnerArea, mappedAreas);

            UnoptimizedPixelsCount -= opaquePixelsDeletedByWinner;
            sw.Stop();
            LastPassTime = sw.ElapsedMilliseconds;
        }

        /*
         * Ок, все равно занимает кучу времени. И еще почему-то кол-во уникальных областей неуклонно растет, хотя по логике, удаляя пиксели, мы должны
         * получать меньше уникальных областей. Хотя нет. Удаляя пиксели мы получаем много вырезанных пространств, много пробелов в картинке, и эти
         * пробелы по идее должны добавлять уникальных вариантов составов пикселей.
         *
         * Ок, так как мне уменьшить время выполнения? Я думаю, надо добавлять эвристик. Например, мы можем предположить, что скорее всего удаление
         * какой-либо области из карты после одного прохода цикла не изменило ситуацию настолько кардинально, чтобы перелопатить все сверху донизу.
         * Т.е. скорее всего все изменилось не настолько чтобы, например, каждый из первых 10_000 областей из лидеров грязного списка перестал быть в
         * первых 10_000 после удаления. На самом деле, удаление потенциально затрагивает не так уж много областей. В области 4х4 может быть 16 1х1
         * уникальных областей, 9 2х2 уникальных областей, и 4 3х3 уникальных областей, т.е. всего, кроме собственно самой 4х4 области победителя, могут
         * быть потенциально затронуты лишь 29 областей. Нет, это те, что могут быть полностью удалены, а затронуты -  15+16*(кол-во вариантов областей - 1),
         * то есть, для 4х4 - это ((16 * 10) - 1) областей, т.е. 159 затронутых областей. Нет, забыл учесть те, что слева и сверху, их должно быть еще порядка
         * 16 * 3 * 10. Т.е., если считать приблизительно, для 4х4 и 10 вариантов областей кол-во затронутых областей не должно быть больше 4х4х4х10. Скорее
         * всего их будет где-то в районе 3х4х4х10 * 0.5 + 4х4х10, или 2.5х4х4х10 или 400. Т.е. в принципе, если предположить худший сценарий, что все эти
         * 400 областей были в 400 первых в грязном списке, а после удаления они все ушли из этих 400 первых, то нам надо пересчитать рейтинги только для
         * первых 400 областей и переупорядочить список. Конечно, мы скорее всего не пересчитаем все реально затронутые области, но если их нету в первых
         * 400 областях, значит эти затронутые области были довольно незначитальными по своему вкладу в картинку и не стали значительнее после удаления.
         * Т.е. да, они останутся с неправильным рейтингом за пределами 400 первых, но если вдруг на каком-то этапе они попадут в эти 400 первых мы
         * пересчитаем их рейтинг. Т.е. по сути мы как бы говорим "да, после удаления рейтинг многих областей поменялся, но скорее всего после удаления
         * новый чистый лидер будет среди первых (400 + buffer) грязных областей по версии до удаления".
         *
         * Но, тут еще есть один момент - новые пустоты могут насоздавать новых областей, которые в принципе могут посоперничать с областями из лидеров. Т.е.
         * в принципе после удаления мы можем дополнительно обновлять список уникальных областей теми, что были обнаружены в прилежащих к удаленным областям,
         * считать для них рейтинги и потом включить их в общий список после пересчета первых 400 областей и перед переупорядочиванием.
         *
         * Так, отмена, пиксели за пределами удаленных областей могут быть любыми, так что тут не 2.5х4х4х10 а гораздо больше областей может быть затронуто.
         * Тогда можно такую эвристику придумать. Если мы удалили процент A картинки, то затронутых пикселей областей потенциально будет процент B (где-то
         * в районе Aх9). Т.е. в худшем случае верхний процент B областей грязного рейтинга ушел куда-то на дно. Т.е. достаточно перепроверить эти B
         * процентов областей сверху грязного рейтинга и тогда мы сможем безопасно взять оттуда буффер. Конечно, это не меняет тот факт, что надо добавить
         * новообразованных областей из окресностей удаленных.
         *
         * Чтобы понять где окресности удаленных областей, мне нужна карта. Карта будет словарем с ключами в виде областей и значениями в виде координат
         * вида (индекс спрайта, X, Y). Имея этот словарь и зная последнюю добавленную туда область мы сможем узнать все затронутые ей части картинки и
         * пройтись по всем окресностям, создавая новые области по необходимости. Также эта карта будет полезна вдальнейшем при составлении структур
         * областей для каждого спрайта.
         */

        Working = false;

        throw new NotImplementedException();
        //return new Chunk[0][];
    }
Ejemplo n.º 27
0
        public bool OK(List <MyPoint> formerNodes = null)
        {
            MyPoint point   = null;
            bool    success = false;

            int[]  lineID     = new int[4];
            bool[] lineExists = { false, false, false, false };

            int numOfArcs = 0;

            parent.clearSelection();

            if (number.TextLength == 0 || line1.TextLength == 0 || line2.TextLength == 0 || line3.TextLength == 0 || line4.TextLength == 0)
            {
                errorMessage1.Visible = true;
                return(success);
            }
            if (errorMessage2.Visible)
            {
                return(success);
            }
            lineID[0] = Convert.ToInt32(line1.Text);
            lineID[1] = Convert.ToInt32(line2.Text);
            lineID[2] = Convert.ToInt32(line3.Text);
            lineID[3] = Convert.ToInt32(line4.Text);
            if (lineID.Distinct().ToArray().Length != 4)
            {
                MessageBox.Show("Зона не может содержать повторяющиеся линии!");
                return(success);
            }

            List <MyPoint>        points = new List <MyPoint>();
            List <MyStraightLine> slines = new List <MyStraightLine>();
            List <MyArc>          arcs   = new List <MyArc>();
            List <MyLine>         lines  = new List <MyLine>();

            // ищем линии
            for (int i = 0; i < 4; i++)
            {
                MyLine         currentLine;
                MyStraightLine line = parent.currentFullModel.geometryModel.StraightLines.Find(ln => ln.Id == lineID[i]);
                MyArc          arc  = parent.currentFullModel.geometryModel.Arcs.Find(a => a.Id == lineID[i]);
                if (line == null)
                {
                    currentLine = arc;
                }
                else
                {
                    currentLine = line;
                }
                if (currentLine != null)
                {
                    lineExists[i] = true;
                    bool neighborLineExists = false;
                    // цикл по всем зонам
                    MyArea area;
                    if (line == null)
                    {
                        area = parent.currentFullModel.geometryModel.Areas.Find(a => a.Arcs.IndexOf(arc) != -1);
                    }
                    else
                    {
                        area = parent.currentFullModel.geometryModel.Areas.Find(a => a.StraightLines.IndexOf(line) != -1);
                    }
                    if (area != null)
                    {
                        if (points.IndexOf(currentLine.EndPoint) == -1)
                        {
                            points.Add(currentLine.EndPoint);
                        }
                        if (points.IndexOf(currentLine.StartPoint) == -1)
                        {
                            points.Add(currentLine.StartPoint);
                        }
                        neighborLineExists = true;
                    }

                    if (!neighborLineExists)
                    {
                        if (points.IndexOf(currentLine.StartPoint) == -1)
                        {
                            points.Add(currentLine.StartPoint);
                        }
                        if (points.IndexOf(currentLine.EndPoint) == -1)
                        {
                            points.Add(currentLine.EndPoint);
                        }
                    }
                    lineExists[i] = true;
                    if (line == null)
                    {
                        arcs.Add(arc);
                        numOfArcs++;
                    }
                    else
                    {
                        slines.Add(line);
                    }
                    lines.Add(currentLine);
                }
            }

            // закончили поиск линий

            if (!lineExists.Contains(false))
            {
                // указанные линии существуют, но надо еще проверить, образуют ли они замкнутую зону
                errorMessage4.Visible   = false;
                errorAreaExists.Visible = false;
                if (points.Count == 4) // условие, определяющее то, что линии образуют замкнутую область
                {
                    errorMessage3.Visible = false;
                    // проверяем число зон, в которым принадлежать линии
                    foreach (MyLine l in lines)
                    {
                        if (l.Areas.Count == 2)
                        {
                            clearLines();
                            errorTwoAreas.Visible = true;
                            return(success);
                        }
                    }

                    // проверяем, нет ли такой зоны уже
                    if (lines.Find(l => l.Areas.Count != 1) == null) //lines[0].Areas.Count == 1 && lines[1].Areas.Count == 1 && lines[2].Areas.Count == 1 && lines[3].Areas.Count == 1)
                    {
                        if (lines.ConvertAll(l => parent.currentFullModel.geometryModel.Areas.Find(ar => ar.Id == l.Areas.First()).Id).Distinct().Count() == 1)
                        {
                            errorAreaExists.Visible = true;
                            clearLines();
                            return(success);
                        }
                    }

                    // определяем первую линию в списке линий
                    int firstLine = 0;
                    for (int i = 0; i < 4; i++)
                    {
                        if (lines[i].Areas.Count == 1)
                        {
                            firstLine = i;
                            break;
                        }
                    }
                    if (firstLine != 0)
                    {
                        MyLine tempLine = lines[0];
                        lines[0]         = lines[firstLine];
                        lines[firstLine] = tempLine;
                    }

                    // определяем вторую линию в списке линий
                    int secondLine = 1;
                    point = lines[0].EndPoint;
                    for (int i = 1; i < 4; i++)
                    {
                        if (point == lines[i].EndPoint || point == lines[i].StartPoint)
                        {
                            secondLine = i;
                            break;
                        }
                    }

                    if (secondLine != 1)
                    {
                        MyLine tempLine = lines[1];
                        lines[1]          = lines[secondLine];
                        lines[secondLine] = tempLine;
                    }

                    // определяем четвертую (последниюю) линию в списке линий. определения третий линии нет, и это не ошибка. она определится автоматом
                    int lastLine = 3;
                    point = lines[0].StartPoint;
                    for (int i = 2; i < 4; i++)
                    {
                        if (point == lines[i].EndPoint || point == lines[i].StartPoint)
                        {
                            lastLine = i;
                            break;
                        }
                    }
                    if (lastLine != 3)
                    {
                        MyLine tempLine = lines[3];
                        lines[3]        = lines[lastLine];
                        lines[lastLine] = tempLine;
                    }

                    points.Clear();
                    int newAreaId;
                    if (!int.TryParse(number.Text, out newAreaId))
                    {
                        errorMessage2.Visible = true;
                        number.Focus();
                        return(success);
                    }

                    if (parent.currentFullModel.geometryModel.Areas.Count > 0)
                    {
                        if (lines.All(l => l.Areas.Count == 0))
                        {
                            MessageBox.Show("Невозможно образовать зону: не прилегает ни к одной из существующих зон");
                            return(success);
                        }
                    }

                    points.Add(lines[0].StartPoint);
                    points.Add(lines[0].EndPoint);
                    if (lines[1].StartPoint != points[1])
                    {
                        points.Add(lines[1].StartPoint);
                    }
                    else
                    {
                        points.Add(lines[1].EndPoint);
                    }

                    if (lines[3].StartPoint != points[0])
                    {
                        points.Add(lines[3].StartPoint);
                    }
                    else
                    {
                        points.Add(lines[3].EndPoint);
                    }

                    double S = Square(points[0], points[1]) + Square(points[1], points[2]) + Square(points[2], points[3]) + Square(points[3], points[0]);

                    if (S > 0.0)
                    {
                        MyPoint tempPoint = points[2];
                        points[2] = points[3];
                        points[3] = tempPoint;

                        tempPoint = points[0];
                        points[0] = points[1];
                        points[1] = tempPoint;

                        MyLine tempLine = lines[1];
                        lines[1] = lines[3];
                        lines[3] = tempLine;
                    }

                    MyPoint[] middlePoints = new MyPoint[4];
                    for (int i = 0; i < 4; i++)
                    {
                        middlePoints[i] = new MyPoint(0, 0, 0);
                    }
                    // если импортируем геометрию, возможно узлы уже двигали
                    // считываем инфу оттуда
                    if (formerNodes != null)
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            MyPoint p1 = points[j];
                            MyPoint p2 = points[j == 3 ? 0 : j + 1];
                            for (int i = 1; i < 8; i += 2)
                            {
                                MyPoint f1 = formerNodes[i - 1];
                                MyPoint f2 = formerNodes[i];
                                MyPoint f3 = formerNodes[i == 7 ? 0 : i + 1];
                                if (Mathematics.sameNode(f1, p1) && Mathematics.sameNode(f3, p2) ||
                                    Mathematics.sameNode(f1, p2) && Mathematics.sameNode(f3, p1))
                                {
                                    middlePoints[j].X = f2.X;
                                    middlePoints[j].Y = f2.Y;
                                }
                            }
                        }
                    }
                    // иначе тыкаем узлы на середины линий. Ручками, конечно, ручками :(
                    else
                    {
                        if (numOfArcs == 0)
                        {
                            middlePoints[0].X = points[0].X + (points[1].X - points[0].X) / 2;
                            middlePoints[0].Y = points[0].Y + (points[1].Y - points[0].Y) / 2;

                            middlePoints[1].X = points[1].X + (points[2].X - points[1].X) / 2;
                            middlePoints[1].Y = points[1].Y + (points[2].Y - points[1].Y) / 2;

                            middlePoints[2].X = points[2].X + (points[3].X - points[2].X) / 2;
                            middlePoints[2].Y = points[2].Y + (points[3].Y - points[2].Y) / 2;

                            middlePoints[3].X = points[3].X + (points[0].X - points[3].X) / 2;
                            middlePoints[3].Y = points[3].Y + (points[0].Y - points[3].Y) / 2;
                        }

                        else
                        {
                            for (int i = 0; i < 4; i++)
                            {
                                int m = i + 1;
                                if (m == 4)
                                {
                                    m = 0;
                                }
                                MyArc tempArc = formAnArc(points[i], points[m]);
                                if (tempArc != null)
                                {
                                    double startAngle  = (180.0 / Math.PI) * ProjectForm.ArcAngle(tempArc, tempArc.StartPoint); // вычисляем углы начальной и конечной точек дуги - меряются они от оси Х против часовой стрелки (в градусах)
                                    double endAngle    = (180.0 / Math.PI) * ProjectForm.ArcAngle(tempArc, tempArc.EndPoint);
                                    double centerAngle = 0;                                                                     // угол от оси Х до точки, делящей дугу по полам

                                    double sweepAngle = 0;                                                                      // угол дуги
                                    if (tempArc.Clockwise && startAngle > endAngle)
                                    {
                                        sweepAngle = (startAngle - endAngle);
                                    }
                                    if (tempArc.Clockwise && startAngle < endAngle)
                                    {
                                        sweepAngle = 360.0 - (endAngle - startAngle);
                                    }
                                    if (!tempArc.Clockwise && startAngle > endAngle)
                                    {
                                        sweepAngle = 360.0 - (startAngle - endAngle);
                                    }
                                    if (!tempArc.Clockwise && startAngle < endAngle)
                                    {
                                        sweepAngle = (endAngle - startAngle);
                                    }

                                    if (sweepAngle > 0.0 && sweepAngle <= 180.0)
                                    {
                                        if (tempArc.Clockwise)
                                        {
                                            centerAngle = startAngle - sweepAngle / 2.0;
                                            double X, Y, R;
                                            R  = Mathematics.FindDist(tempArc.CenterPoint, tempArc.StartPoint);
                                            X  = R * Math.Cos(centerAngle * (Math.PI / 180.0));
                                            Y  = R * Math.Sin(centerAngle * (Math.PI / 180.0));
                                            X += tempArc.CenterPoint.X;
                                            Y += tempArc.CenterPoint.Y;
                                            middlePoints[i].X = X;
                                            middlePoints[i].Y = Y;
                                        }
                                        else
                                        {
                                            centerAngle = startAngle + sweepAngle / 2.0;
                                            double X, Y, R;
                                            R  = Mathematics.FindDist(tempArc.CenterPoint, tempArc.StartPoint);
                                            X  = R * Math.Cos(centerAngle * (Math.PI / 180.0));
                                            Y  = R * Math.Sin(centerAngle * (Math.PI / 180.0));
                                            X += tempArc.CenterPoint.X;
                                            Y += tempArc.CenterPoint.Y;
                                            middlePoints[i].X = X;
                                            middlePoints[i].Y = Y;
                                        }
                                    }
                                    if (sweepAngle < 0.0 && sweepAngle >= -180.0)
                                    {
                                        if (tempArc.Clockwise)
                                        {
                                            centerAngle = startAngle + sweepAngle / 2.0;
                                            double X, Y, R;
                                            R  = Mathematics.FindDist(tempArc.CenterPoint, tempArc.StartPoint);
                                            X  = R * Math.Cos(centerAngle * (Math.PI / 180.0));
                                            Y  = R * Math.Sin(centerAngle * (Math.PI / 180.0));
                                            X += tempArc.CenterPoint.X;
                                            Y += tempArc.CenterPoint.Y;
                                            middlePoints[i].X = X;
                                            middlePoints[i].Y = Y;
                                        }
                                        else
                                        {
                                            centerAngle = startAngle - sweepAngle / 2.0;
                                            double X, Y, R;
                                            R  = Mathematics.FindDist(tempArc.CenterPoint, tempArc.StartPoint);
                                            X  = R * Math.Cos(centerAngle * (Math.PI / 180.0));
                                            Y  = R * Math.Sin(centerAngle * (Math.PI / 180.0));
                                            X += tempArc.CenterPoint.X;
                                            Y += tempArc.CenterPoint.Y;
                                            middlePoints[i].X = X;
                                            middlePoints[i].Y = Y;
                                        }
                                    }
                                }
                                else
                                {
                                    middlePoints[i].X = points[i].X + (points[m].X - points[i].X) / 2;
                                    middlePoints[i].Y = points[i].Y + (points[m].Y - points[i].Y) / 2;
                                }
                            }
                        }
                    }

                    List <MyPoint> Nodes = new List <MyPoint>();

                    for (int i = 0; i < 4; i++) // этим мы обеспечиваем чередование угловых узлов зоны с промежуточными узлами, а также следим за сковозной нумерацией узлов для всех зон пластины
                    {
                        bool pointExists      = false;
                        bool middlePointExits = false;
                        // Находим все зоны, содержащие текущую точку
                        List <MyArea> areas = parent.currentFullModel.geometryModel.Areas.FindAll(a => a.Nodes.Any(n => Mathematics.sameNode(n, points[i]) || Mathematics.sameNode(n, middlePoints[i])));
                        areas.Sort((a, b) => a.Id.CompareTo(b.Id));
                        foreach (MyArea area in areas)    // просматриваем все зоны
                        {
                            int     borderSideNumber = 0; // номер стороны существующей зоны, которая соприкасается с другой зоной. номер человеческий и начинается с 1 а не с 0
                            MyPoint node             = area.Nodes.Find(n => Mathematics.sameNode(n, points[i]) && !Nodes.Contains(n));
                            if (node != null)
                            {
                                Nodes.Add(node); // добавляем в список узлов зоны узел, который уже есть в списке узлов другой зоны
                                pointExists = true;
                            }
                            node = area.Nodes.Find(n => Mathematics.sameNode(n, middlePoints[i]) && !Nodes.Contains(n));
                            if (node != null)
                            {
                                Nodes.Add(node); // добавляем в список узлов зоны узел, который уже есть в списке узлов другой зоны
                                middlePointExits = true;
                                borderSideNumber = (area.Nodes.IndexOf(node) + 1) / 2;

                                parent.currentFullModel.geometryModel.joinTable[area.Id - 1, borderSideNumber - 1] = newAreaId; // т.к. area.Id и borderSideNumber - это индексы, а нумерация индексов с 0, то отнимаем 1
                                parent.currentFullModel.geometryModel.joinTable[newAreaId - 1, i] = area.Id;
                            }
                        }

                        if (!pointExists) // если пройдя по всем зонам, мы не нашли там таких узлов, то создаем новый объект и добавляем его в список зоны
                        {
                            parent.currentFullModel.geometryModel.NumOfAreaNodes++;
                            Nodes.Add(new MyPoint(parent.currentFullModel.geometryModel.NumOfAreaNodes, points[i].X, points[i].Y, MyPoint.PointType.IsAreaNode));
                            foreach (MyPoint p in parent.currentFullModel.geometryModel.Points) // задаем узлу зоны в соответствие точку геометрии и наоборот
                            {
                                if (p.X == points[i].X && p.Y == points[i].Y)
                                {
                                    Nodes[Nodes.Count - 1].PointReference = p;
                                    p.NodeReference = Nodes[Nodes.Count - 1];
                                    break;
                                }
                            }
                        }

                        if (!middlePointExits) // если пройдя по всем зонам, мы не нашли там таких узлов, то создаем новый объект и добавляем его в список зоны
                        {
                            parent.currentFullModel.geometryModel.NumOfAreaNodes++;
                            Nodes.Add(new MyPoint(parent.currentFullModel.geometryModel.NumOfAreaNodes, middlePoints[i].X, middlePoints[i].Y, MyPoint.PointType.IsAreaNode));
                            foreach (MyPoint p in parent.currentFullModel.geometryModel.Points) // задаем узлу зоны в соответствие точку геометрии и наоборот
                            {
                                if (p.X == middlePoints[i].X && p.Y == middlePoints[i].Y)
                                {
                                    Nodes[Nodes.Count - 1].PointReference = p;
                                    p.NodeReference = Nodes[Nodes.Count - 1];
                                    break;
                                }
                            }
                        }
                    }

                    List <MyStraightLine> Segments = new List <MyStraightLine>();
                    for (int i = 0; i < 8; i++) // этим мы создаем отрезки и соединяем ими узлы зоны
                    {
                        int k = i + 1;
                        if (k == 8)
                        {
                            k = 0;
                        }
                        Segments.Add(new MyStraightLine(0, Nodes[i], Nodes[k]));
                    }

                    MyArea newArea = new MyArea(newAreaId, lines, slines, Segments, points, arcs, Nodes);

                    parent.currentFullModel.geometryModel.Areas.Add(newArea);
                    success = true;
                    parent.currentFullModel.geometryModel.NumOfAreas++;

                    foreach (MyLine l in lines)
                    {
                        l.Areas.Add(newAreaId);
                    }

                    number.Text = (parent.currentFullModel.geometryModel.NumOfAreas + 1).ToString();


                    parent.showOnlyAreas.Checked = true;
                }
                else
                {
                    errorMessage3.Visible = true;
                }
            }
            else
            {
                errorMessage4.Visible = true;
            }
            return(success);
        }
Ejemplo n.º 28
0
    /*
     * Ок, мы хотим создать задания - пройтись каждой уникальной областью по всем спрайтам. Чтобы получить уникальные области - возможно тоже придется
     * выкручиваться с помощью шейдеров. Но пока можно и тупо пройтись процессором.
     *
     * Значит, что нам надо сделать - пройтись по всем спрайтам, составить список всех уникальных областей всех размеров во всех спрайтах. Затем надо сложить
     * инжу о них в буффер так, чтобы на каждом пикселе находилась инфа о том, где находится эта область, т.е. x, y, width, height вместо r, g, b, a. Дальше
     * шейдер идут туда забираер эту область и проходится с ней по всем спрайтам, считает счет и пишет его в соответствующую клетку резултирующего буффера.
     */

    Task <ConcurrentDictionary <string, MyArea> > IAreaFetcher.FetchAreas(MyColor[][][] sprites, IEnumerable <MyVector2> areaSizings, IAreaEnumerator areaEnumerator, ProgressReport progressReport)
    {
        return(Task.Run(() =>
        {
            if (!_mapOfEmptinessInitialized)
            {
                Debug.LogError($"map estimation start");
                foreach (var area in areaSizings)
                {
                    var currentMapOfEmptiness = new bool[sprites.Length][][];
                    for (int j = 0; j < sprites.Length; j++)
                    {
                        var sprite = sprites[j];
                        var spriteMapOfEmptiness = new bool[sprite.Length - area.X][];
                        for (int x = 0; x < sprite.Length - area.X; x++)
                        {
                            spriteMapOfEmptiness[x] = new bool[sprite[x].Length - area.Y];
                            for (int y = 0; y < sprite[x].Length - area.Y; y++)
                            {
                                spriteMapOfEmptiness[x][y] = !MyArea.ContainsOpaquePixels(sprite, x, y, area);
                            }
                        }
                        currentMapOfEmptiness[j] = spriteMapOfEmptiness;
                    }
                    _mapOfEmptiness.Add(area, currentMapOfEmptiness);
                }
                _mapOfEmptinessInitialized = true;
                Debug.LogError($"map estimation end");
            }

            var result = new ConcurrentDictionary <string, MyArea>(); //Тут мы храним все уникальные области по их хешам
            var overallOpsCount = areaSizings.Count() * sprites.Length;
            var areasArray = areaSizings.ToArray();

            progressReport.OperationsCount = overallOpsCount;

            try
            {
                Parallel.For(0, overallOpsCount, (int index, ParallelLoopState state) =>
                {
                    if (state.IsExceptional)
                    {
                        Debug.Log("Exception!");
                    }
                    var areaVariantIndex = Mathf.FloorToInt(index / sprites.Length);
                    var spriteIndex = index - areaVariantIndex * sprites.Length;
                    var targetArea = areasArray[areaVariantIndex];
                    var mapOfEmptinessForAreaAndSprite = _mapOfEmptiness[targetArea][spriteIndex];
                    getUniqueAreas(targetArea, spriteIndex, sprites[spriteIndex], result, mapOfEmptinessForAreaAndSprite, progressReport);
                });
            }
            catch (AggregateException ae)
            {
                Debug.Log("catch");
                ae.Handle((inner) =>
                {
                    Debug.Log(inner.Message);
                    return true;
                });
            }

            Debug.Log($"unique areas count = {result.Count}");
            return result;
        }));

        //var algorythmKernel = _computeShader.FindKernel("CSMain");

        //var (groupSizeX, groupSizeY, groupSizeZ) = _computeShader.GetKernelThreadGroupSizes(algorythmKernel);
        //var gpuDataChunks = sprites.PrepareChunksForGpu(groupSizeX, groupSizeY, groupSizeZ);
        //for (int i = 0; i < gpuDataChunks.Length; i++)
        //{
        //    var chunk = gpuDataChunks[i];
        //    _computeShader.SetInt("MultipliedValue", chunk.MultipliedPart);
        //    _computeShader.SetInt("SpriteWidth", chunk.SpriteWidth);
        //    _computeShader.SetInt("SpriteHeight", chunk.SpriteHeight);
        //    _computeShader.SetInt("PreferredAreaWidth", 27);
        //    _computeShader.SetInt("PreferredAreaHeight", 27);
        //    _computeShader.SetBuffer(algorythmKernel, "SpriteBuffer", chunk.SpriteBuffer);
        //    _computeShader.SetBuffer(algorythmKernel, "ResultBuffer", chunk.ResultBuffer);
        //    _computeShader.Dispatch(algorythmKernel, chunk.GroupsCountX, chunk.GroupsCountY, chunk.GroupsCountZ);
        //    chunk.FetchResults();
        //    chunk.Dispose();

        //    var textureBefore = chunk.OriginalSprite.ToTexture2D();
        //    var textureAfter = chunk.Result.ToTexture2D();
        //    File.WriteAllBytes($@"C:\results\{i.ToString()}-before.png", textureBefore.EncodeToPNG());
        //    File.WriteAllBytes($@"C:\results\{i.ToString()}-after.png", textureAfter.EncodeToPNG());
        //    UnityEngine.Object.DestroyImmediate(textureBefore);
        //    UnityEngine.Object.DestroyImmediate(textureAfter);
        //}

        //Здесь что-то делаем с этими данными

        throw new System.NotImplementedException();
    }
Ejemplo n.º 29
0
        private void btnOk_Click(object sender, EventArgs e)
        {
            string modelName = gridName.Text;
            int    elemId    = 0;

            errorBadGridName.Visible = false;

            if (gridName.Text == string.Empty)
            {
                MessageBox.Show("Имя сетки не может быть пустым!");
                return;
            }
            if (parent.currentFullModel.FiniteElementModels.Find(m => m.ModelName == modelName) != null)
            {
                errorBadGridName.Visible = true;
                return;
            }
            if (ddlGenerationMethod.SelectedIndex == -1)
            {
                MessageBox.Show("Не задан метод генерации точек!");
                return;
            }
            this.Hide();
            parent.StartProgress("Построение сетки");
            List <MyFrontSegment> segments = new List <MyFrontSegment>();

            nodesCount = 0;
            MyFiniteElementModel newModel = new MyFiniteElementModel(parent.currentFullModel.IdCandidate, gridName.Text, MyFiniteElementModel.GridType.Normal);

            // если выбрана триангуляция на основе существующих узлов
            if (ddlGenerationMethod.SelectedIndex == 4)
            {
                List <MyFiniteElement> elems = GetTriangulation(currentModel.Nodes);
                newModel.Nodes.AddRange(currentModel.Nodes);
                newModel.Nodes.ForEach(n => n.finiteElements.Clear());
                foreach (MyFiniteElement elem in elems)
                {
                    double cx = elem.Nodes.Sum(s => s.X) / 3;
                    double cy = elem.Nodes.Sum(s => s.Y) / 3;
                    foreach (MyArea area in parent.currentFullModel.geometryModel.Areas)
                    {
                        //if (Mathematics.ContainsPoint(area.Nodes, cx, cy))
                        if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), double.MinValue))
                        {
                            elem.Id     = ++elemId;
                            elem.areaId = area.Id;
                            elem.LinkNodes();
                            newModel.FiniteElements.Add(elem);
                            break;
                        }
                    }
                }
            }
            // любая другая триангуляция
            else
            {
                foreach (MyArea area in parent.currentFullModel.geometryModel.Areas)
                {
                    List <MyNode> result = new List <MyNode>();
                    for (int j = 0; j < 4; j++)
                    {
                        int neighbor = parent.currentFullModel.geometryModel.joinTable[area.Id - 1, j] - 1;
                        if (neighbor != -1)
                        {
                            if (neighbor < area.Id - 1)
                            {
                                List <MyLine> lines = area.Lines.FindAll(l => l.Areas.Contains(area.Id) && l.Areas.Contains(neighbor + 1));
                                foreach (MyLine line in lines)
                                {
                                    if (line is MyStraightLine)
                                    {
                                        result.AddRange(findNodesAtStraightLine(segments[neighbor].Nodes, line as MyStraightLine));
                                    }
                                    else
                                    {
                                        result.AddRange(findNodesAtArc(segments[neighbor].Nodes, line as MyArc));
                                    }
                                }
                            }
                        }
                    }
                    result = result.Distinct().ToList();
                    double h = (double)nudMinDistance.Value;
                    foreach (MyPoint p in area.Nodes)
                    {
                        if (result.Find(n => Mathematics.sameNode(n, p)) == null)
                        {
                            result.Add(new MyNode(p.X, p.Y, ++nodesCount));
                        }
                    }
                    GeneratePoints(area, result);
                    MyFrontSegment seg = new MyFrontSegment(area);
                    seg.Nodes = result;
                    segments.Add(seg);
                    AddNodesFromCommonLine(seg, segments);
                }

                elemId = 0;
                if (ddlGenerationMethod.SelectedIndex == 1)
                {
                    GenerateNodesInDensitySectors(segments);
                }

                foreach (MyFrontSegment seg in segments)
                {
                    foreach (MyNode node in seg.Nodes)
                    {
                        if (!newModel.Nodes.Contains(node))
                        {
                            newModel.Nodes.Add(node);
                        }
                    }
                }
                if (ddlGenerationMethod.SelectedIndex == 1)
                {
                    foreach (MyFiniteElement elem in GetTriangulation(newModel.Nodes))
                    {
                        double cx = elem.Nodes.Sum(s => s.X) / 3;
                        double cy = elem.Nodes.Sum(s => s.Y) / 3;
                        foreach (MyArea area in parent.currentFullModel.geometryModel.Areas)
                        {
                            //if (Mathematics.ContainsPoint(area.Nodes, cx, cy))
                            if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), 0.001))
                            {
                                elem.Id = ++elemId;
                                elem.LinkNodes();
                                newModel.FiniteElements.Add(elem);
                                break;
                            }
                        }
                    }
                }
                else
                {
                    foreach (MyFrontSegment seg in segments)
                    {
                        foreach (MyFiniteElement elem in GetTriangulation(seg.Nodes, seg.CorrespondingArea.Id))
                        {
                            double cx   = elem.Nodes.Sum(s => s.X) / 3;
                            double cy   = elem.Nodes.Sum(s => s.Y) / 3;
                            MyArea area = parent.currentFullModel.geometryModel.Areas[segments.IndexOf(seg)];
                            //if (PointFits(Mathematics.ContainsPoint(area.Nodes, cx, cy))
                            if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), 0.001))
                            {
                                elem.Id = ++elemId;
                                elem.LinkNodes();
                                seg.finiteElems.Add(elem);
                            }
                        }
                        newModel.FiniteElements.AddRange(seg.finiteElems);
                    }
                }
            }
            newModel.baseType = newModel.type = MyFiniteElementModel.GridType.Delauney;
            parent.currentFullModel.densityPoints.Clear();
            parent.EndProgress();
            parent.ModelCreated(newModel);
            Close();
            // создаем для новой КЭ модели id
        }