<commit_before>﻿/*
The MIT License (MIT)
Copyright (c) 2018 Helix Toolkit contributors
*/
//#define DEBUG
using SharpDX;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#if !NETFX_CORE
namespace HelixToolkit.Wpf.SharpDX
#else
#if CORE
namespace HelixToolkit.SharpDX.Core
#else
namespace HelixToolkit.UWP
#endif
#endif
{
    namespace Utilities
    {
        /// <summary>
        /// Static octree for mesh
        /// </summary>
        public class StaticMeshGeometryOctree : StaticOctree<KeyValuePair<int, BoundingBox>>
        {
            /// <summary>
            /// 
            /// </summary>
            protected readonly IList<Vector3> Positions;
            /// <summary>
            /// 
            /// </summary>
            protected readonly IList<int> Indices;
            /// <summary>
            /// Initializes a new instance of the <see cref="StaticMeshGeometryOctree"/> class.
            /// </summary>
            /// <param name="positions">The positions.</param>
            /// <param name="indices">The indices.</param>
            /// <param name="parameter">The parameter.</param>
            public StaticMeshGeometryOctree(IList<Vector3> positions, IList<int> indices, OctreeBuildParameter parameter)
                : base(parameter)
            {
                Positions = positions;
                Indices = indices;
            }
            /// <summary>
            /// Gets the objects.
            /// </summary>
            /// <returns></returns>
            protected override KeyValuePair<int, BoundingBox>[] GetObjects()
            {
                var objects = new KeyValuePair<int, BoundingBox>[Indices.Count / 3];
                // Construct triangle index and its bounding box KeyValuePair
                for (int i = 0; i < Indices.Count / 3; ++i)
                {
                    objects[i] = new KeyValuePair<int, BoundingBox>(i, GetBoundingBox(i));
                }
                return objects;
            }
            protected override BoundingBox GetBoundingBoxFromItem(ref KeyValuePair<int, BoundingBox> item)
            {
                return item.Value;
            }

            protected override BoundingBox GetMaxBound()
            {
                return BoundingBoxExtensions.FromPoints(Positions);
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            private BoundingBox GetBoundingBox(int triangleIndex)
            {
                var actual = triangleIndex * 3;
                var v1 = Positions[Indices[actual++]];
                var v2 = Positions[Indices[actual++]];
                var v3 = Positions[Indices[actual]];
                var maxX = Math.Max(v1.X, Math.Max(v2.X, v3.X));
                var maxY = Math.Max(v1.Y, Math.Max(v2.Y, v3.Y));
                var maxZ = Math.Max(v1.Z, Math.Max(v2.Z, v3.Z));

                var minX = Math.Min(v1.X, Math.Min(v2.X, v3.X));
                var minY = Math.Min(v1.Y, Math.Min(v2.Y, v3.Y));
                var minZ = Math.Min(v1.Z, Math.Min(v2.Z, v3.Z));

                return new BoundingBox(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ));
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="octant"></param>
            /// <param name="context"></param>
            /// <param name="model"></param>
            /// <param name="geometry"></param>
            /// <param name="modelMatrix"></param>
            /// <param name="rayWS"></param>
            /// <param name="rayModel"></param>
            /// <param name="returnMultiple"></param>
            /// <param name="hits"></param>
            /// <param name="isIntersect"></param>
            /// <param name="hitThickness"></param>
            /// <returns></returns>
            protected override bool HitTestCurrentNodeExcludeChild(ref Octant octant,
                RenderContext context, object model, Geometry3D geometry, Matrix modelMatrix,
                ref Ray rayWS, ref Ray rayModel, bool returnMultiple, ref List<HitTestResult> hits,
                ref bool isIntersect, float hitThickness)
            {
                isIntersect = false;
                if (!octant.IsBuilt)
                {
                    return false;
                }
                var isHit = false;
                var bound = octant.Bound;
                //Hit test in local space.
                if (rayModel.Intersects(ref bound))
                {
                    isIntersect = true;
                    if (octant.Count == 0)
                    {
                        return false;
                    }
                    var result = new HitTestResult();
                    result.Distance = double.MaxValue;
                    float minDistance = float.MaxValue;
                    for (int i = octant.Start; i < octant.End; ++i)
                    {
                        var idx = Objects[i].Key * 3;
                        var t1 = Indices[idx];
                        var t2 = Indices[idx + 1];
                        var t3 = Indices[idx + 2];
                        var v0 = Positions[t1];
                        var v1 = Positions[t2];
                        var v2 = Positions[t3];

                        var scaling = 1f;
                        var rayScaled = rayModel;
                        if (MeshGeometry3D.EnableSmallTriangleHitTestScaling)
                        {
                            if ((v0 - v1).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare
                                || (v1 - v2).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare
                                || (v2 - v0).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare)
                            {
                                scaling = MeshGeometry3D.SmallTriangleHitTestScaling;
                                rayScaled = new Ray(rayModel.Position * scaling, rayModel.Direction);
                            }
                        }

                        if (Collision.RayIntersectsTriangle(ref rayScaled, ref v0, ref v1, ref v2, out float d))
                        {
                            d /= scaling;
                            if (returnMultiple)
                            {<commit_msg>Fix small triangle hit test is not working correctly in octree. #1428<commit_after>﻿/*
The MIT License (MIT)
Copyright (c) 2018 Helix Toolkit contributors
*/
//#define DEBUG
using SharpDX;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#if !NETFX_CORE
namespace HelixToolkit.Wpf.SharpDX
#else
#if CORE
namespace HelixToolkit.SharpDX.Core
#else
namespace HelixToolkit.UWP
#endif
#endif
{
    namespace Utilities
    {
        /// <summary>
        /// Static octree for mesh
        /// </summary>
        public class StaticMeshGeometryOctree : StaticOctree<KeyValuePair<int, BoundingBox>>
        {
            /// <summary>
            /// 
            /// </summary>
            protected readonly IList<Vector3> Positions;
            /// <summary>
            /// 
            /// </summary>
            protected readonly IList<int> Indices;
            /// <summary>
            /// Initializes a new instance of the <see cref="StaticMeshGeometryOctree"/> class.
            /// </summary>
            /// <param name="positions">The positions.</param>
            /// <param name="indices">The indices.</param>
            /// <param name="parameter">The parameter.</param>
            public StaticMeshGeometryOctree(IList<Vector3> positions, IList<int> indices, OctreeBuildParameter parameter)
                : base(parameter)
            {
                Positions = positions;
                Indices = indices;
            }
            /// <summary>
            /// Gets the objects.
            /// </summary>
            /// <returns></returns>
            protected override KeyValuePair<int, BoundingBox>[] GetObjects()
            {
                var objects = new KeyValuePair<int, BoundingBox>[Indices.Count / 3];
                // Construct triangle index and its bounding box KeyValuePair
                for (int i = 0; i < Indices.Count / 3; ++i)
                {
                    objects[i] = new KeyValuePair<int, BoundingBox>(i, GetBoundingBox(i));
                }
                return objects;
            }
            protected override BoundingBox GetBoundingBoxFromItem(ref KeyValuePair<int, BoundingBox> item)
            {
                return item.Value;
            }

            protected override BoundingBox GetMaxBound()
            {
                return BoundingBoxExtensions.FromPoints(Positions);
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            private BoundingBox GetBoundingBox(int triangleIndex)
            {
                var actual = triangleIndex * 3;
                var v1 = Positions[Indices[actual++]];
                var v2 = Positions[Indices[actual++]];
                var v3 = Positions[Indices[actual]];
                var maxX = Math.Max(v1.X, Math.Max(v2.X, v3.X));
                var maxY = Math.Max(v1.Y, Math.Max(v2.Y, v3.Y));
                var maxZ = Math.Max(v1.Z, Math.Max(v2.Z, v3.Z));

                var minX = Math.Min(v1.X, Math.Min(v2.X, v3.X));
                var minY = Math.Min(v1.Y, Math.Min(v2.Y, v3.Y));
                var minZ = Math.Min(v1.Z, Math.Min(v2.Z, v3.Z));

                return new BoundingBox(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ));
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="octant"></param>
            /// <param name="context"></param>
            /// <param name="model"></param>
            /// <param name="geometry"></param>
            /// <param name="modelMatrix"></param>
            /// <param name="rayWS"></param>
            /// <param name="rayModel"></param>
            /// <param name="returnMultiple"></param>
            /// <param name="hits"></param>
            /// <param name="isIntersect"></param>
            /// <param name="hitThickness"></param>
            /// <returns></returns>
            protected override bool HitTestCurrentNodeExcludeChild(ref Octant octant,
                RenderContext context, object model, Geometry3D geometry, Matrix modelMatrix,
                ref Ray rayWS, ref Ray rayModel, bool returnMultiple, ref List<HitTestResult> hits,
                ref bool isIntersect, float hitThickness)
            {
                isIntersect = false;
                if (!octant.IsBuilt)
                {
                    return false;
                }
                var isHit = false;
                var bound = octant.Bound;
                //Hit test in local space.
                if (rayModel.Intersects(ref bound))
                {
                    isIntersect = true;
                    if (octant.Count == 0)
                    {
                        return false;
                    }
                    var result = new HitTestResult();
                    result.Distance = double.MaxValue;
                    float minDistance = float.MaxValue;
                    for (int i = octant.Start; i < octant.End; ++i)
                    {
                        var idx = Objects[i].Key * 3;
                        var t1 = Indices[idx];
                        var t2 = Indices[idx + 1];
                        var t3 = Indices[idx + 2];
                        var v0 = Positions[t1];
                        var v1 = Positions[t2];
                        var v2 = Positions[t3];

                        var scaling = 1f;
                        var rayScaled = rayModel;
                        if (MeshGeometry3D.EnableSmallTriangleHitTestScaling)
                        {
                            if ((v0 - v1).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare
                                || (v1 - v2).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare
                                || (v2 - v0).LengthSquared() < MeshGeometry3D.SmallTriangleEdgeLengthSquare)
                            {
                                scaling = MeshGeometry3D.SmallTriangleHitTestScaling;
                                rayScaled = new Ray(rayModel.Position * scaling, rayModel.Direction);
                            }
                        }
                        v0 *= scaling;
                        v1 *= scaling;
                        v2 *= scaling;
                        if (Collision.RayIntersectsTriangle(ref rayScaled, ref v0, ref v1, ref v2, out float d))
                        {
                            d /= scaling;
                            if (returnMultiple)
                            {
{'fraction_non_alphanumeric': 0.10751937984496124, 'fraction_numerical': 0.010155038759689922, 'mean_word_length': 1.277316857899382, 'pattern_counts': {'":': 0, '<': 125, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4235246', 'n_tokens_mistral': 3461, 'n_tokens_neox': 3220, 'n_words': 753}