コード例 #1
0
        public override double3 GetNormal(IntersectData data)
        {
            CsgIntersectData csgIsecData = data as CsgIntersectData;
            double3          n           = csgIsecData.RealObject.GetNormal(csgIsecData.RealData);

            return(csgIsecData.IsFrontSurface ? n : -n);
        }
コード例 #2
0
        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);
            }
        }