<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Vectrics
{
    public class Grid<T>
    {
        private float _cellRadius;
        private float _spacing;
        private float _toGrid;
        private Rectangle2D _region;
        private Rectangle2D _innerRegion;
        private List<T> _data = null;
        private int _stride;
        private int _rows;
        private int _count;

        public struct CellRegion
        {
            public int Start;
            public int Right;
            public int Down;
        }

        //PUBLIC

        public int CellCount
        {
            get { return _count; }
        }

        public float Spacing
        {
            get { return _spacing; }
        }

        public float CellRadius
        {
            get { return _cellRadius; }
        }

        public Rectangle2D Region
        {
            get { return _region; }
        }

        public int Stride
        {
            get { return _stride; }
        }

        public Grid(Rectangle2D region, float spacing) //resolution in cells per meter
        {
            _spacing = spacing;
            _cellRadius = (float)(0.5 * Math.Sqrt(2) * _spacing);
            _toGrid = 1.0f / _spacing;
            _region = region;
            _region.ExpandToGrid(_spacing);
            _innerRegion = _region.Expanded(-0.01f);
            Vector2D topLeft = CellsCenters.First();
            _stride = CellsCenters.Where(cc => cc.Y == topLeft.Y).Count();
            _count = CellsCenters.Count();
            _rows = _count / _stride;
            _data = Enumerable.Repeat(default(T), _count).ToList();
        }

        public void Clear(T value)
        {
            int max_i = _data.Count;
            for (int i = 0; i < max_i; i++)
                _data[i] = value;
        }

        public void Clear(Func<T> generator)
        {
            int max_i = _data.Count;
            for (int i = 0; i < max_i; i++)
                _data[i] = generator();
        }

        public T Sample(Vector2D point)
        {
            int index = CellIndexClamped(point);
            return _data[index];
        }

        public IEnumerable<T> SampleRegion(Rectangle2D region)
        {
            if (!_region.Overlaps(region))
                yield break;

            CellRegion r = RegionIndicesClamped(region);
            int i = r.Start;
            for (int y = 0; y <= r.Down; y++ )
                for (int x = 0; x <= r.Right; x++)
                    yield return _data[i + y * _stride + x];
        }

        public IEnumerable<T> SampleRegionOutward(Rectangle2D region)
        {
            if (!_region.Overlaps(region))
                yield break;

            CellRegion r = RegionIndicesClamped(region);
            //offset [ox, oy] starts at [0, 0] and spirals outward
            int ox = 0;
            int oy = 0;
            int dx = 0;
            int dy = -1;
            int halfX = r.Right / 2;
            int halfY = r.Down / 2;
            int tmp = Math.Max(r.Right, r.Down);
            int max = tmp * tmp;
            for (int i = 0; i < max; i++)
            {
                if((ox >= -halfX) && (ox <= halfX) && (oy >= -halfY) && (oy <= halfY))
                    yield return  _data[r.Start + halfX + ox + _stride * (halfY + oy)];
                if((ox == oy) || (ox < 0 && ox == -oy) || (ox > 0 && ox == 1-oy))
                {
                    tmp = dx;
                    dx = -dy;
                    dy = tmp;
                }
                ox += dx;
                oy += dy;
            }
        }

        public CellRegion RegionIndicesClamped(Rectangle2D rect)
        {
            rect = rect.Intersection(_region);
            rect.ExpandToGrid(_spacing);
            CellRegion region = new CellRegion();
            region.Start = CellIndexClamped(rect.TopLeft);
            float width = rect.Width / _spacing;
            region.Right = (int)width;
            if (region.Right <= width) //frac 0
                region.Right--;

            float height = rect.Height / _spacing;
            region.Down = (int)height;
            if (region.Down <= height) //frac 0
                region.Down--;
            return region;
        }

        public IEnumerable<T> SamplePerimeter(Rectangle2D rect)
        {
            CellRegion r = RegionIndicesClamped(rect);
            if (r.Right == 0 && r.Down == 0)
            {
                yield return _data[r.Start];
                yield break;
            }<commit_msg>fixed region indices clamped calculation<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Vectrics
{
    public class Grid<T>
    {
        private float _cellRadius;
        private float _spacing;
        private float _toGrid;
        private Rectangle2D _region;
        private Rectangle2D _innerRegion;
        private List<T> _data = null;
        private int _stride;
        private int _rows;
        private int _count;

        public struct CellRegion
        {
            public int Start;
            public int Right;
            public int Down;
        }

        //PUBLIC

        public int CellCount
        {
            get { return _count; }
        }

        public float Spacing
        {
            get { return _spacing; }
        }

        public float CellRadius
        {
            get { return _cellRadius; }
        }

        public Rectangle2D Region
        {
            get { return _region; }
        }

        public int Stride
        {
            get { return _stride; }
        }

        public Grid(Rectangle2D region, float spacing) //resolution in cells per meter
        {
            _spacing = spacing;
            _cellRadius = (float)(0.5 * Math.Sqrt(2) * _spacing);
            _toGrid = 1.0f / _spacing;
            _region = region;
            _region.ExpandToGrid(_spacing);
            _innerRegion = _region.Expanded(-0.01f);
            Vector2D topLeft = CellsCenters.First();
            _stride = CellsCenters.Where(cc => cc.Y == topLeft.Y).Count();
            _count = CellsCenters.Count();
            _rows = _count / _stride;
            _data = Enumerable.Repeat(default(T), _count).ToList();
        }

        public void Clear(T value)
        {
            int max_i = _data.Count;
            for (int i = 0; i < max_i; i++)
                _data[i] = value;
        }

        public void Clear(Func<T> generator)
        {
            int max_i = _data.Count;
            for (int i = 0; i < max_i; i++)
                _data[i] = generator();
        }

        public T Sample(Vector2D point)
        {
            int index = CellIndexClamped(point);
            return _data[index];
        }

        public IEnumerable<T> SampleRegion(Rectangle2D region)
        {
            if (!_region.Overlaps(region))
                yield break;

            CellRegion r = RegionIndicesClamped(region);
            int i = r.Start;
            for (int y = 0; y <= r.Down; y++ )
                for (int x = 0; x <= r.Right; x++)
                    yield return _data[i + y * _stride + x];
        }

        public IEnumerable<T> SampleRegionOutward(Rectangle2D region)
        {
            if (!_region.Overlaps(region))
                yield break;

            CellRegion r = RegionIndicesClamped(region);
            //offset [ox, oy] starts at [0, 0] and spirals outward
            int ox = 0;
            int oy = 0;
            int dx = 0;
            int dy = -1;
            int halfX = r.Right / 2;
            int halfY = r.Down / 2;
            int tmp = Math.Max(r.Right, r.Down);
            int max = tmp * tmp;
            for (int i = 0; i < max; i++)
            {
                if((ox >= -halfX) && (ox <= halfX) && (oy >= -halfY) && (oy <= halfY))
                    yield return  _data[r.Start + halfX + ox + _stride * (halfY + oy)];
                if((ox == oy) || (ox < 0 && ox == -oy) || (ox > 0 && ox == 1-oy))
                {
                    tmp = dx;
                    dx = -dy;
                    dy = tmp;
                }
                ox += dx;
                oy += dy;
            }
        }

        public CellRegion RegionIndicesClamped(Rectangle2D rect)
        {
            rect = rect.Intersection(_region);
            CellRegion region = new CellRegion();

            //.0 is considered the start of a new cell
            Vector2D p1 = _toGrid * (rect.TopLeft - _region.TopLeft);
            int x1 = Math.Min(_stride - 1, Math.Max(0, (int)p1.X));
            int y1 = Math.Min(_rows - 1, Math.Max(0, (int)p1.Y));
            region.Start = y1 * _stride + x1;

            //.0 is included in the previous cell
            Vector2D p2 = _toGrid * (rect.BottomRight - _region.TopLeft);
            int x2 = Math.Min(_stride - 1, Math.Max(x1, (int)(Math.Ceiling(p2.X) - 1)));
            int y2 = Math.Min(_rows - 1, Math.Max(y1, (int)(Math.Ceiling(p2.Y) - 1)));
            region.Right = x2 - x1;
            region.Down = y2 - y1;

            return region;
        }

        public IEnumerable<T> SamplePerimeter(Rectangle2D rect)
        {
            if (!_region.Overlaps(rect))
                yield break;

            CellRegion r = RegionIndicesClamped(rect);
            if (r.Right == 0 && r.Down == 0)
            {
                yield return _data[r.Start];
                yield break;
            }
{'fraction_non_alphanumeric': 0.10428931875525652, 'fraction_numerical': 0.010933557611438183, 'mean_word_length': 1.286229271809661, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5162478', 'n_tokens_mistral': 2832, 'n_tokens_neox': 2674, 'n_words': 735}