public TubeProcessingData ProcessTubeStageOne(Tube3D tube) { TubeProcessingData tpd = new TubeProcessingData(); Vector2[] Vert = new Vector2[3] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1) }; /* 1. Сохраним дно трубки */ /* for (int i = 0; i < 3; ++i) * tpd.OldDno[i] = new Vector3(tube.Rays[i].Begin); * tube.AntiRayize();*/ /* 2. Найдем точки пересечения каждого из лучей с плоскостью треугольника */ int Fails = 0; int UnderFails = 0; for (int i = 0; i < 3; ++i) { tpd.IFact[i] = RayIntersect(tube.Rays[i], out tpd.UVs[i].x, out tpd.UVs[i].y); /* Плоские координаты u, v в 3D x, y, z */ tpd.IPoints[i] = UVToXYZ(tpd.UVs[i].x, tpd.UVs[i].y); double t = tube.Rays[i].GetT(tpd.IPoints[i]); /* Если вдруг луч параллелен грани или вообще в другую сторону*/ if (tpd.IFact[i] == -1 || tpd.IFact[i] == -2 /*|| t <= GeometryEpsilon*/ || t > 1 + Tracer3D.GeometryEpsilon) { tpd.cs = TTCase.CaseNo; // Log("Stage1 : reject because tpd.IFact[" + i + "] = " + tpd.IFact[i] + " and t = " + t); return(tpd); } else if (t <= Tracer3D.GeometryEpsilon) { Fails++; tpd.ExclusiveCaseUnderDno = true; tpd.ExclusiveCaseIV[i] = true; // Log("tpd.ExclusiveCaseUnderDno = true;"); } // Log(" i = " + i + " ; t = " + t); /* трубка внутри треугольника */ if (tpd.IFact[i] == 1) { ++tpd.TinP; tpd.TinPs.Add(i); tpd.LastIndexTinP = i; } // Log("Stage 1: UnderPlane test: IPoints[i] = {" + tpd.IPoints[i].X + " , " + tpd.IPoints[i].Y + " , " + tpd.IPoints[i].Z + "}"); // Log("Stage 1: UnderPlane test: tube.Rays[0].Begin = {" + tube.Rays[0].Begin.X + " , " + tube.Rays[0].Begin.Y + " , " + tube.Rays[0].Begin.Z + "}"); if (tpd.UnderPlane(UVToXYZ(tpd.Vert[i].x, tpd.Vert[i].y) - tube.Rays[0].Begin)) { UnderFails++; tpd.DoNotAddPP[i] = true; Log("Stage1 : underfail on i = " + i); if (UnderFails == 3) { tpd.cs = TTCase.CaseNo; Log("Stage1 : reject because UnderFails = 3"); return(tpd); } } //if (cw != null) cw("IPoints[" + i + "] = " + IPoints[i].ToString() + " >>>>> u = " + UVs[i].x + " ; v = " + UVs[i].y); } if (Fails > 2) { tpd.cs = TTCase.CaseNo; return(tpd); } /* 3. ищем и пересчитываем все пересечения граней треугольника с гранями трубки */ for (int i = 0; i < 3; ++i) { /* точки треугольника в трубке ? */ double q1 = Utils2D.Classify(tpd.UVs[0].x, tpd.UVs[0].y, tpd.UVs[1].x, tpd.UVs[1].y, Vert[i].x, Vert[i].y); double q2 = Utils2D.Classify(tpd.UVs[1].x, tpd.UVs[1].y, tpd.UVs[2].x, tpd.UVs[2].y, Vert[i].x, Vert[i].y); double q3 = Utils2D.Classify(tpd.UVs[2].x, tpd.UVs[2].y, tpd.UVs[0].x, tpd.UVs[0].y, Vert[i].x, Vert[i].y); if ((q1 > 0 && q2 > 0 && q3 > 0) || (q1 < 0 && q2 < 0 && q3 < 0)) { ++tpd.PinT; tpd.PinTs.Add(i); tpd.LastIndexPinT = i; } int nexti = i == 2 ? 0 : i + 1; for (int j = 0; j < 3; ++j) { int nextj = j == 2 ? 0 : j + 1; Utils2D.CrossResultRec crr = Utils2D.Crossing(Vert[j], Vert[nextj], tpd.UVs[i], tpd.UVs[nexti]); if (crr.type == Utils2D.EnumCrossType.ctOnLine) { // double t1 = Utils2D.GetParameterLinesPoint(tpd.Vert[j], tpd.Vert[nextj], tpd.UVs[i]); // double t2 = Utils2D.GetParameterLinesPoint(tpd.Vert[j], tpd.Vert[nextj], tpd.UVs[nexti]); tpd.Intersections.Add(new IntersectRecord(tpd.UVs[i], i, nexti, j, nextj)); tpd.Intersections.Add(new IntersectRecord(tpd.UVs[nexti], i, nexti, j, nextj)); // tpd.DoNotAddPT[i] = true; // tpd.DoNotAddPT[nexti] = true; tpd.HasNoIc[i] = false; } else if (crr.type == Utils2D.EnumCrossType.ctInBounds || crr.type == Utils2D.EnumCrossType.ctOnBounds) { tpd.Intersections.Add(new IntersectRecord(crr.pt, i, nexti, j, nextj)); tpd.HasNoIc[i] = false; } /* else if (crr.type == Utils2D.EnumCrossType.ctOutBounds) * { * tpd.OutIntersections.Add(new IntersectRecord(crr.pt, i, nexti, j, nextj)); * }*/ } } int Ic = tpd.Intersections.Count; if (tpd.PinT == 0 && tpd.TinP == 0 && Ic < 4) { tpd.cs = TTCase.CaseNo; return(tpd); } /* 4. теперь зная TinP, PinT, Intersections.Count можно рассмотреть все 8 случаев */ tpd.cs = WhichCase(tpd.TinP, tpd.PinT, Ic); // определим случай /* 5. если пересечение есть, смотрим минимальную дистанцию до каждого луча */ if (tpd.cs != TTCase.CaseNo) { tpd.Distance = Math.Min(Math.Min( (tube.Rays[0].Begin - tpd.IPoints[0]).SumComponentSqrs(), (tube.Rays[1].Begin - tpd.IPoints[1]).SumComponentSqrs()), (tube.Rays[2].Begin - tpd.IPoints[2]).SumComponentSqrs()); tpd.WaveDirection = tube.CenterDirection(); tpd.WaveDirection.Normalize(); } /* for (int i = 0; i < 3; ++i) * tube.Rays[i].Begin = tpd.OldDno[i];*/ return(tpd); }
// 0 - REFLECT // 1 - REFRACT public Tube3D[] ReflectAndRefractTube(Tube3D itube) { Tube3D[] rtube = new Tube3D[2] { null, null }; // центральное направление падающей трубки Vector3 Dir = itube.CenterDirection(); // косинус угла падения double CosThetaI = Dir.DotProduct(Normal) / Dir.Magnitude; CosThetaI = Math.Abs(CosThetaI); // просветвляющее покрытие - нет отраженной трубки if (Tp != PlaneType.Antireflection) { rtube[0] = new Tube3D(); // всегда есть отражение rtube[0].MyN = itube.MyN; rtube[0].MyDelta = itube.MyDelta; } // показатель преломления в среде 2 double n2; double n1 = itube.MyN; // флаг того, что лучи идут из среды в вакуум (true) или наоборот (fasle) bool FromMediumToVacuum; if (itube.MyN == InnerN) // это значит луч распространялся в толще вещества и теперь выходит наружу { n2 = 1; // вакуум FromMediumToVacuum = true; } else // перешли из вакуума в среду { n2 = InnerN; FromMediumToVacuum = false; } // косинус угла преломления double CosThetaTSqr = 1 - (n1 * n1) / (n2 * n2) * (1 - CosThetaI * CosThetaI); // коэффициент отражения по формулам Френеля double ReCoeff = 1.0; // если этот косинус не в [-1,1], значит и нет преломления; так же, если поверхность - металл его тоже нет if (Tp != PlaneType.Metal && Math.Abs(CosThetaTSqr) <= 1) { // это - не полное внутреннее отражение, значит есть (возможно) преломленный rtube[1] = new Tube3D(); rtube[1].MyN = n2; rtube[1].MyDelta = FromMediumToVacuum ? 0.0 : InnerDelta; double CosThetaT = Math.Sqrt(CosThetaTSqr); if (n1 != n2) { if (itube.IsSPolarization) { ReCoeff = (n1 * CosThetaI - n2 * CosThetaT) / (n1 * CosThetaI + n2 * CosThetaT); } else { ReCoeff = (n1 * CosThetaT - n2 * CosThetaI) / (n1 * CosThetaT + n2 * CosThetaI); } ReCoeff *= ReCoeff; } else { ReCoeff = 0; rtube[0] = null; } } // в каждой трубке - три луча for (int i = 0; i < 3; ++i) { if (rtube[0] != null) { // отраженные лучи rtube[0].Rays[i] = Reflected(itube.Rays[i]); rtube[0].Color = new Vector4(0, 0, 1, 1); // добавим к лучу пройденную дистанцию от соответствующего луча падающей трубки rtube[0].Rays[i].AddPath(itube.Rays[i], itube.MyN); // !!! добавить фазу на отражение } if (rtube[1] != null) { // преломленный луч rtube[1].Rays[i] = Refracted(itube.Rays[i], itube.MyN, rtube[1].MyN); if (rtube[1].Rays[i] == null) // если хоть один из лучей испытывает полное внутрненнее отражение - нафиг всю трубку { rtube[1] = null; continue; } rtube[1].Color = new Vector4(0, 0.5, 0, 1); rtube[1].Rays[i].AddPath(itube.Rays[i], itube.MyN); } } if (rtube[0] != null) { rtube[0].Power = itube.Power * ReCoeff; rtube[0].Color.A = rtube[0].Power; } if (rtube[1] != null) { rtube[1].Power = itube.Power * (1 - ReCoeff); rtube[1].Color.A = rtube[1].Power; } return(rtube); }