Vector2Array
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RicardoSantos

//@version=5

// @description functions to handle vector2 Array operations.
// .
// references:
//      https://docs.unity3d.com/ScriptReference/Vector2.html
//      https://gist.github.com/winduptoy/a1aa09c3499e09edbd33
//      https://github.com/dogancoruh/Javascript-Vector2/blob/master/js/vector2.js
//      https://gist.github.com/Dalimil/3daf2a0c531d7d030deb37a7bfeff454
//      https://gist.github.com/jeantimex/7fa22744e0c45e5df770b532f696af2d
//      https://gist.github.com/volkansalma/2972237
// .
library(title='Vector2Array')

//#region ~~~ Imports and Helpers:

import RicardoSantos/CommonTypesMath/1 as TMath
import RicardoSantos/Vector2/1 as Vector2

//#endregion



//#region   -> Constructor:

// from () {

// @function Generate array of vector2 from string.
// @param source string Source string of the vectors.
// @param prop_sep string Separator character of the vector properties (x`,`y).
// @param vect_sep string Separator character of the vectors ((x,y)`;`(x,y)).
// @returns array<Vector2>.
export from (string source, string prop_sep=',', string vect_sep=';') =>
    array<string> _s = str.split(source, vect_sep)
    int _size = _s.size()
    if _size > 0
        _output = array.new<TMath.Vector2>(_size)
        for [_i, _e] in _s
            _output.set(_i, Vector2.from(_e, prop_sep))
        _output

// TEST: 20230221 RS
// if barstate.islast
//     _V = from('1.2,3;2.0,3.0;(1,2.0);4,3')
//     _str = ''
//     for _e in _V
//         _str += ':' + _e.to_string()
//     label.new(bar_index, 0.0, _str)

// }

//#endregion



//#region ~~~ Array Methods:

// max      () {

// @function Combination of the highest elements in column of a array of vectors.
// @param vectors array<Vector2.Vector2>, Array of Vector2 objects.
// @returns Vector2.Vector2, Vector2 object.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = max(array.from(a, b, c)) , plot(d.x)`
export method max (array<TMath.Vector2> vectors) =>
	int _size = array.size(vectors)
	if _size > 0
		TMath.Vector2 _min = array.get(vectors, 0)
		for _e in vectors
			if _e.x > _min.x 
				_min.x := _e.x
			if _e.y > _min.y 
				_min.y := _e.y
		_min
	else
		Vector2.nan()

// }
// min      () {

// @function Combination of the lowest elements in column of a array of vectors.
// @param vectors array<Vector2.Vector2>, Array of Vector2 objects.
// @returns Vector2.Vector2, Vector2 object.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = min(array.from(a, b, c)) , plot(d.x)`
export min (array<TMath.Vector2> vectors) =>
	int _size = array.size(vectors)
	if _size > 0
		TMath.Vector2 _min = array.get(vectors, 0)
		for _e in vectors
			if _e.x < _min.x
				_min.x := _e.x
			if _e.y < _min.y
				_min.y := _e.y
		_min
	else
		Vector2.nan()

// }
// sum      () {

// @function Total sum of all vectors.
// @param vectors array<Vector2.Vector2>, ID of the vector2 array.
// @returns Vector2.Vector2, vector2 object.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = sum(array.from(a, b, c)) , plot(d.x)`
export sum (array<TMath.Vector2> vectors) =>
    TMath.Vector2 _sum = Vector2.zero()
    for _e in vectors
        _sum.x += _e.x
        _sum.y += _e.y
    _sum

// }
// center   () {

// @function Finds the vector center of the array.
// @param vectors array<Vector2.Vector2>, ID of the vector2 array.
// @returns Vector2.Vector2, vector2 object.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = center(array.from(a, b, c)) , plot(d.x)`
export center (array<TMath.Vector2> vectors) =>
    int _size = array.size(vectors)
    TMath.Vector2 _sum = sum(vectors)
    Vector2.new(_sum.x / _size, _sum.y / _size)

// }
// rotate   () {

// @function Rotate Array vectors around origin vector by a angle.
// @param vectors array<Vector2.Vector2>, ID of the vector2 array.
// @param center  Vector2.Vector2       , Vector2 object. Center of the rotation.
// @param degree  float                 , Angle value.
// @returns rotated points array.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = rotate(array.from(a, b, c), b, 45.0)`
export rotate (array<TMath.Vector2> vectors, TMath.Vector2 center, float degree) =>
    array<TMath.Vector2> _vectors = array.new<TMath.Vector2>(0, Vector2.nan())
    int _size = array.size(vectors)
    for _e in vectors
        array.push(_vectors, Vector2.rotate_around(_e, center, degree))
    _vectors

// TEST: 20230206 RS
// va = Vector2.from(300.0) , vb = Vector2.from(200.0), vc = Vector2.from(100.0)//, vd = rotate(array.from(va, vb, vc), vb, 45.0)
// if barstate.islast
//     label.new(bar_index+int(vc.x), vc.y, vc.to_string())
//     for _d = 0 to 360 by 20
//         vd = rotate(array.from(va, vb), vc, _d)
//         line.new(bar_index+int(vd.get(0).x), vd.get(0).y, bar_index+int(vd.get(1).x), vd.get(1).y)

// }
// scale    () {

// @function Scale Array vectors based on a origin vector perspective.
// @param vectors array<Vector2.Vector2>, ID of the vector2 array.
// @param center  Vector2.Vector2       , Vector2 object. Origin center of the transformation.
// @param rate    float                 , Rate to apply transformation.
// @returns rotated points array.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = scale(array.from(a, b, c), b, 1.25)`
export method scale (array<TMath.Vector2> vectors, TMath.Vector2 center, float rate) =>
    array<TMath.Vector2> _vectors = array.new<TMath.Vector2>(0, Vector2.from(0.0))
    for _oldvector in vectors
        // Vector2.Vector2 _newvector = add(center, scale(subtract(_oldvector, center), 1.0 + rate))
        TMath.Vector2 _newvector = Vector2.new(center.x + (_oldvector.x - center.x) * (1.0 + rate), center.y + (_oldvector.y - center.y) * (1.0 + rate))
        array.push(_vectors, _newvector)
    _vectors

// TEST: 20230221 RS
// float _r = input.float(0.0, step=0.05)
// if barstate.islast
//     _a = Vector2.new(bar_index + 000.0, 000.0)
//     _b = Vector2.new(bar_index + 100.0, 100.0)
//     _c = Vector2.new(bar_index + 150.0, 050.0)
//     _center = Vector2.new(bar_index + 100.0, 050.0)
//     _before = array.from(_a, _b, _c)
//     line.new(int(_before.get(0).x), _before.get(0).y, int(_before.get(1).x), _before.get(1).y)
//     line.new(int(_before.get(1).x), _before.get(1).y, int(_before.get(2).x), _before.get(2).y)
//     _after = _before.scale(_center, _r)
//     line.new(int(_after.get(0).x), _after.get(0).y, int(_after.get(1).x), _after.get(1).y)
//     line.new(int(_after.get(1).x), _after.get(1).y, int(_after.get(2).x), _after.get(2).y)

// }
// move     () {

// @function Move Array vectors by a rate of the distance to center position (LERP).
// @param vectors array<Vector2.Vector2>, ID of the vector2 array.
// @param value   Vector2.Vector2       , Vector2 object. Value of the transformation.
// @returns Moved points array.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = move(array.from(a, b, c), b, 1.25)`
export method move (array<TMath.Vector2> vectors, TMath.Vector2 center, float rate) =>
    array<TMath.Vector2> _vectors = array.new<TMath.Vector2>(0, Vector2.from(0.0))
    for _oldvector in vectors
        // Vector2.Vector2 _newvector = add(center, scale(subtract(_oldvector, center), 1.0 + rate))
        TMath.Vector2 _newvector = Vector2.new(center.x + (_oldvector.x - center.x) * (1.0 + rate), center.y + (_oldvector.y - center.y) * (1.0 + rate))
        array.push(_vectors, _newvector)
    _vectors

// TEST: 20230221 RS
// float _r = input.float(0.0, step=0.05)
// _center = Vector2.from(input.string('100,50'))
// _center.x += bar_index
// if barstate.islast
//     _a = Vector2.new(bar_index + 000.0, 000.0)
//     _b = Vector2.new(bar_index + 100.0, 100.0)
//     _c = Vector2.new(bar_index + 150.0, 050.0)
//     _before = array.from(_a, _b, _c)
//     line.new(int(_before.get(0).x), _before.get(0).y, int(_before.get(1).x), _before.get(1).y)
//     line.new(int(_before.get(1).x), _before.get(1).y, int(_before.get(2).x), _before.get(2).y)
//     _after = _before.move(_center, _r)
//     line.new(int(_after.get(0).x), _after.get(0).y, int(_after.get(1).x), _after.get(1).y)
//     line.new(int(_after.get(1).x), _after.get(1).y, int(_after.get(2).x), _after.get(2).y)

// }



//#region ~~~ ~~~ Translate:

// to_string () {

// @function Reads a array of vectors into a string, of the form `[ (x, y), ... ]`.
// @param id array<Vector2.Vector2>, ID of the vector2 array.
// @param separator string separator for cell splitting.
// @returns string Translated complex array into string.
// -> usage:
//      `a = Vector2.from(1.0) , b = Vector2.from(2.0), c = Vector2.from(3.0), d = to_string(array.from(a, b, c))`
export to_string (array<TMath.Vector2> id, string separator='') =>
    string _separator = na(separator) ? ', ' : separator
    string _str = '[ '
    for _e in id
        _str += Vector2.to_string(_e) + _separator
    int _size = str.length(_str)
    if _size > 2
        str.substring(_str, 0, _size - 2) + ' ]'
    else
        _str + ' ]'

// }
// to_string () {

// @function Reads a array of vectors into a string, of the form `[ (x, y), ... ]`.
// @param id        array<Vector2.Vector2>, ID of the vector2 array.
// @param format    string   , Format to apply transformation.
// @param separator string   , Separator for cell splitting.
// @returns string Translated complex array into string.
// -> usage:
//      `a = Vector2.from(1.234) , b = Vector2.from(2.23), c = Vector2.from(3.1234), d = to_string(array.from(a, b, c), "#.##")`
export to_string (array<TMath.Vector2> id, string format, string separator = '') =>
    string _separator = na(separator) ? ', ' : separator
    string _str = '[ '
    for _e in id
        _str += Vector2.to_string(_e, format) + _separator
    int _size = str.length(_str)
    if _size > 2
        str.substring(_str, 0, _size - 2) + ' ]'
    else
        _str + ' ]'

// }

//#endregion

//#endregion



// rotation = input(0)
// origin = input(0.0)
// triangle_scale = input(0.0)
// if barstate.ishistory[1] and (barstate.isrealtime or barstate.islast)
//     TMath.Vector2 a = Vector2.new(0.10, -0.25)
//     TMath.Vector2 b = Vector2.new(0.66, float(na))
//     TMath.Vector2 c = Vector2.add(a, Vector2.one())
//     TMath.Vector2 d = Vector2.subtract(c, Vector2.one())

//     array<TMath.Vector2> L = array.new<TMath.Vector2>(4, Vector2.new(0, 0))
//     array.set(L, 0, a)
//     array.set(L, 1, b)
//     array.set(L, 2, c)
//     array.set(L, 3, d)

//     _text = ''
//     _text := _text + 'Array Methods:\n'
//     _text := _text + 'array L: ' + to_string(L, string(na)) + '\n'
//     _text := _text + 'center of L: ' + Vector2.to_string(center(L)) + '\n'
//     array.unshift(L, Vector2.from(1.111))
//     array.push(L, Vector2.from(2.222))
//     _text := _text + 'Sum of L: ' + Vector2.to_string(sum(L)) + '\n'
//     _text := _text + 'Top of L: ' + Vector2.to_string(max(L)) + '\n'
//     _text := _text + 'Bottom of L: ' + Vector2.to_string(min(L)) + '\n'

//     array<TMath.Vector2> _triangle = array.new<TMath.Vector2>(3, Vector2.from(0.0))
//     array.set(_triangle, 1, Vector2.from(bar_index/2))
//     array.set(_triangle, 2, Vector2.new(bar_index/2, 0.0))
//     array<TMath.Vector2> _new_triangle = scale(_triangle, Vector2.from(origin), triangle_scale)
//     T = table.new(position.bottom_right, 1, 1, #000000)
//     table.cell(T, 0, 0, _text, text_color = #ffffff, text_size = size.small)

// console.update(__T, __C)
