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); }