diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bc41f3e2..7c4dded2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,8 @@ - `Polyline.TransformAt` returns correct transformations when parameter on domain is provided. - `IndexedPolycurve` constructor that takes list of `BoundedCurve` now produces `CurveIndices` that share vertices and are withing index range. This means `IndexedPolyline.TransformedPolyline` preserves `CurveIndicies` on new `IndexedPolyline`. - `BoundedCurve.ToPolyline` now works correctly for `EllipticalArc` class. +- `Ray.Intersects(Topography)` and `Ray.Intersects(Mesh)` would sometimes return a different intersection than the closest one. +- `Ray.Intersects(Topography)` now considers the topography's transform. ### Changed diff --git a/Elements/src/Geometry/Mesh.cs b/Elements/src/Geometry/Mesh.cs index 1a28b4f26..9a7aeb3b9 100644 --- a/Elements/src/Geometry/Mesh.cs +++ b/Elements/src/Geometry/Mesh.cs @@ -259,7 +259,8 @@ public Triangle AddTriangle(Triangle t) public void RemoveTriangle(Triangle face) { this.Triangles.Remove(face); - foreach(var vert in face.Vertices) { + foreach (var vert in face.Vertices) + { vert.Triangles.Remove(face); } } @@ -450,10 +451,10 @@ public List GetNakedBoundaries() } /// - /// Does the provided ray intersect this mesh mesh? + /// Does the provided ray intersect this mesh? /// /// The Ray to intersect. - /// The location of intersection. + /// The location of the closest intersection. /// True if an intersection result occurs. /// False if no intersection occurs. public bool Intersects(Ray ray, out Vector3 intersection) @@ -461,14 +462,20 @@ public bool Intersects(Ray ray, out Vector3 intersection) var nearbyVertices = GetOctree().GetNearby(ray, _maxTriangleSize).ToList(); var nearbyTriangles = nearbyVertices.SelectMany(v => v.Triangles).Distinct(); intersection = default; + var closest = double.MaxValue; foreach (var t in nearbyTriangles) { - if (ray.Intersects(t, out intersection)) + if (ray.Intersects(t, out var triangleIntersection)) { - return true; + var d = triangleIntersection.DistanceTo(ray.Origin); + if (d < closest) + { + intersection = triangleIntersection; + closest = d; + } } } - return false; + return closest < double.MaxValue; } private double SignedVolumeOfTriangle(Triangle t) diff --git a/Elements/src/Geometry/Ray.cs b/Elements/src/Geometry/Ray.cs index 2c82d2a35..4e9989c6b 100644 --- a/Elements/src/Geometry/Ray.cs +++ b/Elements/src/Geometry/Ray.cs @@ -244,7 +244,15 @@ public bool Intersects(Plane plane, out Vector3 result, out double t) /// False if no intersection occurs. public bool Intersects(Topography topo, out Vector3 result) { - return Intersects(topo.Mesh, out result); + var transform = topo.Transform; + var inverse = transform.Inverted(); + var transformedRay = new Ray(inverse.OfPoint(Origin), Direction); + var intersects = transformedRay.Intersects(topo.Mesh, out result); + if (intersects) + { + result = transform.OfPoint(result); + } + return intersects; } /// diff --git a/Elements/test/RayTests.cs b/Elements/test/RayTests.cs index fb2e6b433..03c791ba7 100644 --- a/Elements/test/RayTests.cs +++ b/Elements/test/RayTests.cs @@ -7,6 +7,8 @@ using Xunit.Abstractions; using System.Diagnostics; using Vertex = Elements.Geometry.Vertex; +using Xunit.Sdk; +using System.Linq; namespace Elements.Tests { @@ -63,43 +65,34 @@ public void RayIntersectsTopography() { this.Name = "RayIntersectTopo"; - var elevations = new double[25]; + var elevations = new double[100]; int e = 0; - for (var x = 0; x < 5; x++) + for (var x = 0; x < 10; x++) { - for (var y = 0; y < 5; y++) + for (var y = 0; y < 10; y++) { - elevations[e] = Math.Sin(((double)x / 5.0) * Math.PI) * 10; + elevations[e] = Math.Sin(((double)x / 10.0) * Math.PI) * 5; e++; } } - var topo = new Topography(Vector3.Origin, 4, elevations); + var topo = new Topography(Vector3.Origin, 10, elevations) + { + Material = new Material("topo", new Color(0.5, 0.5, 0.5, 0.5)), + Transform = new Transform(0, 0, 2) + }; this.Model.AddElement(topo); - - var modelPoints = new ModelPoints(new List(), new Material("begin", Colors.Blue)); - this.Model.AddElement(modelPoints); - foreach (var t in topo.Mesh.Triangles) + this.Model.AddElements(new Transform().ToModelCurves()); + for (int i = 1; i < 9; i++) { - var c = Center(t); - var o = new Vector3(c.X, c.Y); - modelPoints.Locations.Add(o); - - var ray = new Ray(o, Vector3.ZAxis); - - Vector3 xsect; - if (ray.Intersects(t, out xsect)) + for (int j = 1; j < 9; j++) { - try - { - var l = new Line(o, xsect); - var ml = new ModelCurve(l); - this.Model.AddElement(ml); - } - catch - { - continue; - } + var newRay = new Ray(new Vector3(i, j, 40), Vector3.ZAxis.Negate()); + var intersect = newRay.Intersects(topo, out var result2); + Assert.True(intersect); + var line = new Line(result2, newRay.Origin); + Model.AddElement(new ModelCurve(line, BuiltInMaterials.XAxis)); + Assert.True(result2.Z > elevations.Min() + 2 && result2.Z < elevations.Max() + 2); } } }