/**
     * Estimate the 3D position (in unity units) of a point on the camera feed, optionally filtering
     * the results by the source of information that is used to estimate the 3d position. If no
     * types are specified, all hit test results are returned.
     *
     * X and Y are specified as numbers between 0 and 1, where (0, 0) is the upper left corner and
     * (1, 1) is the lower right corner of the camera feed as rendered in the camera that was
     * specified with UpdateCameraProjectionMatrix.
     *
     * Mutltiple 3d position esitmates may be returned for a single hit test based on the source
     * of data being used to estimate the position. The data source that was used to estimate the
     * position is indicated by the XRHitTestResult.Type.
     *
     * Example usage:
     *
     * List<XRHitTestResult> hits = new List<XRHitTestResult>();
     * List<XRHitTestResult.Type> types = new List<XRHitTestResult.Type>();
     * types.Add(XRHitTestResult.Type.DETECTED_SURFACE);
     * if (Input.touchCount != 0) {
     *   var t = Input.GetTouch(0);
     *   if (t.phase == TouchPhase.Began) {
     *     float x = t.position.x / Screen.width;
     *     float y = (Screen.height - t.position.y) / Screen.height;
     *     hits.AddRange(xr.HitTest(x, y, types));
     *   }
     * }
     */
    public List <XRHitTestResult> HitTest(float x, float y, List <XRHitTestResult.Type> includedTypes)
    {
        MessageBuilder queryMessage = new MessageBuilder();
        var            query        = queryMessage.initRoot(XrQueryRequest.factory);
        var            ht           = query.getHitTest();

        ht.setX(x);
        ht.setY(y);
        if (includedTypes.Count > 0)
        {
            query.getHitTest().initIncludedTypes(includedTypes.Count);
            for (int i = 0; i < includedTypes.Count; ++i)
            {
                var type = includedTypes[i];
                switch (type)
                {
                case XRHitTestResult.Type.FEATURE_POINT:
                    ht.getIncludedTypes().set(i, XrHitTestResult.ResultType.FEATURE_POINT);
                    break;

                case XRHitTestResult.Type.ESTIMATED_SURFACE:
                    ht.getIncludedTypes().set(i, XrHitTestResult.ResultType.ESTIMATED_SURFACE);
                    break;

                case XRHitTestResult.Type.DETECTED_SURFACE:
                    ht.getIncludedTypes().set(i, XrHitTestResult.ResultType.DETECTED_SURFACE);
                    break;

                default:
                    // pass
                    break;
                }
            }
        }
        var response = bridge.Query(queryMessage);
        List <XRHitTestResult> results = new List <XRHitTestResult>();

        foreach (var hit in response.getHitTest().getHits())
        {
            var type = XRHitTestResult.Type.UNSPECIFIED;
            switch (hit.getType())
            {
            case XrHitTestResult.ResultType.FEATURE_POINT:
                type = XRHitTestResult.Type.FEATURE_POINT;
                break;

            case XrHitTestResult.ResultType.ESTIMATED_SURFACE:
                type = XRHitTestResult.Type.ESTIMATED_SURFACE;
                break;

            case XrHitTestResult.ResultType.DETECTED_SURFACE:
                type = XRHitTestResult.Type.DETECTED_SURFACE;
                break;

            default:
                type = XRHitTestResult.Type.UNSPECIFIED;
                break;
            }
            Vector3 position = new Vector3(
                hit.getPlace().getPosition().getX(),
                hit.getPlace().getPosition().getY(),
                hit.getPlace().getPosition().getZ());
            Quaternion rotation = new Quaternion(
                hit.getPlace().getRotation().getX(),
                hit.getPlace().getRotation().getY(),
                hit.getPlace().getRotation().getZ(),
                hit.getPlace().getRotation().getW());
            float distance = hit.getDistance();
            results.Add(new XRHitTestResult(type, position, rotation, distance));
        }
        return(results);
    }