コード例 #1
0
        public List <Tube3D> RecursiveTracing(Scene3D MyScene, List <Tube3D> Rays, uint Call = 0, uint AddCnt = 0)
        {
            // Список лучей
            List <Tube3D> Result = new List <Tube3D>();

            if (MyScene.ShouldTerminate)
            {
                MyScene.Ready = true;
                return(Result);
            }

            // Если достигли максимального шага вернем пустой список
            if (Call >= MaxTraceSteps || AddCnt >= 5)
            {
                if (AddCnt >= 5)
                {
                    Log("Stack overflow???");
                }
                Rays.ForEach(R => R.SetLenght(InfinityMVisible));
                return(Rays);
            }

            // Для каждого луча из предложенных на данный шаг
            foreach (Tube3D Ray in Rays)
            {
                // Заморочки многопоточности
                if (MyScene.ShouldTerminate)
                {
                    MyScene.Ready = true;
                    return(Result);
                }
                if (Call == 0 && AddCnt == 0)
                {
                    MyScene.RayCnt++;

                    MyScene.ProgressPercent = 100 * MyScene.RayCnt / MyScene.InitialRays.Count;

                    if (MyScene.ProgressPercent != MyScene.ProgressPercentOld)
                    {
                        UpdateProgress(MyScene.Tag, false);
                        MyScene.ProgressPercentOld = MyScene.ProgressPercent;
                    }
                }

                Log("Call = " + Call + " comment = {{" + Ray.Comment + "}}" + " Area = " + Ray.AreaTop().ToString());

                if (Call == 1)
                {
                    Log("stop call 1");
                }

                // Если мощность трубки исчезающе мала, проигнорируем ее, чтобы не плодить лишних
                // или если площадь нулевая
                if (Ray.Power < MinimumPower || Ray.AreaTopC < MinAreaTop)
                {
                    continue;
                }

                // Устремим концы лучей в бесконечность
                Ray.Rayize();

                // Данные о ближайшем пересечении
                TubeProcessingData MinTpd      = null;
                double             MinDistance = 1e10;
                Plane3D            MinPlane    = null;

                // Для всех граней в сцене
                int fc = -1;
                foreach (Figure3D Fig in MyScene.Figs)
                {
                    foreach (Plane3D Plane in Fig.TransformedFaces)
                    {
                        fc++;
                        // Нам запрещено взаимодействовать с этим треугольником, пропускаем его
                        if (Ray.Prohibit == Plane)
                        {
                            continue;
                        }

                        // Данные о столковении
                        TubeProcessingData Tpd = Plane.ProcessTubeStageOne(Ray);

                        // Если оно имело место и оказалось ближе предыдущего, сохраним эти данные
                        if (Tpd.cs != TTCase.CaseNo && MinDistance > Tpd.Distance)
                        {
                            MinDistance = Tpd.Distance;
                            MinTpd      = Tpd;
                            MinPlane    = Plane;
                        }
                    }
                }

                // Список трубок, которые отправят на следующий этап алгоритма
                List <Tube3D> ToNextCall = new List <Tube3D>();
                // Список трубок, которые получены из падающей трубки путем ее разбиения
                List <Tube3D> SplitTubes = new List <Tube3D>();
                // Список трубок, отсчеченных
                List <Tube3D> ToThisCall = new List <Tube3D>();

                // Если нет никаких пересечений пересечение
                if (MinPlane == null)
                {
                    // Просто сохраним эту трубку с результатах
                    Ray.SetLenght(InfinityMVisible);
                    Result.Add(Ray);
                }
                else
                {
                    Log("Stage 2: " + MinTpd.cs);
                    if (MinTpd.cs == TTCase.CaseUnknown)
                    {
                        Log("Stage 2: Unknown case details: ");
                        Log("   Ic = " + MinTpd.Intersections.Count);
                        Log("   PinT = " + MinTpd.PinT);
                        Log("   TinP = " + MinTpd.TinP);
                    }

                    // Второй этап обработки трубки и треугольника дает нам уже все производные трубки
                    TubeProcessResult Tpr = MinPlane.ProcessTubeStageTwo(MinTpd, Ray, ToNextCall, SplitTubes, ToThisCall);

                    // Добавим трубки составляющее все, что осталось от исходной при отсечке
                    Result.AddRange(SplitTubes);

                    // Добавим результат рекурсивного вызова трассировки для следующего шага (это прел./отр. трубки)
                    Result.AddRange(RecursiveTracing(MyScene, ToNextCall, Call + 2));

                    // Добавим результат рекурсивного вызова трассировки для текущего шага (отсечка)
                    Result.AddRange(RecursiveTracing(MyScene, ToThisCall, Call, AddCnt + 1));
                }
            }

            return(Result);
        }