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); } }
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); }
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)); }
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); }
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)); } }
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); }
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()); }
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)); }
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(); }
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)); }
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); }
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)); }
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)); }
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); }
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); }
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)); }
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)); }
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()); }
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); }
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()); }
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); }
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); }
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); }
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); }
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); }
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)); }
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); }
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)); }
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; }
public bool TryGetIntersection(Vector2D point, out IntersectionInfo info) { return grid.TryGetIntersection(point, out info); }
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; } }
public bool TryGetIntersection(Vector2D point, out IntersectionInfo info) { throw new NotSupportedException(); }