<commit_before>using Mapsui.Fetcher;
using Mapsui.Rendering.Skia;
using CoreFoundation;
using Foundation;
using UIKit;
using System;
using System.ComponentModel;
using System.Linq;
using CoreGraphics;
using SkiaSharp.Views.iOS;

namespace Mapsui.UI.iOS
{
    [Register("MapControl"), DesignTimeVisible(true)]
    public class MapControl : UIStackView, IMapControl
    {
        private CGPoint _previousMid;
        private CGPoint _currentMid;
        private float _oldDist = 1f;
        private Map _map;
        private readonly MapRenderer _renderer = new MapRenderer();
        private readonly SKCanvasView _canvas = new SKCanvasView();
        private readonly AttributionView _attributionPanel = new AttributionView();

        private bool _viewportInitialized;

        private float Width => (float)Frame.Width;
        private float Height => (float)Frame.Height;

        public event EventHandler ViewportInitialized;

        public MapControl(CGRect frame)
            : base(frame)
        {
            Initialize();
        }

        [Preserve]
        public MapControl(IntPtr handle) : base(handle) // used when initialized from storyboard
        {
            Initialize();
        }
        
        public override CGRect Frame
        {
            get { return base.Frame; }
            set
            {
                Resize(value);
                base.Frame = value;
            }
        }

        private void Resize(CGRect frame)
        {
            _canvas.Frame = frame;
            _attributionPanel.Frame = new CGRect(
                frame.Width - _attributionPanel.Frame.Width, 
                frame.Height - _attributionPanel.Frame.Height,
                _attributionPanel.Frame.Width,
                _attributionPanel.Frame.Height);
        }

        public void Initialize()
        {
            Map = new Map();
            BackgroundColor = UIColor.White;

            Axis = UILayoutConstraintAxis.Vertical;    
            
            _canvas.ClipsToBounds = true;           
            AddSubview(_canvas);

            AddSubview(_attributionPanel);

            InitializeViewport();
            
            ClipsToBounds = true;

            var pinchGesture = new UIPinchGestureRecognizer(PinchGesture) { Enabled = true };
            AddGestureRecognizer(pinchGesture);

            _canvas.PaintSurface += OnPaintSurface;
        }

        public override void LayoutMarginsDidChange()
        {
            if (_canvas == null) return;

            var frame = _canvas.Frame;
            frame.Size = frame.Size;
            _canvas.Frame = frame;

            base.LayoutMarginsDidChange();
        }

        private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs skPaintSurfaceEventArgs)
        {
            if (!_viewportInitialized) InitializeViewport();
            if (!_viewportInitialized) return;

            if (Width != _map.Viewport.Width) _map.Viewport.Width = Width;
            if (Height != _map.Viewport.Height) _map.Viewport.Height = Height;

            var scaleFactor = 2; // todo: figure out how to get this value programatically
            skPaintSurfaceEventArgs.Surface.Canvas.Scale(scaleFactor, scaleFactor);

            _renderer.Render(skPaintSurfaceEventArgs.Surface.Canvas, _map.Viewport, _map.Layers, _map.BackColor);
        }

        private void InitializeViewport()
        {
            if (ViewportHelper.TryInitializeViewport(_map, Width, Height))
            {
                _viewportInitialized = true;
                Map.ViewChanged(true);
                OnViewportInitialized();
            }
        }
        
        private void OnViewportInitialized()
        {
            ViewportInitialized?.Invoke(this, EventArgs.Empty);
        }

        private void PinchGesture(UIPinchGestureRecognizer recognizer)
        {
            if ((int)recognizer.NumberOfTouches < 2)
                return;

            if (recognizer.State == UIGestureRecognizerState.Began)
            {
                _oldDist = 1;
                _currentMid = recognizer.LocationInView(this);
            }

            var scale = 1 - (_oldDist - (float)recognizer.Scale);

            if (scale > 0.5 && scale < 1.5)
            {
                if (_oldDist != (float)recognizer.Scale)
                {
                    _oldDist = (float)recognizer.Scale;
                    _currentMid = recognizer.LocationInView(this);
                    _previousMid = new CGPoint(_currentMid.X, _currentMid.Y);

                    _map.Viewport.Center = _map.Viewport.ScreenToWorld(
                        _currentMid.X,
                        _currentMid.Y);
                    _map.Viewport.Resolution = _map.Viewport.Resolution / scale;
                    _map.Viewport.Center = _map.Viewport.ScreenToWorld(
                        (_map.Viewport.Width - _currentMid.X),
                        (_map.Viewport.Height - _currentMid.Y));
                }

                _map.Viewport.Transform(
                    _currentMid.X,
                    _currentMid.Y,
                    _previousMid.X,
                    _previousMid.Y);

                RefreshGraphics();
            }

            var majorChange = recognizer.State == UIGestureRecognizerState.Ended;
            _map.ViewChanged(majorChange);
        }

        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            if ((uint)touches.Count == 1)
            {
                var touch = touches.AnyObject as UITouch;
                if (touch != null)
                {
                    var currentPos = touch.LocationInView(this);
                    var previousPos = touch.PreviousLocationInView(this);

                    var cRect = new CGRect(new CGPoint((int)currentPos.X, (int)currentPos.Y), new CGSize(5, 5));
                    var pRect = new CGRect(new CGPoint((int)previousPos.X, (int)previousPos.Y), new CGSize(5, 5));

                    if (!cRect.IntersectsWith(pRect))
                    {
                        _map.Viewport.Transform(currentPos.X, currentPos.Y, previousPos.X, previousPos.Y);

                        RefreshGraphics();
                    }
                }
            }
        }

        public override void TouchesEnded(NSSet touches, UIEvent e)
        {
            Refresh();
            HandleInfo(e.AllTouches);
        }

        private void HandleInfo(NSSet touches)
        {
            if (touches.Count != 1) return;
            var touch = touches.FirstOrDefault() as UITouch;
            if (touch == null) return;
            var screenPosition = touch.LocationInView(this);
            Map.InvokeInfo(screenPosition.ToMapsui(), _renderer.SymbolCache);
        }
<commit_msg>Replacing iOS gesture touch with TouchesMoved override<commit_after>using Mapsui.Fetcher;
using Mapsui.Rendering.Skia;
using CoreFoundation;
using Foundation;
using UIKit;
using System;
using System.ComponentModel;
using System.Linq;
using CoreGraphics;
using Mapsui.Geometries.Utilities;
using SkiaSharp.Views.iOS;

namespace Mapsui.UI.iOS
{
    [Register("MapControl"), DesignTimeVisible(true)]
    public class MapControl : UIStackView, IMapControl
    {
        private Map _map;
        private readonly MapRenderer _renderer = new MapRenderer();
        private readonly SKCanvasView _canvas = new SKCanvasView();
        private readonly AttributionView _attributionPanel = new AttributionView();
        private nuint _previousTouchCount = 0;
        private bool _viewportInitialized;
        private nfloat _previousX;
        private nfloat _previousY;
        private double _previousRadius;

        private float Width => (float)Frame.Width;
        private float Height => (float)Frame.Height;

        public event EventHandler ViewportInitialized;

        public MapControl(CGRect frame)
            : base(frame)
        {
            Initialize();
        }

        [Preserve]
        public MapControl(IntPtr handle) : base(handle) // used when initialized from storyboard
        {
            Initialize();
        }

        public override CGRect Frame
        {
            get { return base.Frame; }
            set
            {
                Resize(value);
                base.Frame = value;
            }
        }

        private void Resize(CGRect frame)
        {
            _canvas.Frame = frame;
            _attributionPanel.Frame = new CGRect(
                frame.Width - _attributionPanel.Frame.Width,
                frame.Height - _attributionPanel.Frame.Height,
                _attributionPanel.Frame.Width,
                _attributionPanel.Frame.Height);
        }

        public void Initialize()
        {
            Map = new Map();
            BackgroundColor = UIColor.White;

            Axis = UILayoutConstraintAxis.Vertical;

            _canvas.ClipsToBounds = true;
            _canvas.MultipleTouchEnabled = true;
            AddSubview(_canvas);

            AddSubview(_attributionPanel);

            InitializeViewport();

            ClipsToBounds = true;

            MultipleTouchEnabled = true;
            UserInteractionEnabled = true;

            _canvas.PaintSurface += OnPaintSurface;
        }

        public override void LayoutMarginsDidChange()
        {
            if (_canvas == null) return;

            var frame = _canvas.Frame;
            frame.Size = frame.Size;
            _canvas.Frame = frame;

            base.LayoutMarginsDidChange();
        }

        private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs skPaintSurfaceEventArgs)
        {
            if (!_viewportInitialized) InitializeViewport();
            if (!_viewportInitialized) return;

            if (Width != _map.Viewport.Width) _map.Viewport.Width = Width;
            if (Height != _map.Viewport.Height) _map.Viewport.Height = Height;

            var scaleFactor = 2; // todo: figure out how to get this value programatically
            skPaintSurfaceEventArgs.Surface.Canvas.Scale(scaleFactor, scaleFactor);

            _renderer.Render(skPaintSurfaceEventArgs.Surface.Canvas, _map.Viewport, _map.Layers, _map.BackColor);
        }

        private void InitializeViewport()
        {
            if (ViewportHelper.TryInitializeViewport(_map, Width, Height))
            {
                _viewportInitialized = true;
                Map.ViewChanged(true);
                OnViewportInitialized();
            }
        }

        private void OnViewportInitialized()
        {
            ViewportInitialized?.Invoke(this, EventArgs.Empty);
        }

        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            base.TouchesMoved(touches, evt);

            
            if (touches.Count == 1)
            {
                var touch = touches.AnyObject as UITouch;
                if (touch != null)
                {
                    var currentPos = touch.LocationInView(this);
                    var previousPos = touch.PreviousLocationInView(this);

                    var cRect = new CGRect(new CGPoint((int)currentPos.X, (int)currentPos.Y), new CGSize(5, 5));
                    var pRect = new CGRect(new CGPoint((int)previousPos.X, (int)previousPos.Y), new CGSize(5, 5));

                    if (!cRect.IntersectsWith(pRect))
                    {
                        if (_previousTouchCount == touches.Count)
                        {
                            _map.Viewport.Transform(currentPos.X, currentPos.Y, previousPos.X, previousPos.Y);
                            RefreshGraphics();
                        }
                    }
                }
            }
            else if (touches.Count == 2)
            {
                nfloat centerX = 0;
                nfloat centerY = 0;

                var locations = touches.Select(t => ((UITouch) t).LocationInView(this)).ToList();

                foreach (var location in locations)
                {
                    centerX += location.X;
                    centerY += location.Y;
                }

                centerX = centerX / touches.Count;
                centerY = centerY / touches.Count;
                var radius = Algorithms.Distance(centerX, centerY, locations[0].X, locations[0].Y);

                if (_previousTouchCount == touches.Count)
                {
                    _map.Viewport.Transform(centerX, centerY, _previousX, _previousY, radius / _previousRadius);
                    RefreshGraphics();
                }

                _previousX = centerX;
                _previousY = centerY;
                _previousRadius = radius;
            }
            _previousTouchCount = touches.Count;
        }

        public override void TouchesEnded(NSSet touches, UIEvent e)
        {
            Refresh();
            HandleInfo(e.AllTouches);
        }

        private void HandleInfo(NSSet touches)
        {
            if (touches.Count != 1) return;
            var touch = touches.FirstOrDefault() as UITouch;
            if (touch == null) return;
            var screenPosition = touch.LocationInView(this);
            Map.InvokeInfo(screenPosition.ToMapsui(), _renderer.SymbolCache);
        }

{'fraction_non_alphanumeric': 0.08199198972266304, 'fraction_numerical': 0.0021159223154235624, 'mean_word_length': 1.6154150197628458, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, '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': '2104032', 'n_tokens_mistral': 3540, 'n_tokens_neox': 3291, 'n_words': 719}