public override double3 GetNormal(IntersectData data) { CsgIntersectData csgIsecData = data as CsgIntersectData; double3 n = csgIsecData.RealObject.GetNormal(csgIsecData.RealData); return(csgIsecData.IsFrontSurface ? n : -n); }
public override List <IntersectData> Intersect(Ray r) { List <IntersectData> frontIsecs = new List <IntersectData> (); foreach (Traceable operand in Operands) { frontIsecs.AddRange(operand.Intersect(r)); } // Note: the following calculations assume that // nDotRay == 0 ignored cos it produces both // enter and exit at the same time. // Also operands should be non-self-intersecting figures. if (frontIsecs.Count > 0) { List <IntersectData> backIsecs = new List <IntersectData> (); Ray nR = -r; foreach (Traceable operand in Operands) { backIsecs.AddRange(operand.Intersect(nR)); } var sortedIsecs = backIsecs.OrderByDescending(isecData => (isecData.P - r.p).LengthSq) .Concat(frontIsecs.OrderBy(isecData => (isecData.P - r.p).LengthSq)) .Distinct(); List <IntersectData> resultIsecs = new List <IntersectData> (); if (Operation == CsgOp.Subtract) { int numSubtrahendEnters = 0; int numOpAEnters = 0; foreach (IntersectData isecData in sortedIsecs) { bool isFrontSurface = true; bool InsideAAndExitedSubtrahends = false; bool InsideAAndEnteredSubtrahend = false; bool ExitedAAndOutsideSubtrahends = false; bool EnteredAAndOutsideSubtrahends = false; double3 n = isecData.Object.GetNormal(isecData); double nDotRay = n & r.l; if (isecData.Object != Operands [0]) { if (nDotRay < 0) { numSubtrahendEnters++; if (numSubtrahendEnters == 1 && numOpAEnters == 1) { InsideAAndEnteredSubtrahend = true; isFrontSurface = false; } } else if (nDotRay > 0) { numSubtrahendEnters--; if (numSubtrahendEnters == 0 && numOpAEnters == 1) { InsideAAndExitedSubtrahends = true; isFrontSurface = false; } } } else { if (nDotRay < 0) { numOpAEnters++; if (numSubtrahendEnters == 0 && numOpAEnters == 1) { EnteredAAndOutsideSubtrahends = true; } } else if (nDotRay > 0) { numOpAEnters--; if (numSubtrahendEnters == 0 && numOpAEnters == 0) { ExitedAAndOutsideSubtrahends = true; } } } if (InsideAAndExitedSubtrahends || InsideAAndEnteredSubtrahend || ExitedAAndOutsideSubtrahends || EnteredAAndOutsideSubtrahends) { CsgIntersectData csgIsecData = new CsgIntersectData(isecData.P, this, isecData.Object, isFrontSurface, isecData); resultIsecs.Add(csgIsecData); } } } else if (Operation == CsgOp.Intersect) { List <Traceable> insideList = new List <Traceable> (); bool isInside = false; foreach (IntersectData isecData in sortedIsecs) { double3 n = isecData.Object.GetNormal(isecData); double nDotRay = n & r.l; if (nDotRay < 0) { insideList.Add(isecData.Object); if (insideList.Count == Operands.Count) { CsgIntersectData csgIsecData = new CsgIntersectData(isecData.P, this, isecData.Object, true, isecData); resultIsecs.Add(csgIsecData); isInside = true; } } else if (nDotRay > 0) { insideList.Remove(isecData.Object); if (insideList.Count == Operands.Count - 1 && isInside) { CsgIntersectData csgIsecData = new CsgIntersectData(isecData.P, this, isecData.Object, true, isecData); resultIsecs.Add(csgIsecData); isInside = false; } } } } else if (Operation == CsgOp.Union) { List <Traceable> insideList = new List <Traceable> (); foreach (IntersectData isecData in sortedIsecs) { double3 n = isecData.Object.GetNormal(isecData); double nDotRay = n & r.l; if (nDotRay < 0) { insideList.Add(isecData.Object); if (insideList.Count == 1) { CsgIntersectData csgIsecData = new CsgIntersectData(isecData.P, this, isecData.Object, true, isecData); resultIsecs.Add(csgIsecData); } } else if (nDotRay > 0) { insideList.Remove(isecData.Object); if (insideList.Count == 0) { CsgIntersectData csgIsecData = new CsgIntersectData(isecData.P, this, isecData.Object, true, isecData); resultIsecs.Add(csgIsecData); } } } } resultIsecs = resultIsecs.Where(isecData => !backIsecs.Contains((isecData as CsgIntersectData).RealData)).ToList(); return(resultIsecs); } else { return(frontIsecs); } }