예제 #1
0
        public override bool TryGetIntersection(Vector2D point, out IntersectionInfo info)
        {
            ContainmentType type;

            Rectangle.Contains(ref point, out type);
            if (type == ContainmentType.Contains)
            {
                Scalar xDist, yDist;
                info.Position = point;
                xDist         = Math.Min(Rectangle.Min.X - point.X, point.X - Rectangle.Min.X);
                yDist         = Math.Min(Rectangle.Min.Y - point.Y, point.Y - Rectangle.Min.Y);
                if (xDist < yDist)
                {
                    info.Distance = xDist;
                    info.Normal.Y = 0;
                    info.Normal.X = (xDist < 0) ? (1) : (-1);
                }
                else
                {
                    info.Distance = yDist;
                    info.Normal.X = 0;
                    info.Normal.Y = (yDist < 0) ? (1) : (-1);
                }
                return(true);
            }
            else
            {
                info = IntersectionInfo.Zero;
                return(false);
            }
        }
예제 #2
0
        public void RefractedColor()
        {
            var world   = new DefaultWorld();
            var sphereA = world.Shapes[0];

            sphereA.Material.Ambient = 1;
            sphereA.Material.Pattern = new TestPattern();

            var sphereB = world.Shapes[1];

            sphereB.Material.Transparency    = 1;
            sphereB.Material.RefractiveIndex = 1.5f;

            var ray           = new Ray(new Point(0, 0, 0.1f), Vector.UnitY);
            var intersections = new Intersections(
                new Intersection(-0.9899f, sphereA),
                new Intersection(-0.4899f, sphereB),
                new Intersection(0.4899f, sphereB),
                new Intersection(0.9899f, sphereA));
            var info = new IntersectionInfo(intersections, intersections[2], ray);

            var actual = world.RefractedColor(info, 5);

            Assert.Equal(new Color(0, 0.9978715f, 0.047472f), actual);
        }
        private void TrimAtSource(Edge edge)
        {
            //pick the intersection furthest from the source
            IntersectionInfo x = Curve.GetAllIntersections(edge.Source.BoundaryCurve, edge.Curve, true).Aggregate((a, b) => a.Par1 > b.Par1 ? a : b);

            edge.Curve = edge.Curve.Trim(x.Par1, edge.Curve.ParEnd);
        }
예제 #4
0
 public bool TryGetIntersection(Vector2D point, out IntersectionInfo info)
 {
     info.Position = point;
     Vector2D.Normalize(ref point, out info.Distance, out info.Normal);
     info.Distance -= radius;
     return(info.Distance <= 0);
 }
        static internal Point RawIntersection(IntersectionInfo xx, Point origin)
        {
            // If this fires, then you didn't pass the LineSegment as the first argument to GetAllIntersections.
            Debug.Assert(xx.Segment0 is LineSegment, "LineSegment was not first arg to GetAllIntersections");

            // The intersection snaps the end of the intersection to the PolylinePoint at the start/end
            // of the interesecting segment on the obstacle if the intersection is Curve.CloseIntersections
            // to that segment endpoint, which can return a point that is just more than Curve.DistanceEpsilon
            // off the line.  Therefore, re-create the intersection using the LineSegment and intersection
            // parameters (this assumes the LineSegment.End is not Curve.CloseIntersections to the intersection).
            Point point = xx.Segment0[xx.Par0];

#if TEST_MSAGL
            // This may legitimately be rounding-error'd in the same way as xx.IntersectionPoint (and the
            // caller addresses this later).  The purpose of the assert is to verify that the LineSegment
            // interception is not outside the bbox in the perpendicular direction.
            var lineSeg = (LineSegment)xx.Segment0;
            if (StaticGraphUtility.IsVertical(PointComparer.GetDirections(lineSeg.Start, lineSeg.End)))
            {
                Debug.Assert(PointComparer.Equal(point.X, origin.X), "segment0 obstacle intersection is off the vertical line");
            }
            else
            {
                Debug.Assert(PointComparer.Equal(point.Y, origin.Y), "segment0 obstacle intersection is off the horizontal line");
            }
#endif // TEST_MSAGL
            return(ApproximateComparer.Round(point));
        }
예제 #6
0
        public void BaselineTestOfPerformance()
        {
#if DEBUG
            // my laptop in High Performance mode
            const double minMillionRaysPerSec = 2.5;
            const double maxMillionRaysPerSec = 3.4;
#elif APPVEYOR_PERFORMANCE_MARGINS
            // AppVeyor build server
            const double minMillionRaysPerSec = 9.0;
            const double maxMillionRaysPerSec = 13.0;
#else
            // my laptop in High Performance mode
            const double minMillionRaysPerSec = 4.5;
            const double maxMillionRaysPerSec = 9.6;
#endif

            const int numRays    = 1000000;
            var       numRaysHit = 0;

            DateTime startTime = DateTime.Now;
            for (var i = 0; i < numRays; i++)
            {
                var start = MakeRandomVector(-10, 10, -10, 10, -10, 10);
                var dir   = MakeRandomVector(1, 1, 1);
                var info  = new IntersectionInfo();
                numRaysHit++;
            }
            var elapsedTime       = DateTime.Now - startTime;
            var millionRaysPerSec = numRays / 1000000.0 / elapsedTime.TotalSeconds;
            Assert.IsTrue(minMillionRaysPerSec < millionRaysPerSec && millionRaysPerSec < maxMillionRaysPerSec,
                          "Rays per second {0:f2} not between {1} and {2} (millions)", millionRaysPerSec, minMillionRaysPerSec, maxMillionRaysPerSec);
            Console.WriteLine("Performance: {0} million rays per second", millionRaysPerSec);
        }
예제 #7
0
        private void LookForCloserNonGroupIntersectionToRestrictRay(IList <IntersectionInfo> intersections)
        {
            int numberOfGoodIntersections            = 0;
            IntersectionInfo closestIntersectionInfo = null;
            var localLeastDistSquared = this.restrictedRayLengthSquared;
            var testDirection         = PointComparer.GetDirections(restrictedIntersectionTestSegment.Start, restrictedIntersectionTestSegment.End);

            foreach (var intersectionInfo in intersections)
            {
                var intersect      = SpliceUtility.RawIntersection(intersectionInfo, currentRestrictedRay.Start);
                var dirToIntersect = PointComparer.GetDirections(currentRestrictedRay.Start, intersect);

                if (dirToIntersect == CompassVector.OppositeDir(testDirection))
                {
                    continue;
                }

                ++numberOfGoodIntersections;

                if (Directions.None == dirToIntersect)
                {
                    localLeastDistSquared   = 0.0;
                    closestIntersectionInfo = intersectionInfo;
                    continue;
                }

                var distSquared = (intersect - currentRestrictedRay.Start).LengthSquared;
                if (distSquared < localLeastDistSquared)
                {
                    // Rounding may falsely report two intersections as different when they are actually "Close",
                    // e.g. a horizontal vs. vertical intersection on a slanted edge.
                    var rawDistSquared = (intersectionInfo.IntersectionPoint - currentRestrictedRay.Start).LengthSquared;
                    if (rawDistSquared < ApproximateComparer.SquareOfDistanceEpsilon)
                    {
                        continue;
                    }

                    localLeastDistSquared   = distSquared;
                    closestIntersectionInfo = intersectionInfo;
                }
            }

            if (null != closestIntersectionInfo)
            {
                // If there was only one intersection and it is quite close to an end, ignore it.
                // If there is more than one intersection, we have crossed the obstacle so we want it.
                if (numberOfGoodIntersections == 1)
                {
                    var intersect = SpliceUtility.RawIntersection(closestIntersectionInfo, currentRestrictedRay.Start);
                    if (ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.Start) ||
                        ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.End))
                    {
                        return;
                    }
                }
                this.restrictedRayLengthSquared = localLeastDistSquared;
                currentRestrictedRay.End        = SpliceUtility.MungeClosestIntersectionInfo(currentRestrictedRay.Start, closestIntersectionInfo
                                                                                             , !StaticGraphUtility.IsVertical(currentRestrictedRay.Start, currentRestrictedRay.End));
            }
        }
예제 #8
0
        public void ConstructorN1AndN2(int index, float n1, float n2)
        {
            var outer = new Sphere(
                Matrix4x4.Scaling(2, 2, 2),
                Material.Glass());

            var innerLeft = new Sphere(
                Matrix4x4.Translation(0, 0, -0.25f),
                new Material(refractiveIndex: 2.0f));

            var innerRight = new Sphere(
                Matrix4x4.Translation(0, 0, 0.25f),
                new Material(refractiveIndex: 2.5f));

            var ray = new Ray(new Point(0, 0, -4), Vector.UnitZ);

            var intersections = new Intersections(
                new Intersection(2, outer),            // entering outer sphere
                new Intersection(2.75f, innerLeft),    // entering inner left sphere
                new Intersection(3.25f, innerRight),   // entering inner right sphere
                new Intersection(4.75f, innerLeft),    // exiting inner left sphere
                new Intersection(5.25f, innerRight),   // exiting inner right sphere
                new Intersection(6, outer));           // exiting outer sphere

            var info = new IntersectionInfo(intersections, intersections[index], ray);

            Assert.Equal(n1, info.RefractiveIndex1);
            Assert.Equal(n2, info.RefractiveIndex2);
        }
예제 #9
0
        public void ReflectanceSmallAngle()
        {
            var sphere        = new Sphere(Material.Glass());
            var ray           = new Ray(new Point(0, 0.99f, -2), Vector.UnitZ);
            var intersections = new Intersections(new Intersection(1.8589f, sphere));
            var info          = new IntersectionInfo(intersections, intersections[0], ray);

            Assert.Equal(0.4887307f, info.Reflectance());
        }
예제 #10
0
        public void ComputesReflectionVector()
        {
            var shape = new Plane();
            var r     = new Ray(new Point(0, 1, -1), new Vector(0, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f));
            var i     = new Intersection(MathF.Sqrt(2f), shape);
            var comps = new IntersectionInfo(i, r);

            comps.Reflect.Should().Be(new Vector(0, MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f));
        }
예제 #11
0
        public void IsNotInsideWhenIntersectsOutsideSurface()
        {
            var r     = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var shape = new Sphere();
            var i     = new Intersection(4, shape);
            var comps = new IntersectionInfo(i, r);

            comps.IsInside.Should().BeFalse();
        }
예제 #12
0
        public void InterpolatesNormalsForIntersections()
        {
            var tri   = DefaultTriangle();
            var i     = new Intersection(1, tri, 0.45f, 0.25f);
            var r     = new Ray(new Point(-0.2f, 0.3f, -2), new Vector(0, 0, 1));
            var xs    = Intersections.Create(i);
            var comps = new IntersectionInfo(i, r, xs);

            comps.Normal.Should().Be(new Normal(-0.5547f, 0.83205f, 0));
        }
예제 #13
0
        public void ReflectanceIsSignificantAtSmallViewAngles()
        {
            var s           = Spheres.GlassSphere();
            var r           = new Ray(new Point(0, 0.99f, -2f), new Vector(0, 0, 1));
            var xs          = Intersections.Create(new Intersection(1.8589f, s));
            var comps       = new IntersectionInfo(xs[0], r, xs);
            var reflectance = PhongShading.Schlick(comps);

            reflectance.Should().BeApproximately(0.48873f, 0.0001f);
        }
예제 #14
0
        public void ShadeHitIntersectionFromInside()
        {
            var world            = new DefaultWorld(new PointLight(new Point(0, 0.25f, 0), Color.White));
            var ray              = new Ray(new Point(0, 0, 0), new Vector(0, 0, 1));
            var shape            = world.Shapes[1];
            var intersection     = new Intersection(0.5f, shape);
            var intersectionInfo = new IntersectionInfo(new Intersections(intersection), intersection, ray);

            Assert.Equal(new Color(0.9046617f, 0.9046617f, 0.9046617f), world.ShadeHit(intersectionInfo, 0));
        }
예제 #15
0
        public void ShadeHitIntersectionFromOutside()
        {
            var world            = new DefaultWorld();
            var ray              = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var shape            = world.Shapes[0];
            var intersection     = new Intersection(4, shape);
            var intersectionInfo = new IntersectionInfo(new Intersections(intersection), intersection, ray);

            Assert.Equal(new Color(0.38066f, 0.47583f, 0.2855f), world.ShadeHit(intersectionInfo, 0));
        }
예제 #16
0
        public void RefractedColorOfOpaqueSurfaceIsBlack()
        {
            var w     = World.Default();
            var s     = w.Objects[0];
            var r     = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var xs    = Intersections.Create(new Intersection(4f, s), new Intersection(6f, s));
            var comps = new IntersectionInfo(xs[0], r, xs);

            PhongShading.RefractedColor(w, comps, 5).Should().Be(Colors.Black);
        }
예제 #17
0
        public void ConstructorReflection()
        {
            var plane        = new Plane();
            var ray          = new Ray(new Point(0, 1, -1), new Vector(0, -MathF.Sqrt(2) / 2, MathF.Sqrt(2) / 2));
            var intersection = new Intersection(MathF.Sqrt(2), plane);

            var info = new IntersectionInfo(new Intersections(intersection), intersection, ray);

            Assert.Equal(new Vector(0, MathF.Sqrt(2) / 2, MathF.Sqrt(2) / 2), info.ReflectVector);
        }
예제 #18
0
        public void IsInsideWhenIntersectsInsideSurface()
        {
            var r     = new Ray(new Point(0, 0, 0), new Vector(0, 0, 1));
            var shape = new Sphere();
            var i     = new Intersection(1, shape);
            var comps = new IntersectionInfo(i, r);

            comps.IsInside.Should().BeTrue();
            comps.Normal.Should().Be(new Normal(0, 0, -1));
        }
예제 #19
0
        public void ShadingOutsideIntersection()
        {
            var w     = World.Default();
            var r     = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var shape = w.Objects[0];
            var i     = new Intersection(4f, shape);
            var comps = new IntersectionInfo(i, r);
            var c     = PhongShading.HitColor(w, comps);

            c.Should().Be(new Color(0.38066f, 0.47583f, 0.2855f));
        }
예제 #20
0
        public void ReflectanceTotalInternalReflection()
        {
            var sphere        = new Sphere(Material.Glass());
            var ray           = new Ray(new Point(0, 0, MathF.Sqrt(2) / 2), Vector.UnitY);
            var intersections = new Intersections(
                new Intersection(-MathF.Sqrt(2) / 2, sphere),
                new Intersection(MathF.Sqrt(2) / 2, sphere));
            var info = new IntersectionInfo(intersections, intersections[1], ray);

            Assert.Equal(1, info.Reflectance());
        }
예제 #21
0
        public void ConstructorHitOffsetsPoint()
        {
            var ray          = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var sphere       = new Sphere(Matrix4x4.Translation(0, 0, 1));
            var intersection = new Intersection(5, sphere);

            var info = new IntersectionInfo(new Intersections(intersection), intersection, ray);

            Assert.True(info.OverPoint.Z < -0.0001f / 2);
            Assert.True(info.Point.Z > info.OverPoint.Z);
        }
예제 #22
0
        public void ReflectancePerpendicular()
        {
            var sphere        = new Sphere(Material.Glass());
            var ray           = new Ray(new Point(0, 0, 0), Vector.UnitY);
            var intersections = new Intersections(
                new Intersection(-1, sphere),
                new Intersection(1, sphere));
            var info = new IntersectionInfo(intersections, intersections[1], ray);

            Assert.Equal(0.040000003f, info.Reflectance());
        }
예제 #23
0
        public void ReflectanceIsSmallAtPerpendicularViewAngles()
        {
            var s  = Spheres.GlassSphere();
            var r  = new Ray(new Point(0, 0, 0), new Vector(0, 1, 0));
            var xs = Intersections.Create(new Intersection(-1f, s),
                                          new Intersection(1f, s));
            var comps       = new IntersectionInfo(xs[1], r, xs);
            var reflectance = PhongShading.Schlick(comps);

            reflectance.Should().BeApproximately(0.04f, 0.0001f);
        }
예제 #24
0
        public void SchlickApproximationForTotalInternalReflectionIsOne()
        {
            var s  = Spheres.GlassSphere();
            var r  = new Ray(new Point(0, 0, MathF.Sqrt(2f) / 2f), new Vector(0, 1, 0));
            var xs = Intersections.Create(new Intersection(-MathF.Sqrt(2f) / 2f, s),
                                          new Intersection(MathF.Sqrt(2f) / 2f, s));
            var comps       = new IntersectionInfo(xs[1], r, xs);
            var reflectance = PhongShading.Schlick(comps);

            reflectance.Should().Be(1f);
        }
예제 #25
0
        public void DeterminesOverPoint()
        {
            var r     = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var shape = new Sphere();

            shape.SetTransform(Transform.Translate(0, 0, 1));
            var i     = new Intersection(5, shape);
            var comps = new IntersectionInfo(i, r);

            comps.OverPoint.Z.Should().BeLessThan(-IntersectionInfo.Epsilon / 2f);
            comps.Point.Z.Should().BeGreaterThan(comps.OverPoint.Z);
        }
예제 #26
0
        public void RefractedColorOpaqueSurface()
        {
            var world         = new DefaultWorld();
            var sphere        = world.Shapes[0];
            var ray           = new Ray(new Point(0, 0, -5), Vector.UnitZ);
            var intersections = new Intersections(new Intersection(4, sphere), new Intersection(6, sphere));
            var info          = new IntersectionInfo(intersections, intersections[0], ray);

            var actual = world.RefractedColor(info, 5);

            Assert.Equal(Color.Black, actual);
        }
예제 #27
0
        public void ReflectedColorForNonReflectiveMaterialIsBlack()
        {
            var w     = World.Default();
            var r     = new Ray(new Point(0, 0, 0), new Vector(0, 0, 1));
            var shape = w.Objects[1];

            shape.Material.Ambient = 1f;
            var i     = new Intersection(1, shape);
            var comps = new IntersectionInfo(i, r);

            PhongShading.ReflectedColor(w, comps).Should().Be(Colors.Black);
        }
예제 #28
0
        public override IntersectionInfo Intersection(Ray r)
        {
            IntersectionInfo result = base.Intersection(r);

            if (result == null)
            {
                return(null);
            }

            Material material = result.Material;
            Point3D  P        = result.CrossPoint;

            Point3D E = new Point3D(P.X - Center.X, P.Y - Center.Y, P.Z - Center.Z);
            double  psi, fi;

            psi = Math.Asin(E.Z / Radius);

            if (Math.Abs(psi) == Math.PI / 2)
            {
                fi = 0;
            }
            else
            {
                double cosfi = E.X / (Radius * Math.Cos(psi));
                if (cosfi > 1)
                {
                    cosfi = 1;
                }
                if (cosfi < -1)
                {
                    cosfi = -1;
                }
                fi = Math.Acos(cosfi);
                if (E.Y < 0)
                {
                    fi = 2 * Math.PI - fi;
                }
            }

            Material m;

            lock (texture)
            {
                int x = (int)((fi / (Math.PI * 2)) * (texture.Width - 1));
                int y = (int)((0.5 - psi / Math.PI) * (texture.Height - 1));
                m = new Material(texture.GetPixel(x, y), material.Diffusion, material.Specularity,
                                 material.Reflection, material.Transparency, material.FongCoeff);
            }

            material = m;
            return(new IntersectionInfo(P, result.Normal, material));
        }
예제 #29
0
        public void RefractedColorIsBlackIfRemainingBouncesIsZero()
        {
            var w = World.Default();
            var s = w.Objects[0];

            s.Material.Transparency    = 1.0f;
            s.Material.RefractiveIndex = 1.5f;
            var r     = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1));
            var xs    = Intersections.Create(new Intersection(4f, s), new Intersection(6f, s));
            var comps = new IntersectionInfo(xs[0], r, xs);

            PhongShading.RefractedColor(w, comps, 0).Should().Be(Colors.Black);
        }
예제 #30
0
        public void ShadingInsideIntersection()
        {
            var w = World.Default();

            w.SetLights(new PointLight(new Point(0, 0.25f, 0), new Color(1f, 1f, 1f)));
            var r     = new Ray(new Point(0, 0, 0), new Vector(0, 0, 1));
            var shape = w.Objects[1];
            var i     = new Intersection(0.5f, shape);
            var comps = new IntersectionInfo(i, r);
            var c     = PhongShading.HitColor(w, comps);

            c.Should().Be(new Color(0.90482f, 0.90482f, 0.90482f));
        }
예제 #31
0
 public bool TryGetIntersection(Vector2D point, out IntersectionInfo info)
 {
     info.Position = point;
     Vector2D.Normalize(ref point, out info.Distance, out info.Normal);
     info.Distance -= radius;
     return info.Distance <= 0;
 }
예제 #32
0
 public bool TryGetIntersection(Vector2D point, out IntersectionInfo info)
 {
     return grid.TryGetIntersection(point, out info);
 }
예제 #33
0
        public static bool LineSegmentsIntersect(Vector2 p1, Vector2 p2, Vector2 q1, Vector2 q2, out Vector2 pointOfIntersection, out IntersectionInfo intersectionInfo)
        {
            Vector2 r = p2 - p1;
            Vector2 s = q2 - q1;
            float rXs = Vector3.Cross(r, s).z;
            float qpXr = Vector3.Cross((q1 - p1), r).z;

            //t = (q − p) × s / (r × s)
            float t = Vector3.Cross((q1 - p1), s).z / rXs;

            //u = (q − p) × r / (r × s)
            float u = qpXr / rXs;

            //If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
            if (rXs == 0 && qpXr == 0)
            {
                pointOfIntersection = new Vector2(float.NaN, float.NaN);
                intersectionInfo = IntersectionInfo.Collinear;
                return false;
            }
            else if (rXs == 0 && qpXr != 0) // If r × s = 0 and(q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
            {
                pointOfIntersection = new Vector2(float.NaN, float.NaN);
                intersectionInfo = IntersectionInfo.Parallel;
                return false;
            }
            else if (rXs != 0 && t <= 1 && t >= 0 && u <= 1 && u >= 0) // If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s
            {
                pointOfIntersection = p1 + t * r;
                intersectionInfo = IntersectionInfo.Intersecting;
                return true;
            }
            else
            {
                // Otherwise, the two line segments are not parallel but do not intersect.
                pointOfIntersection = new Vector2(float.NaN, float.NaN);
                intersectionInfo = IntersectionInfo.NonIntersecting;
                return false;
            }
        }
예제 #34
0
 public  bool TryGetIntersection(Vector2D point, out IntersectionInfo info)
 {
     throw new NotSupportedException();
 }