Example #1
0
        /// <summary>
        /// Reflect a point in us.
        /// </summary>
        public Vector3D ReflectPoint(Vector3D p)
        {
            if (IsPlane)
            {
                // We used to call ProjectOntoPlane, but optimized it away.
                // This is faster because we already know our normal is normalized,
                // and it avoids some extra Vector3D operations.
                double   dist   = Euclidean3D.DistancePointPlane(this.Normal, this.Offset, p);
                Vector3D offset = this.Normal * dist * -2;
                return(p + offset);
            }
            else
            {
                if (p == Center)
                {
                    return(Infinity.InfinityVector);
                }
                if (Infinity.IsInfinite(p))
                {
                    return(Center);
                }

                Vector3D v = p - Center;
                double   d = v.Abs();
                v.Normalize();
                return(Center + v * (Radius * Radius / d));
            }
        }
Example #2
0
        /// <summary>
        /// Reflect a point in us.
        /// </summary>
        public Vector3D ReflectPoint(Vector3D p)
        {
            if (IsPlane)
            {
                //Debug.Assert( !Infinity.IsInfinite( p ) );
                Vector3D v = Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, p);
                v = p + (v - p) * 2;
                return(v);
            }
            else
            {
                if (p == Center)
                {
                    return(Infinity.InfinityVector);
                }
                if (Infinity.IsInfinite(p))
                {
                    return(Center);
                }

                Vector3D v = p - Center;
                double   d = v.Abs();
                v.Normalize();
                return(Center + v * (Radius * Radius / d));
            }
        }
Example #3
0
        public bool IsPointOn(Vector3D test)
        {
            if (IsPlane)
            {
                double dist = Euclidean3D.DistancePointPlane(this.Normal, this.Offset, test);
                return(Tolerance.Zero(dist));
            }

            return(Tolerance.Equal((test - Center).Abs(), Radius));
        }
Example #4
0
        /// <summary>
        /// Calculate a normal after a transformation function is applied
        /// to the points of the polygon.
        /// </summary>
        public Vector3D NormalAfterTransform(System.Func <Vector3D, Vector3D> transform)
        {
            if (this.NumSides < 1)
            {
                return(new Vector3D(0, 0, 1));
            }

            return(Euclidean3D.NormalFrom3Points(
                       this.Segments[0].P1, this.Segments[0].P2, this.Center, transform));
        }
Example #5
0
 public static void TranslateSphere(Sphere s, Vector3D t)
 {
     if (s.IsPlane)
     {
         Vector3D offsetAlongNormal = Euclidean3D.ProjectOntoLine(s.Normal, new Vector3D(), t);
         s.Offset += offsetAlongNormal;
     }
     else
     {
         s.Center += t;
     }
 }
Example #6
0
        /// <summary>
        /// Radially project a point onto our surface.
        /// </summary>
        public Vector3D ProjectToSurface(Vector3D p)
        {
            if (this.IsPlane)
            {
                return(Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, p));
            }

            Vector3D direction = p - Center;

            direction.Normalize();
            direction *= Radius;
            return(Center + direction);
        }
Example #7
0
        /// <summary>
        /// Reflect ourselves about another sphere.
        /// </summary>
        public void Reflect(Sphere sphere)
        {
            // An interior point used to calculate whether we get inverted.
            Vector3D interiorPoint;

            if (IsPlane)
            {
                Debug.Assert(!this.Normal.IsOrigin);
                interiorPoint = this.Offset - this.Normal;
            }
            else
            {
                // We don't want it to be the center, because that will reflect to infinity.
                interiorPoint = (this.Center + new Vector3D(this.Radius / 2, 0));
            }
            if (Invert)
            {
                interiorPoint = ReflectPoint(interiorPoint);
            }
            Debug.Assert(IsPointInside(interiorPoint));
            interiorPoint = sphere.ReflectPoint(interiorPoint);
            Debug.Assert(!interiorPoint.DNE);

            if (this.Equals(sphere))
            {
                if (IsPlane)
                {
                    //this.Center = -this.Center;	// Same as inverting, but we need to do it this way because of Pov-Ray
                    this.Invert = !this.Invert;
                }
                else
                {
                    this.Invert = !this.Invert;
                }

                Debug.Assert(this.IsPointInside(interiorPoint));
                return;
            }

            // Both planes?
            if (IsPlane && sphere.IsPlane)
            {
                // XXX - not general, but I know the planes I'll be dealing with go through the origin.
                //if( !sphere.Offset.IsOrigin )
                //	throw new System.NotImplementedException();

                /*Vector3D p1 = this.Normal.Cross( sphere.Normal );
                 * if( !p1.Normalize() )
                 * {
                 *      this.Center *= -1;
                 *      return;
                 * }
                 *
                 * Vector3D p2 = p1.Cross( this.Normal );
                 * p2.Normalize();
                 * p1 = sphere.ReflectPoint( p1 );
                 * p2 = sphere.ReflectPoint( p2 );
                 * Vector3D newNormal = p2.Cross( p1 );
                 * if( !newNormal.Normalize() )
                 *      throw new System.Exception( "Reflection impl" );
                 * this.Center = newNormal;*/

                // Reflect the normal relative to the plane (conjugate with sphere.Offset).
                Vector3D newNormal = this.Normal + sphere.Offset;
                newNormal  = sphere.ReflectPoint(newNormal);
                newNormal -= sphere.Offset;
                newNormal.Normalize();
                this.Center = newNormal;

                // Calc the new offset (so far we have considered planes through origin).
                this.Offset = sphere.ReflectPoint(this.Offset);

                //Debug.Assert( Offset.IsOrigin );	// XXX - should handle more generality.
                Debug.Assert(this.IsPointInside(interiorPoint));
                return;
            }

            // We are a plane and reflecting in a sphere.
            if (IsPlane)
            {
                // Think of 2D case here (circle and line)...
                Vector3D projected = Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, sphere.Center);
                Vector3D p         = sphere.ReflectPoint(projected);
                if (Infinity.IsInfinite(p))
                {
                    // This can happen if we go through sphere.Center.
                    // This reflection does not change our orientation (does not invert us).
                    return;
                }

                Center = sphere.Center + (p - sphere.Center) / 2;
                Radius = Center.Dist(sphere.Center);

                // Did this invert us?
                if (!this.IsPointInside(interiorPoint))
                {
                    Invert = !Invert;
                }

                return;
            }

            // Is mirror a plane?
            if (sphere.IsPlane)
            {
                Vector3D projected = Euclidean3D.ProjectOntoPlane(sphere.Normal, sphere.Offset, Center);
                Vector3D diff      = Center - projected;
                Center -= 2 * diff;
                // Radius remains unchanged.
                // NOTE: This does not invert us.
                Debug.Assert(this.IsPointInside(interiorPoint));
                return;
            }

            //
            // Now sphere reflecting in a sphere.
            //

            // Reflecting to a plane?
            if (IsPointOn(sphere.Center))
            {
                // Concentric spheres?
                if (Center == sphere.Center)
                {
                    throw new System.Exception();
                }

                // Center
                Vector3D center = Center - sphere.Center;

                // Offset
                Vector3D direction = center;
                direction.Normalize();
                Vector3D offset = direction * Radius * 2;
                offset = sphere.ReflectPoint(offset);

                // We are a line now.
                Center = center;
                //Offset = offset;	// Not working??  Caused issues in old generation code for 435.
                Radius = double.PositiveInfinity;

                // Did this invert us?
                if (!this.IsPointInside(interiorPoint))
                {
                    this.Invert = !this.Invert;
                }

                Debug.Assert(this.IsPointInside(interiorPoint));
                return;
            }

            // XXX - Could try to share code below with Circle class.
            // NOTE: We can't just reflect the center.
            //		 See http://mathworld.wolfram.com/Inversion.html
            double   a = Radius;
            double   k = sphere.Radius;
            Vector3D v = Center - sphere.Center;
            double   s = k * k / (v.MagSquared() - a * a);

            Center = sphere.Center + v * s;
            Radius = Math.Abs(s) * a;

            // Did this invert us?
            if (!this.IsPointInside(interiorPoint))
            {
                Invert = !Invert;
            }
        }