lib_drawing_composites
// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © robbatt, extending Trendoscope's https://www.tradingview.com/script/eNM7BFaR-DrawingMethods/

//@version=5
//@description methods to draw and manage composite obejects. Based on Trendoscope's https://www.tradingview.com/script/eNM7BFaR-DrawingMethods/, added Triangle and Polygon composite objects, fixed tostring method output to be actual json
library("lib_drawing_composites", overlay = true)
import HeWhoMustNotBeNamed/DrawingTypes/2 as D
import HeWhoMustNotBeNamed/DrawingMethods/2
import robbatt/lib_drawing_composite_types/1 as DC


//******************************************************************* json *******************************************************/

// @function Converts lib_drawing_types/Point object to a json string representation
// @param this lib_drawing_types/Point object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Point
export method tostring(D.Point this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 (format_date ?
	 str.format('{0}{1}"bar": {2},{0}{1}"bartime": "{3}",{0}{1}"price": {4}{0}', separator, tab, this.bar, str.format_time(this.bartime, format, tz), this.price) :
	 str.format('{0}{1}"bar": {2},{0}{1}"bartime": {3},{0}{1}"price": {4}{0}', separator, tab, this.bar, this.bartime, this.price)
	 ) + '}'

// @function Converts lib_drawing_types/LineProperties object to a json string representation
// @param this lib_drawing_types/LineProperties object
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/LineProperties
export method tostring(D.LineProperties this, simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + str.format('{0}{1}"xloc": "{2}",{0}{1}"extend": "{3}",{0}{1}"style": "{4}",{0}{1}"width": {5}{0}', separator, tab, this.xloc, this.extend, this.style, this.width) + '}'


// @function Converts lib_drawing_types/Line object to a json string representation
// @param this lib_drawing_types/Line object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @returns string representation of lib_drawing_types/Line
export method tostring(D.Line this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"start": {2},{0}{1}"end": {3},{0}{1}"properties": {4}{0}', separator, tab,
	 this.start.tostring(format_date, format, tz, pretty), 
	 this.end.tostring(format_date, format, tz, pretty), 
	 this.properties.tostring(pretty)
	 ) + '}'

// @function Converts lib_drawing_types/LabelProperties object to a json string representation
// @param this lib_drawing_types/LabelProperties object
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/LabelProperties
export method tostring(D.LabelProperties this, simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
     str.format('{0}{1}"xloc": "{2}",{0}{1}"yloc": "{3}",{0}{1}"style": "{4}",{0}{1}"size": "{5}",{0}{1}"textalign": "{6}",{0}{1}"text_font_family": "{7}"{0}', separator, tab, this.xloc, this.yloc, this.style, this.size, this.textalign, this.text_font_family )
	 + '}'


// @function Converts lib_drawing_types/Label object to a json string representation
// @param this lib_drawing_types/Label object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Label
export method tostring(D.Label this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"point": {2},{0}{1}"labeltext": "{3}",{0}{1}"tooltip": "{4}",{0}{1}"properties": {5}{0}', separator, tab,
	 this.point.tostring(format_date, format, tz, pretty), 
	 this.lblText,
	 this.tooltip, 
	 this.properties.tostring(pretty)
	 ) + '}'


// @function Converts lib_drawing_types/Linefill object to a json string representation
// @param this lib_drawing_types/Linefill object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Linefill
export method tostring(D.Linefill this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'':'{' + 
	 str.format('{0}{1}"line1": {2},{0}{1}"line2": {3},{0}{1}"transparency": {4}{0}', separator, tab,
	 this.line1.tostring(format_date, format, tz, pretty), 
	 this.line2.tostring(format_date, format, tz, pretty), 
	 this.transparency
	 ) + '}'
	

// @function Converts lib_drawing_types/BoxProperties object to a json string representation
// @param this lib_drawing_types/BoxProperties object
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/BoxProperties
export method tostring(D.BoxProperties this, simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"border_width": {2},{0}{1}"border_style": "{3}",{0}{1}"extend": "{4}",{0}{1}"xloc": "{5}"{0}', separator, tab,
	 this.border_width, 
	 this.border_style, 
	 this.extend,
	 this.xloc
	 ) + '}'


// @function Converts lib_drawing_types/BoxText object to a json string representation
// @param this lib_drawing_types/BoxText object
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/BoxText
export method tostring(D.BoxText this, simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"boxText": "{2}",{0}{1}"text_size": "{3}",{0}{1}"text_halign": "{4}",{0}{1}"text_valign": "{5}",{0}{1}"text_wrap": "{6}",{0}{1}"text_font_family": "{7}"{0}', separator, tab,
	 this.boxText, 
	 this.text_size, 
	 this.text_valign, 
	 this.text_wrap, 
	 this.text_font_family
	 ) + '}'

// @function Converts lib_drawing_types/Box object to a json string representation
// @param this lib_drawing_types/Box object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Box
export method tostring(D.Box this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"p1": {2},{0}{1}"p2": {3},{0}{1}"properties": {4},{0}{1}"text_properties": {5}{0}', separator, tab,
	 this.p1.tostring(format_date, format, tz, pretty), 
	 this.p2.tostring(format_date, format, tz, pretty), 
	 this.properties.tostring(pretty),
	 this.textProperties.tostring(pretty)
	 ) + '}'


// @function Converts lib_drawing_types/TriangleProperties object to a json string representation
// @param this lib_drawing_types/TriangleProperties object
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/TriangleProperties
export method tostring(DC.TriangleProperties this, simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' +
	 str.format('{0}{1}"fill_transparency": {2},{0}{1}"border_width": {3},{0}{1}"border_style": "{4}",{0}{1}"xloc": "{5}"{0}', separator, tab,
	 this.fill_transparency,
	 this.border_width,
	 this.border_style,
	 this.xloc
	 ) + '}'


// @function Converts lib_drawing_types/Triangle object to a json string representation
// @param this lib_drawing_types/Triangle object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Triangle
export method tostring(DC.Triangle this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"p1": {2},{0}{1}"p2": {3},{0}{1}"p3": {4},{0}{1}"properties": {5},{0}', separator, tab,
	 this.p1.tostring(format_date, format, tz, pretty), 
	 this.p2.tostring(format_date, format, tz, pretty), 
	 this.p3.tostring(format_date, format, tz, pretty), 
	 this.properties.tostring(pretty)
	 ) + '}'

	

// @function Converts lib_drawing_types/Trianglefill object to a json string representation
// @param this lib_drawing_types/Trianglefill object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/TriangleProperties
export method tostring(DC.Trianglefill this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	var separator = pretty?'\n':' '
	var tab = pretty?' ':''
	na(this)?'null':'{' + 
	 str.format('{0}{1}"triangle": {2},{0}{1}"transparency": {3}{0}', separator, tab,
	 this.triangle.tostring(format_date, format, tz, pretty),
	 this.transparency
	 ) + '}'



// @function Converts a Polygon object to a json string representation
// @param this Polygon object array
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of Pivot object array
export method tostring(DC.Polygon this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
    if na(this)
		'null'
	else if na(this.triangles)
		'null'
	else
    	array<string> combinedStr = array.new<string>()
        for triangle in this.triangles
            combinedStr.push(triangle.tostring(format_date, format, tz, pretty))
    	'['+array.join(combinedStr, ",")+']'


// @function Converts lib_drawing_types/Polygonfill object to a json string representation
// @param this lib_drawing_types/Polygonfill object
// @param format_date whether to format the bartime integer (unix timestamp) into a human readable format
// @param format the format for bartime (default: "yyyy-MM-dd HH:mm")
// @param tz the timezone for bartime, e.g. 'UTC+1' (default: exchange time zone)
// @param pretty if true adds a line feed after every property and a space before properties (default: true)
// @returns string representation of lib_drawing_types/Polygonfill
export method tostring(DC.Polygonfill this, simple bool format_date = true, simple string format = "yyyy-MM-dd HH:mm", simple string tz = 'UTC', simple bool pretty = false)=>
	if na(this)
		'null'
	else if na(this._fills)
		'null'
	else
    	array<string> combinedStr = array.new<string>()
        for fill in this._fills
            combinedStr.push(fill.tostring(format_date, format, tz, pretty))
    	'['+array.join(combinedStr, ",")+']'


//******************************************************************* delete and clear *******************************************************/
deleteObj(this)=>
	this.object.delete()
	this

// @function Deletes Trianglefill from lib_drawing_types/Trianglefill object
// @param this lib_drawing_types/Trianglefill object
// @returns Trianglefill object deleted
export method delete(DC.Trianglefill this)=>deleteObj(this)

// @function Deletes Triangle from lib_drawing_types/Triangle object
// @param this lib_drawing_types/Triangle object
// @returns Triangle object deleted
export method delete(DC.Triangle this)=>
	this.l12.delete()
	this.l23.delete()
	this.l31.delete()
	this


deleteAll(this)=>
	if(not na(this))
		for obj in this
			obj.delete()
	this

// @function Deletes Triangle from array of lib_drawing_types/Triangle objects
// @param this Array of lib_drawing_types/Triangle objects
// @returns Array of lib_drawing_types/Triangle objects
export method delete(array<DC.Triangle> this)=>deleteAll(this)

// @function Deletes Trianglefill from array of lib_drawing_types/Trianglefill objects
// @param this Array of lib_drawing_types/Trianglefill objects
// @returns Array of lib_drawing_types/Trianglefill objects
export method delete(array<DC.Trianglefill> this)=>deleteAll(this)

// @function Deletes Triangle from lib_drawing_types/Triangle object
// @param this lib_drawing_types/Triangle object
// @returns Triangle object deleted
export method delete(DC.Polygon this)=>deleteAll(this.triangles)

// @function Deletes Polygonfill from lib_drawing_types/Polygonfill object
// @param this lib_drawing_types/Polygonfill object
// @returns Polygonfill object deleted
export method delete(DC.Polygonfill this)=>deleteAll(this._fills)

// @function Deletes Polygon from array of lib_drawing_types/Polygon objects
// @param this Array of lib_drawing_types/Polygon objects
// @returns Array of lib_drawing_types/Polygon objects
export method delete(array<DC.Polygon> this)=>
	if not na(this)
		for p in this
			p.delete()

// @function Deletes Polygonfill from array of lib_drawing_types/Polygonfill objects
// @param this Array of lib_drawing_types/Polygonfill objects
// @returns Array of lib_drawing_types/Polygonfill objects
export method delete(array<DC.Polygonfill> this)=>
	if not na(this)
		for p in this
			p.delete()


// @function clear items from array of lib_drawing_types/Triangle while deleting underlying objects
// @param this array<lib_drawing_types/Triangle>
// @returns void
export method clear(array<DC.Triangle> this)=>this.delete().clear()

// @function clear items from array of lib_drawing_types/Trianglefill while deleting underlying objects
// @param this array<lib_drawing_types/Trianglefill>
// @returns void
export method clear(array<DC.Trianglefill> this)=>this.delete().clear()

// @function clear items from array of lib_drawing_types/Polygon while deleting underlying objects
// @param this array<lib_drawing_types/Polygon>
// @returns void
export method clear(array<DC.Polygon> this)=>this.delete().clear()

// @function clear items from array of lib_drawing_types/Polygonfill while deleting underlying objects
// @param this array<lib_drawing_types/Polygonfill>
// @returns void
export method clear(array<DC.Polygonfill> this)=>this.delete().clear()

//******************************************************************* draw *******************************************************/



// @function Creates Triangle object from lib_drawing_types/Triangle
// @param this lib_drawing_types/Triangle objects
// @returns Triangle object created
export method draw(DC.Triangle this, bool is_polygon_section = false)=>
	this.l12.delete()
	this.l23.delete()
	this.l31.delete()	
	this.properties := na(this.properties)? DC.TriangleProperties.new() : this.properties

	if(not na(this.p1) and not na(this.p2) and not na(this.p3))
		x1 = this.properties.xloc == xloc.bar_index ? this.p1.bar : this.p1.bartime
		x2 = this.properties.xloc == xloc.bar_index ? this.p2.bar : this.p2.bartime
		x3 = this.properties.xloc == xloc.bar_index ? this.p3.bar : this.p3.bartime

		this.l23 := line.new(x2, this.p2.price, x3, this.p3.price, this.properties.xloc, style = this.properties.border_style, width = this.properties.border_width, color = this.properties.border_color)
		this.l12 := line.new(x1, this.p1.price, x2, this.p2.price, this.properties.xloc, style = this.properties.border_style, width = this.properties.border_width, color = is_polygon_section ? #00000000 :this.properties.border_color)
		this.l31 := line.new(x1, this.p1.price, x3, this.p3.price, this.properties.xloc, style = this.properties.border_style, width = this.properties.border_width, color = is_polygon_section ? #00000000 :this.properties.border_color)
	this

// @function Creates Trianglefill object from lib_drawing_types/Trianglefill
// @param this lib_drawing_types/Trianglefill objects
// @returns Trianglefill object created
export method draw(DC.Trianglefill this)=>
	this.object.delete()
	if not na(this.triangle)
		this.object := linefill.new(this.triangle.l12, this.triangle.l31, color.new(this.fill_color, this.transparency))
	this



// @function Creates Triangles from array of lib_drawing_types/Triangle objects
// @param this Array of lib_drawing_types/Triangle objects
// @returns Array of lib_drawing_types/Triangle objects
export method draw(array<DC.Triangle> this, bool is_polygon = false)=>
	if not na(this)
		for t in this
			t.draw(is_polygon)
	this


// @function Creates Polygon object from lib_drawing_types/Polygon
// @param this lib_drawing_types/Polygon objects
// @returns Polygon object
export method draw(DC.Polygon this)=>
	draw(this.triangles, is_polygon = true)
	this


drawAll(this)=>
	if(not na(this))
		for obj in this
			obj.draw()
	this

// @function Creates Trianglefill from array of lib_drawing_types/Trianglefill objects
// @param this Array of lib_drawing_types/Trianglefill objects
// @returns Array of lib_drawing_types/Trianglefill objects
export method draw(array<DC.Trianglefill> this)=>
	if not na(this)
		for f in this
			f.draw()

// @function Creates Polygonfill object from lib_drawing_types/Polygonfill
// @param this lib_drawing_types/Polygonfill objects
// @returns Polygonfill object
export method draw(DC.Polygonfill this)=>
	draw(this._fills)
	this


// @function Creates Polygons from array of lib_drawing_types/Polygon objects
// @param this Array of lib_drawing_types/Polygon objects
// @returns Array of lib_drawing_types/Polygon objects
export method draw(array<DC.Polygon> this)=>
	if not na(this)
		for p in this
			p.draw()
	this


// @function Creates Polygonfills from array of lib_drawing_types/Polygonfill objects
// @param this Array of lib_drawing_types/Polygonfill objects
// @returns Array of lib_drawing_types/Polygonfill objects
export method draw(array<DC.Polygonfill> this)=>
	if not na(this)
		for pf in this
			pf._fills.draw()
	this


//******************************************************************* createXXX *******************************************************/

// @function Creates centered lib_drawing_types/Point object between two lib_drawing_types/Points
// @param this lib_drawing_types/Point object
// @param other lib_drawing_types/Point object
// @returns lib_drawing_types/Label object
export method createCenter(D.Point this, D.Point other)=>
	t_center = int(math.avg(this.bartime, other.bartime))
	b_center = int(math.avg(this.bar, other.bar))
	p_center = other.price + (this.price - other.price) * (b_center - other.bar) / (this.bar - other.bar) 
	D.Point.new(p_center, b_center, t_center)

// @function Creates centered lib_drawing_types/Point object between an array of given Points
// @param this lib_drawing_types/Point objects
// @param other1 lib_drawing_types/Point object
// @param other2 lib_drawing_types/Point object
// @returns lib_drawing_types/Point object
export method createCenter(array<D.Point> this)=>
	t_center = 0.0	
	b_center = 0.0
	p_center = 0.0
	for point in this
		t_center += point.bartime
		b_center += point.bar
		p_center += point.price
	count = this.size()
	t_center /= count
	b_center /= count
	p_center /= count
	D.Point.new(p_center, int(b_center), int(t_center))

// @function Creates centered lib_drawing_types/Point object between three lib_drawing_types/Points
// @param this lib_drawing_types/Point object
// @param other1 lib_drawing_types/Point object
// @param other2 lib_drawing_types/Point object
// @returns lib_drawing_types/Point object
export method createCenter(D.Point this, D.Point other1, D.Point other2)=>
	array.from(this, other1, other2).createCenter()	
// @function Creates lib_drawing_types/Label centered between lib_drawing_types/Line endpoints, using bar_index for calculation
// @param this lib_drawing_types/Line object
// @param labeltext Label text
// @param tooltip Tooltip text. Default is na
// @param properties lib_drawing_types/LabelProperties object. Default is na - meaning default values are used.
// @returns lib_drawing_types/Label object
export method createLabel(D.Line this, string labeltext, string tooltip=na, D.LabelProperties properties=na)=>
	D.Label.new(this.start.createCenter(this.end), labeltext, tooltip, na(properties)?D.LabelProperties.new():properties)


// @function Creates lib_drawing_types/Label centered between lib_drawing_types/Line endpoints, using bar_index for calculation
// @param this lib_drawing_types/Line object
// @param labeltext Label text
// @param tooltip Tooltip text. Default is na
// @param properties lib_drawing_types/LabelProperties object. Default is na - meaning default values are used.
// @returns lib_drawing_types/Label object
export method createLabel(DC.Triangle this, string labeltext, string tooltip=na, D.LabelProperties properties=na)=>
	D.Label.new(this.p1.createCenter(this.p2, this.p3), labeltext, tooltip, na(properties)?D.LabelProperties.new():properties)


// @function Creates lib_drawing_types/Line object from one lib_drawing_types/Point to other
// @param this First lib_drawing_types/Point object
// @param other Second lib_drawing_types/Point object
// @param properties lib_drawing_types/LineProperties object. Default set to na - meaning default values are used.
// @returns lib_drawing_types/Line object
export method createTriangle(D.Point this, D.Point p2, D.Point p3, DC.TriangleProperties properties = na)=>
	DC.Triangle.new(this, p2, p3, na(properties)? DC.TriangleProperties.new():properties)


// @function Creates lib_drawing_types/Trianglefill object from lib_drawing_types/Triangle object
// @param this lib_drawing_types/Trianglefill object
// @param fill_color fill color of linefill. Default is color.blue
// @param transparency fill transparency for linefill. Default is 80
// @returns Array of lib_drawing_types/Linefill object
export method createTrianglefill(DC.Triangle this, color fill_color=chart.fg_color, int transparency=93)=>
	DC.Trianglefill.new(this, fill_color, transparency)


// @function Creates lib_drawing_types/Polygonfill object from lib_drawing_types/Polygon object
// @param this lib_drawing_types/Polygon object
// @param fill_color fill color of linefill. Default is chart.fg_color
// @param transparency fill transparency for Polygonfill. Default is 93
// @returns a lib_drawing_types/Polygonfill object
export method createPolygonfill(DC.Polygon this, color fill_color=chart.fg_color, int transparency=93)=>
	if na(this.triangles)
		na
	else
		fills = array.new<DC.Trianglefill>(this.triangles.size())
		for [i, triangle] in this.triangles
			fills.set(i, DC.Trianglefill.new(triangle, fill_color, transparency))
		DC.Polygonfill.new(this, fills)


// @function Creates lib_drawing_types/Line object from one lib_drawing_types/Point to other
// @param this First lib_drawing_types/Point object
// @param other Second lib_drawing_types/Point object
// @param properties lib_drawing_types/LineProperties object. Default set to na - meaning default values are used.
// @returns lib_drawing_types/Line object
export method createPolygon(array<D.Point> points, DC.TriangleProperties properties)=>
	if na(points)
		DC.Polygon.new(na, array.new<DC.Triangle>())
	else if points.size() < 3
		DC.Polygon.new(na, array.new<DC.Triangle>())
	else
		count = points.size()
		maxIdx = count-1
		center = points.createCenter()
		triangles = array.new<DC.Triangle>(count, center.createTriangle(points.get(0), points.get(maxIdx), properties))
		for i = 1 to maxIdx
			triangles.set(i, center.createTriangle(points.get(i-1), points.get(i), properties))
		DC.Polygon.new(center, triangles)
	


// ###################################################################### Tests #############################################################
import robbatt/lib_log/6
var l = lib_log.Logger.new(min_level = 1, color_logs = true)

hh = ta.highest(high, 15)
hh_bars = ta.highestbars(high, 15)
hh_bar = bar_index[-hh_bars]
hh_time = time[-hh_bars]
l.debug(str.format('hh - bar: {0}, price: {1}', hh_bar, hh))

ll = ta.lowest(low, 15)
ll_bars = ta.lowestbars(low, 15)
ll_bar = bar_index[-ll_bars]
ll_time = time[-ll_bars]
l.debug(str.format('ll - bar: {0}, price: {1}', ll_bar, ll))

if barstate.islast
	D.Point p1 = D.Point.new (high, bar_index, time)
	D.Point p2 = D.Point.new (high[10], bar_index[10], time[10])
	D.Point p3 = D.Point.new (high[15], bar_index[15], time[15])
	D.Point p4 = D.Point.new (high[21], bar_index[21], time[21])
	D.Point phh = D.Point.new(hh, hh_bar, hh_time)
	D.Point pll = D.Point.new(ll, ll_bar, ll_time)
	l.debug(p1.tostring())

	D.LabelProperties l_props_up = D.LabelProperties.new(xloc = xloc.bar_index, color = chart.bg_color, textcolor = chart.fg_color, style = label.style_label_up)
	D.LabelProperties l_props_down = D.LabelProperties.new(xloc = xloc.bar_index, color = chart.bg_color, textcolor = chart.fg_color, style = label.style_label_down)
	D.LabelProperties l_props_center = D.LabelProperties.new(xloc = xloc.bar_index, color = chart.bg_color, textcolor = chart.fg_color, style = label.style_label_center)

	D.Label lp1 = p1.createLabel('p1', properties = l_props_down)
	lp1.draw()
	D.Label lp2 = p2.createLabel('p2', properties = l_props_down)
	lp2.draw()
	D.Label lp3 = p3.createLabel('p3', properties = l_props_down)
	lp3.draw()
	D.Label lp4 = p4.createLabel('p4', properties = l_props_down)
	lp4.draw()
	D.Label lphh = phh.createLabel('HH', properties = l_props_down)
	lphh.draw()
	D.Label lpll = pll.createLabel('LL', properties = l_props_up)
	lpll.draw()

	l.debug(lp1.tostring())

	D.Line ln = p1.createLine(p2)
	ln.draw()
	l.debug(ln.tostring())

	D.Line ln2 = D.Line.new(D.Point.new(low, bar_index, time), D.Point.new(low, bar_index[10], time[10]))
	ln2.draw()

	D.Linefill lf = ln.createLinefill(ln2)
	lf.draw()
	l.debug(lf.tostring())

	D.BoxText textProps = D.BoxText.new('This is my box')
	D.Box bx = p2.createBox(p3, textProperties = textProps)
	bx.draw()
	
	D.Point c = p4.createCenter(p3)
	D.Line lc = p4.createLine(p3)
	lc.draw()
	D.Label cl = c.createLabel('center point', properties = l_props_down)
	cl.draw()
	D.Line lc1 = c.createLine(p3)
	lc1.draw()
	D.Line lc2 = c.createLine(p4)
	lc2.draw()
	D.Label cl2 = lc.createLabel('line center', properties = l_props_center)
	cl2.draw()
	
	DC.Triangle t = p4.createTriangle(p3, phh)
	t.draw()
	D.Label tl = t.createLabel('triangle center', properties = l_props_center)
	tl.draw()
	DC.Trianglefill tf = t.createTrianglefill()
	tf.draw()
	l.debug(str.format('x1 {0} y1 {1} x2 {2} y2 {3} | x1 {4} y1 {5} x2 {6} y2 {7}', tf.object.get_line1().get_x1(),	tf.object.get_line1().get_y1(),	tf.object.get_line1().get_x2(),	tf.object.get_line1().get_y2(),	tf.object.get_line2().get_x1(),	tf.object.get_line2().get_y1(),	tf.object.get_line2().get_x2(),	tf.object.get_line2().get_y2()))

	DC.TriangleProperties polygon_props = DC.TriangleProperties.new(color.red, color.red)
	D.Point[] polygonPoints = array.from(p1, phh, p3, pll)
	DC.Polygon p = polygonPoints.createPolygon(polygon_props)
	p.draw()
	D.Point pcenter = polygonPoints.createCenter()
	D.Label lpc = pcenter.createLabel('poly center', properties = l_props_center)
	lpc.draw()
	DC.Polygonfill pf = p.createPolygonfill(fill_color = color.blue, transparency = 93)
	pf.draw()

// if barstate.isfirst
// 	label.new(bar_index, close, 'mandatory showcase')


