コード例 #1
0
        public static IList <FeatureHitTestResult> HitTestWithFeatures(this ARSCNView view, CGPoint point)
        {
            var results = new List <FeatureHitTestResult>();

            var ray = view.HitTestRayFromScreenPosition(point);

            if (ray.HasValue)
            {
                var result = view.HitTestFromOrigin(ray.Value.Origin, ray.Value.Direction);
                if (result.HasValue)
                {
                    results.Add(result.Value);
                }
            }

            return(results);
        }
コード例 #2
0
        public static SCNVector3?HitTestWithInfiniteHorizontalPlane(this ARSCNView view, CGPoint point, SCNVector3 pointOnPlane)
        {
            SCNVector3?result = null;

            var ray = view.HitTestRayFromScreenPosition(point);

            if (ray.HasValue)
            {
                // Do not intersect with planes above the camera or if the ray is almost parallel to the plane.
                if (ray.Value.Direction.Y <= -0.03f)
                {
                    // Return the intersection of a ray from the camera through the screen position with a horizontal plane
                    // at height (Y axis).
                    result = Utilities.RayIntersectionWithHorizontalPlane(ray.Value.Origin, ray.Value.Direction, pointOnPlane.Y);
                }
            }

            return(result);
        }
コード例 #3
0
        public static IList <FeatureHitTestResult> HitTestWithFeatures(this ARSCNView view,
                                                                       CGPoint point,
                                                                       float coneOpeningAngleInDegrees,
                                                                       float minDistance = 0,
                                                                       float maxDistance = float.MaxValue,
                                                                       int maxResults    = 1)
        {
            var results = new List <FeatureHitTestResult>();

            ARPointCloud features = null;

            using (var frame = view.Session.CurrentFrame)
            {
                features = frame?.RawFeaturePoints;
            }

            if (features != null)
            {
                var ray = view.HitTestRayFromScreenPosition(point);
                if (ray.HasValue)
                {
                    var maxAngleInDegrees = Math.Min(coneOpeningAngleInDegrees, 360f) / 2f;
                    var maxAngle          = (maxAngleInDegrees / 180f) * Math.PI;

                    var points = features.Points;
                    for (nuint j = 0; j < features.Count; j++)
                    {
                        var feature = points[j];

                        var featurePosition = new SCNVector3((Vector3)feature);
                        var originToFeature = featurePosition - ray.Value.Origin;

                        var crossProduct = SCNVector3.Cross(originToFeature, ray.Value.Direction);
                        var featureDistanceFromResult = crossProduct.Length;

                        var hitTestResult         = ray.Value.Origin + (ray.Value.Direction * SCNVector3.Dot(ray.Value.Direction, originToFeature));
                        var hitTestResultDistance = (hitTestResult - ray.Value.Origin).Length;

                        if (hitTestResultDistance < minDistance || hitTestResultDistance > maxDistance)
                        {
                            // Skip this feature - it is too close or too far away.
                            continue;
                        }

                        var originToFeatureNormalized = SCNVector3.Normalize(originToFeature);
                        var angleBetweenRayAndFeature = Math.Acos(SCNVector3.Dot(ray.Value.Direction, originToFeatureNormalized));

                        if (angleBetweenRayAndFeature > maxAngle)
                        {
                            // Skip this feature - is outside of the hit test cone.
                            continue;
                        }

                        // All tests passed: Add the hit against this feature to the results.
                        results.Add(new FeatureHitTestResult
                        {
                            Position                   = hitTestResult,
                            DistanceToRayOrigin        = hitTestResultDistance,
                            FeatureHit                 = featurePosition,
                            FeatureDistanceToHitResult = featureDistanceFromResult
                        });
                    }

                    // Sort the results by feature distance to the ray.
                    results = results.OrderBy(result => result.DistanceToRayOrigin).ToList();

                    // Cap the list to maxResults.
                    var cappedResults = new List <FeatureHitTestResult>();
                    var i             = 0;

                    while (i < maxResults && i < results.Count)
                    {
                        cappedResults.Add(results[i]);
                        i += 1;
                    }

                    results = cappedResults;
                }
            }

            return(results);
        }