diff --git a/build_library.sh b/build_library.sh index f283f09..6291c87 100755 --- a/build_library.sh +++ b/build_library.sh @@ -1,4 +1,16 @@ #!/bin/zsh -# Concatenate all Lua files in the current directory into one +# Concatenate all Lua files in the current directory into one except for builtins. -find . -name '*.lua' -not -name 'library.lua' -exec sh -c 'cat {} && echo && echo' \; > library.lua \ No newline at end of file +temp_file="temp_library.lua" + +# Add the top content +echo "-- SCROLL TO BOTTOM ----------------------------------------------------\n" > "$temp_file" + +# Concatenate the Lua files +find . -name '*.lua' -not -name 'library.lua' -not -name 'builtins.lua' -not -name 'temp_library.lua' -exec sh -c 'cat {} && echo && echo' \; >> "$temp_file" + +# Add the bottom content +echo -e "-- AUDULUS-CANVAS LIBRARY ----------------------------------------------\n\n----- Instructions -----\n-- 1. Create 'Time' input (case-sensitive)\n-- 2. Attach Timer node to the 'Time' input\n-- 3. Select 'Save Data' at the bottom of the inspector panel\n-- 4. Set a custom W(idth) and H(eight) in the inspector panel\n-- 5. Write your code below this line\n\n-- CODE ----------------------------------------------------------------\n\n\n\n\n\n-- PRINT CONSOLE -------------------------------------------------------\n\nprint_all()" >> "$temp_file" + +# Rename the temporary file to library.lua +mv "$temp_file" "library.lua" diff --git a/config.ld b/config.ld deleted file mode 100644 index e69de29..0000000 diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index 245b534..0000000 --- a/doc/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- - -

Audulus-Canvas Libraries v0.0.1-alpha

- -

Libraries

- - - - - - - - - -
colorFunctions and tables that create, translate, validate, and manipulate colors.
debugUseful debugging functions.
- -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 20:10:08 -
-
- - diff --git a/doc/ldoc_fixed.css b/doc/ldoc_fixed.css deleted file mode 100644 index d7c7a6e..0000000 --- a/doc/ldoc_fixed.css +++ /dev/null @@ -1,312 +0,0 @@ -/* BEGIN RESET - -Copyright (c) 2010, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.com/yui/license.html -version: 2.8.2r1 -*/ -html { - color: #000; - background: #FFF; -} -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { - margin: 0; - padding: 0; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -fieldset,img { - border: 0; -} -address,caption,cite,code,dfn,em,strong,th,var,optgroup { - font-style: inherit; - font-weight: inherit; -} -del,ins { - text-decoration: none; -} -li { - margin-left: 20px; -} -caption,th { - text-align: left; -} -h1,h2,h3,h4,h5,h6 { - font-size: 100%; - font-weight: bold; -} -q:before,q:after { - content: ''; -} -abbr,acronym { - border: 0; - font-variant: normal; -} -sup { - vertical-align: baseline; -} -sub { - vertical-align: baseline; -} -legend { - color: #000; -} -input,button,textarea,select,optgroup,option { - font-family: inherit; - font-size: inherit; - font-style: inherit; - font-weight: inherit; -} -input,button,textarea,select {*font-size:100%; -} -/* END RESET */ - -body { - margin-left: 1em; - margin-right: 1em; - font-family: arial, helvetica, geneva, sans-serif; - background-color: #ffffff; margin: 0px; -} - -code, tt { font-family: monospace; font-size: 1.1em; } -span.parameter { font-family:monospace; } -span.parameter:after { content:":"; } -span.types:before { content:"("; } -span.types:after { content:")"; } -.type { font-weight: bold; font-style:italic } - -body, p, td, th { font-size: .95em; line-height: 1.2em;} - -p, ul { margin: 10px 0 0 0px;} - -strong { font-weight: bold;} - -em { font-style: italic;} - -h1 { - font-size: 1.5em; - margin: 0 0 20px 0; -} -h2, h3, h4 { margin: 15px 0 10px 0; } -h2 { font-size: 1.25em; } -h3 { font-size: 1.15em; } -h4 { font-size: 1.06em; } - -a:link { font-weight: bold; color: #004080; text-decoration: none; } -a:visited { font-weight: bold; color: #006699; text-decoration: none; } -a:link:hover { text-decoration: underline; } - -hr { - color:#cccccc; - background: #00007f; - height: 1px; -} - -blockquote { margin-left: 3em; } - -ul { list-style-type: disc; } - -p.name { - font-family: "Andale Mono", monospace; - padding-top: 1em; -} - -pre { - background-color: rgb(245, 245, 245); - border: 1px solid #C0C0C0; /* silver */ - padding: 10px; - margin: 10px 0 10px 0; - overflow: auto; - font-family: "Andale Mono", monospace; -} - -pre.example { - font-size: .85em; -} - -table.index { border: 1px #00007f; } -table.index td { text-align: left; vertical-align: top; } - -#container { - margin-left: 1em; - margin-right: 1em; - background-color: #ffffff; -} - -#product { - text-align: center; - border-bottom: 1px solid #cccccc; - background-color: #ffffff; -} - -#product big { - font-size: 2em; -} - -#main { - background-color:#FFFFFF; // #f0f0f0; - border-left: 1px solid #cccccc; -} - -#navigation { - position: fixed; - top: 0; - left: 0; - float: left; - width: 14em; - vertical-align: top; - background-color:#FFFFFF; // #f0f0f0; - border-right: 2px solid #cccccc; - overflow: visible; - overflow-y: scroll; - height: 100%; - padding-left: 1em; -} - -#navigation h2 { - background-color:#FFFFFF;//:#e7e7e7; - font-size:1.1em; - color:#000000; - text-align: left; - padding:0.2em; - border-bottom:1px solid #dddddd; -} - -#navigation ul -{ - font-size:1em; - list-style-type: none; - margin: 1px 1px 10px 1px; -} - -#navigation li { - text-indent: -1em; - display: block; - margin: 3px 0px 0px 22px; -} - -#navigation li li a { - margin: 0px 3px 0px -1em; -} - -#content { - margin-left: 14em; - padding: 1em; - padding-left: 2em; - width: 700px; - border-left: 2px solid #cccccc; - // border-right: 2px solid #cccccc; - background-color: #ffffff; -} - -#about { - clear: both; - padding-left: 1em; - margin-left: 14em; // avoid the damn sidebar! - border-top: 2px solid #cccccc; - border-left: 2px solid #cccccc; - background-color: #ffffff; -} - -@media print { - body { - font: 12pt "Times New Roman", "TimeNR", Times, serif; - } - a { font-weight: bold; color: #004080; text-decoration: underline; } - - #main { - background-color: #ffffff; - border-left: 0px; - } - - #container { - margin-left: 2%; - margin-right: 2%; - background-color: #ffffff; - } - - #content { - padding: 1em; - background-color: #ffffff; - } - - #navigation { - display: none; - } - pre.example { - font-family: "Andale Mono", monospace; - font-size: 10pt; - page-break-inside: avoid; - } -} - -table.module_list { - border-width: 1px; - border-style: solid; - border-color: #cccccc; - border-collapse: collapse; -} -table.module_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #cccccc; -} -table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; } -table.module_list td.summary { width: 100%; } - -table.function_list { - border-width: 1px; - border-style: solid; - border-color: #cccccc; - border-collapse: collapse; -} -table.function_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #cccccc; -} -table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; } -table.function_list td.summary { width: 100%; } - -dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} -dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} -dl.table h3, dl.function h3 {font-size: .95em;} - -ul.nowrap { - overflow:auto; - whitespace:nowrap; -} - -/* stop sublists from having initial vertical space */ -ul ul { margin-top: 0px; } -ol ul { margin-top: 0px; } -ol ol { margin-top: 0px; } -ul ol { margin-top: 0px; } - -/* make the target distinct; helps when we're navigating to a function */ -a:target + * { - background-color: #FF9; -} - - -/* styles for prettification of source */ -pre .comment { color: #558817; } -pre .constant { color: #a8660d; } -pre .escape { color: #844631; } -pre .keyword { color: #aa5050; font-weight: bold; } -pre .library { color: #0e7c6b; } -pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } -pre .string { color: #8080ff; } -pre .number { color: #f8660d; } -pre .function-name { color: #60447f; } -pre .operator { color: #2239a8; font-weight: bold; } -pre .preprocessor, pre .prepro { color: #a33243; } -pre .global { color: #800080; } -pre .user-keyword { color: #800080; } -pre .prompt { color: #558817; } -pre .url { color: #272fc2; text-decoration: underline; } - diff --git a/doc/libraries/color.color.html b/doc/libraries/color.color.html deleted file mode 100644 index dbdd553..0000000 --- a/doc/libraries/color.color.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module color.color

-

color library.

-

- This is the main module for color-related functionalities. - It encapsulates submodules like color.convert, color.tables, and color.validate.

- - - -
-
- - - - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 15:25:56 -
-
- - diff --git a/doc/libraries/color.convert.html b/doc/libraries/color.convert.html deleted file mode 100644 index fdf22fd..0000000 --- a/doc/libraries/color.convert.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module color.convert

-

Functions to convert various color types into one another

-

- - -

Functions

- - - - - -
hex_code_to_color (s)Converts a hex code string to a color table.
- -
-
- - -

Functions

- -
-
- - hex_code_to_color (s) -
-
- Converts a hex code string to a color table. - Takes a string representation of a CSS hex value and converts it into - an {r, g, b, a} color table. The function ignores the leading # - symbol if present and will parse a 3 (rgb), 4 (rgba), 6 (rrggbb), or - 8 (rrggbbaa) character-long hex value into a normalized (0 to 1) rgba - color table. Sets a to 1 if not present in the hex code. - - -

Parameters:

-
    -
  • s - string - A hex code formatted as #rgb, #rgba, #rrggbb, or - #rrggbbaa with or without the leading # symbol -
  • -
- -

Returns:

-
    - - table - A color table in the format {r, g, b, a} -
- -

Raises:

- ValueError if hex code is malformed - -

See also:

-
    -
- - -
-
- - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 15:25:56 -
-
- - diff --git a/doc/libraries/color.html b/doc/libraries/color.html deleted file mode 100644 index 80853c0..0000000 --- a/doc/libraries/color.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module color

-

Functions and tables that create, translate, validate, and manipulate colors.

-

- This is the main module for color-related functionalities. - It encapsulates submodules like color.convert, color.tables, and color.validate.

- - -

color.convert Functions

- - - - - -
hex_code_to_color (s)Converts a hex code string to a color table.
-

color.tables Functions

- - - - - -
htmlColorsAll of the named HTML colors.
-

color.validate Functions

- - - - - -
is_valid_hex_code (s)Checks if a CSS hex code is formatted properly.
- -
-
- - -

color.convert Functions

- -
-
- - hex_code_to_color (s) -
-
- Converts a hex code string to a color table. - Takes a string representation of a CSS hex value and converts it into - an `{r, g, b, a}` color table. The function ignores the leading # - symbol if present and will parse a 3 (rgb), 4 (rgba), 6 (rrggbb), or - 8 (rrggbbaa) character-long hex value into a normalized (0 to 1) rgba - color table. Sets a to 1 if not present in the hex code. - - -

Parameters:

-
    -
  • s - string - A hex code formatted as #rgb, #rgba, #rrggbb, or - #rrggbbaa with or without the leading # symbol -
  • -
- -

Returns:

-
    - - table - A color table in the format {r, g, b, a} -
- -

Raises:

- ValueError if hex code is malformed - - -

Usage:

-
    -
    white = hex_code_to_color("#FFF")
    -print(white) -- {1, 1, 1, 1}
    -
    -black = hex_code_to_color("000F")
    -print(black) -- {0, 0, 0, 1}
    -
    -orange = hex_code_to_color("#FFA500")
    -print(orange) -- {0.9450..., 0.7686..., 0.0588..., 1}
    -
    -blue_transparent = hex_code_to_color("0000FF33")
    -print(blue_transparent) -- {0, 0, 1, 0.2}
    -
    -malformed_hex = hex_code_to_color("#G09F3")
    --- ValueError: Not a valid hex code.
    -
- -
-
-

color.tables Functions

- -
-
- - htmlColors -
-
- All of the named HTML colors. - - -

Fields:

-
    -
  • colorname - {r, g, b, a} -
  • -
- - - - - -
-
-

color.validate Functions

- -
-
- - is_valid_hex_code (s) -
-
- Checks if a CSS hex code is formatted properly. - Uses character and length matching to assert that the hex code is - formatted correctly. Works for rgb, rgba, rrggbb, and rrggbbaa hex - codes. Outputs true if correct and false if malformed. - - -

Parameters:

-
    -
  • s - string - A hex code formatted as #rgb, #rgba, #rrggbb, or - #rrggbbaa with or without the leading # symbol -
  • -
- -

Returns:

-
    - - boolean - true if correctly formatted, false if not. -
- - - -

Usage:

-
    -
    print(is_valid_hex_code(FFF)) -- true
    -
    -print(is_valid_hex_code(#J37N)) -- false
    -
- -
-
- - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 20:10:08 -
-
- - diff --git a/doc/libraries/color.tables.html b/doc/libraries/color.tables.html deleted file mode 100644 index 408e8b2..0000000 --- a/doc/libraries/color.tables.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module color.tables

-

Tables of colors

-

- - -

Tables

- - - - - -
htmlColorsAll of the named HTML colors.
- -
-
- - -

Tables

- -
-
- - htmlColors -
-
- All of the named HTML colors. - - -

Fields:

-
    -
  • colorname - {r, g, b, a} -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 15:25:56 -
-
- - diff --git a/doc/libraries/color.validate.html b/doc/libraries/color.validate.html deleted file mode 100644 index 90b490e..0000000 --- a/doc/libraries/color.validate.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module color.validate

-

Functions to validate the form of color strings and numbers

-

- - -

Local Functions

- - - - - -
isValidHexCode (s)Checks if a CSS hex code is formatted properly.
- -
-
- - -

Local Functions

- -
-
- - isValidHexCode (s) -
-
- Checks if a CSS hex code is formatted properly. - Uses character and length matching to assert that the hex code is - formatted correctly. Works for rgb, rgba, rrggbb, and rrggbbaa hex - codes. Outputs true if correct and false if malformed. - - -

Parameters:

-
    -
  • s - string - A hex code formatted as #rgb, #rgba, #rrggbb, or - #rrggbbaa with or without the leading # symbol -
  • -
- -

Returns:

-
    - - boolean - true if correctly formatted, false if not. -
- - -

See also:

-
    -
- - -
-
- - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 15:25:56 -
-
- - diff --git a/doc/libraries/debug.html b/doc/libraries/debug.html deleted file mode 100644 index 9ae0eab..0000000 --- a/doc/libraries/debug.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Audulus-Canvas Docs - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module debug

-

Useful debugging functions.

-

- - -

Functions

- - - - - -
create_print_logger ()Returns a set of functions that together enable stdout-like printing.
- -
-
- - -

Functions

- -
-
- - create_print_logger () -
-
- Returns a set of functions that together enable stdout-like printing. - The built-in Lua print() function can't print anywhere in Audulus. This - function enables you to add in a stdout-like experience in Audulus. The - function creates two functions (normally named print and printAll) that - assist in printing variables beneath the Canvas node. print() will add a - variable or value to the print queue. Use print() just as you would in any - any other program. Then, call printAll() at the very end of your script to - display the print queue. Each print item is numbered in the order it was - called starting at 1. Additionally, displays the current memory usage. - - - -

Returns:

-
    -
  1. - function - add_to_queue Adds variable to print queue.
  2. -
  3. - function - print_queue Prints the queue beneath the Canvas node.
  4. -
- - - -

Usage:

-
    -
    print, printAll = create_print_logger()
    -
    -x = 1 + 1
    -print(x)
    -
    -color = {0.5, 0.75, 0.1, 1}
    -print(color)
    -
    -coordinate = {x = 1, y = 12}
    -print(coordinate)
    -
    -printAll()
    --- (Note: This appears below the Canvas node) --
    --- Memory usage (KB): 72
    --- Print Queue Output
    --- _________________
    --- 1. 2
    --- 2. {0.5, 0.75, 0.1, 1}
    --- 3. {x = 1, y = 12}
    -
- -
-
- - -
-
-
-generated by LDoc 1.5.0 -Last updated 2023-12-20 20:10:08 -
-
- - diff --git a/library.lua b/library.lua index 18db71d..13ed9a0 100644 --- a/library.lua +++ b/library.lua @@ -1,43 +1,22 @@ ---- Tables of colors --- @submodule color - ---- All of the named HTML colors. --- @table htmlColors --- @field colorname {r, g, b, a} -htmlColors = { indianred = { 205, 92, 92, 1 }, lightcoral = { 240, 128, 128, 1 }, salmon = { 250, 128, 114, 1 }, darksalmon = { 233, 150, 122, 1 }, lightsalmon = { 255, 160, 122, 1 }, crimson = { 220, 20, 60, 1 }, red = { 255, 0, 0, 1 }, firebrick = { 178, 34, 34, 1 }, darkred = { 139, 0, 0, 1 }, pink = { 255, 192, 203, 1 }, lightpink = { 255, 182, 193, 1 }, hotpink = { 255, 105, 180, 1 }, deeppink = { 255, 20, 147, 1 }, mediumvioletred = { 199, 21, 133, 1 }, palevioletred = { 219, 112, 147, 1 }, coral = { 255, 127, 80, 1 }, tomato = { 255, 99, 71, 1 }, orangered = { 255, 69, 0, 1 }, darkorange = { 255, 140, 0, 1 }, orange = { 255, 165, 0, 1 }, gold = { 255, 215, 0, 1 }, yellow = { 255, 255, 0, 1 }, lightyellow = { 255, 255, 224, 1 }, lemonchiffon = { 255, 250, 205, 1 }, lightgoldenrodyellow = { 250, 250, 210, 1 }, papayawhip = { 255, 239, 213, 1 }, moccasin = { 255, 228, 181, 1 }, peachpuff = { 255, 218, 185, 1 }, palegoldenrod = { 238, 232, 170, 1 }, khaki = { 240, 230, 140, 1 }, darkkhaki = { 189, 183, 107, 1 }, lavender = { 230, 230, 250, 1 }, thistle = { 216, 191, 216, 1 }, plum = { 221, 160, 221, 1 }, violet = { 238, 130, 238, 1 }, orchid = { 218, 112, 214, 1 }, fuchsia = { 255, 0, 255, 1 }, magenta = { 255, 0, 255, 1 }, mediumorchid = { 186, 85, 211, 1 }, mediumpurple = { 147, 112, 219, 1 }, rebeccapurple = { 102, 51, 153, 1 }, blueviolet = { 138, 43, 226, 1 }, darkviolet = { 148, 0, 211, 1 }, darkorchid = { 153, 50, 204, 1 }, darkmagenta = { 139, 0, 139, 1 }, purple = { 128, 0, 128, 1 }, indigo = { 75, 0, 130, 1 }, slateblue = { 106, 90, 205, 1 }, darkslateblue = { 72, 61, 139, 1 }, mediumslateblue = { 123, 104, 238, 1 }, greenyellow = { 173, 255, 47, 1 }, chartreuse = { 127, 255, 0, 1 }, lawngreen = { 124, 252, 0, 1 }, lime = { 0, 255, 0, 1 }, limegreen = { 50, 205, 50, 1 }, palegreen = { 152, 251, 152, 1 }, lightgreen = { 144, 238, 144, 1 }, mediumspringgreen = { 0, 250, 154, 1 }, springgreen = { 0, 255, 127, 1 }, mediumseagreen = { 60, 179, 113, 1 }, seagreen = { 46, 139, 87, 1 }, forestgreen = { 34, 139, 34, 1 }, green = { 0, 128, 0, 1 }, darkgreen = { 0, 100, 0, 1 }, yellowgreen = { 154, 205, 50, 1 }, olivedrab = { 107, 142, 35, 1 }, olive = { 128, 128, 0, 1 }, darkolivegreen = { 85, 107, 47, 1 }, mediumaquamarine = { 102, 205, 170, 1 }, darkseagreen = { 143, 188, 139, 1 }, lightseagreen = { 32, 178, 170, 1 }, darkcyan = { 0, 139, 139, 1 }, teal = { 0, 128, 128, 1 }, aqua = { 0, 255, 255, 1 }, cyan = { 0, 255, 255, 1 }, lightcyan = { 224, 255, 255, 1 }, paleturquoise = { 175, 238, 238, 1 }, aquamarine = { 127, 255, 212, 1 }, turquoise = { 64, 224, 208, 1 }, mediumturquoise = { 72, 209, 204, 1 }, darkturquoise = { 0, 206, 209, 1 }, cadetblue = { 95, 158, 160, 1 }, steelblue = { 70, 130, 180, 1 }, lightsteelblue = { 176, 196, 222, 1 }, powderblue = { 176, 224, 230, 1 }, lightblue = { 173, 216, 230, 1 }, skyblue = { 135, 206, 235, 1 }, lightskyblue = { 135, 206, 250, 1 }, deepskyblue = { 0, 191, 255, 1 }, dodgerblue = { 30, 144, 255, 1 }, cornflowerblue = { 100, 149, 237, 1 }, royalblue = { 65, 105, 225, 1 }, blue = { 0, 0, 255, 1 }, mediumblue = { 0, 0, 205, 1 }, darkblue = { 0, 0, 139, 1 }, navy = { 0, 0, 128, 1 }, midnightblue = { 25, 25, 112, 1 }, cornsilk = { 255, 248, 220, 1 }, blanchedalmond = { 255, 235, 205, 1 }, bisque = { 255, 228, 196, 1 }, navajowhite = { 255, 222, 173, 1 }, wheat = { 245, 222, 179, 1 }, burlywood = { 222, 184, 135, 1 }, tan = { 210, 180, 140, 1 }, rosybrown = { 188, 143, 143, 1 }, sandybrown = { 244, 164, 96, 1 }, goldenrod = { 218, 165, 32, 1 }, darkgoldenrod = { 184, 134, 11, 1 }, peru = { 205, 133, 63, 1 }, chocolate = { 210, 105, 30, 1 }, saddlebrown = { 139, 69, 19, 1 }, sienna = { 160, 82, 45, 1 }, brown = { 165, 42, 42, 1 }, maroon = { 128, 0, 0, 1 }, white = { 255, 255, 255, 1 }, snow = { 255, 250, 250, 1 }, honeydew = { 240, 255, 240, 1 }, mintcream = { 245, 255, 250, 1 }, azure = { 240, 255, 255, 1 }, aliceblue = { 240, 248, 255, 1 }, ghostwhite = { 248, 248, 255, 1 }, whitesmoke = { 245, 245, 245, 1 }, seashell = { 255, 245, 238, 1 }, beige = { 245, 245, 220, 1 }, oldlace = { 253, 245, 230, 1 }, floralwhite = { 255, 250, 240, 1 }, ivory = { 255, 255, 240, 1 }, antiquewhite = { 250, 235, 215, 1 }, linen = { 250, 240, 230, 1 }, lavenderblush = { 255, 240, 245, 1 }, mistyrose = { 255, 228, 225, 1 }, gainsboro = { 220, 220, 220, 1 }, lightgray = { 211, 211, 211, 1 }, silver = { 192, 192, 192, 1 }, darkgray = { 169, 169, 169, 1 }, gray = { 128, 128, 128, 1 }, dimgray = { 105, 105, 105, 1 }, lightslategray = { 119, 136, 153, 1 }, slategray = { 112, 128, 144, 1 }, darkslategray = { 47, 79, 79, 1 }, black = { 0, 0, 0, 1 } } - - ---- Functions to convert various color types into one another\ --- Dependencies: `color.validate` --- @submodule color - ---- Converts a hex code string to a color table. --- Takes a string representation of a CSS hex value and converts it into --- an `{r, g, b, a}` color table. The function ignores the leading # --- symbol if present and will parse a 3 (rgb), 4 (rgba), 6 (rrggbb), or --- 8 (rrggbbaa) character-long hex value into a normalized (0 to 1) rgba --- color table. Sets a to 1 if not present in the hex code. --- @tparam string s A hex code formatted as #rgb, #rgba, #rrggbb, or --- #rrggbbaa with or without the leading # symbol --- @treturn table A color table in the format {r, g, b, a} --- @raise ValueError if hex code is malformed --- @usage --- white = hex_code_to_color("#FFF") --- print(white) -- {1, 1, 1, 1} --- --- black = hex_code_to_color("000F") --- print(black) -- {0, 0, 0, 1} --- --- orange = hex_code_to_color("#FFA500") --- print(orange) -- {0.9450..., 0.7686..., 0.0588..., 1} --- --- blue_transparent = hex_code_to_color("0000FF33") --- print(blue_transparent) -- {0, 0, 1, 0.2} --- --- malformed_hex = hex_code_to_color("#G09F3") --- -- ValueError: Not a valid hex code. -function hex_code_to_color(s) - if not is_valid_hex_code(s) then +-- SCROLL TO BOTTOM ---------------------------------------------------- + +ColorTables = {} + +ColorTables.htmlColors = { indianred = { 205, 92, 92, 1 }, lightcoral = { 240, 128, 128, 1 }, salmon = { 250, 128, 114, 1 }, darksalmon = { 233, 150, 122, 1 }, lightsalmon = { 255, 160, 122, 1 }, crimson = { 220, 20, 60, 1 }, red = { 255, 0, 0, 1 }, firebrick = { 178, 34, 34, 1 }, darkred = { 139, 0, 0, 1 }, pink = { 255, 192, 203, 1 }, lightpink = { 255, 182, 193, 1 }, hotpink = { 255, 105, 180, 1 }, deeppink = { 255, 20, 147, 1 }, mediumvioletred = { 199, 21, 133, 1 }, palevioletred = { 219, 112, 147, 1 }, coral = { 255, 127, 80, 1 }, tomato = { 255, 99, 71, 1 }, orangered = { 255, 69, 0, 1 }, darkorange = { 255, 140, 0, 1 }, orange = { 255, 165, 0, 1 }, gold = { 255, 215, 0, 1 }, yellow = { 255, 255, 0, 1 }, lightyellow = { 255, 255, 224, 1 }, lemonchiffon = { 255, 250, 205, 1 }, lightgoldenrodyellow = { 250, 250, 210, 1 }, papayawhip = { 255, 239, 213, 1 }, moccasin = { 255, 228, 181, 1 }, peachpuff = { 255, 218, 185, 1 }, palegoldenrod = { 238, 232, 170, 1 }, khaki = { 240, 230, 140, 1 }, darkkhaki = { 189, 183, 107, 1 }, lavender = { 230, 230, 250, 1 }, thistle = { 216, 191, 216, 1 }, plum = { 221, 160, 221, 1 }, violet = { 238, 130, 238, 1 }, orchid = { 218, 112, 214, 1 }, fuchsia = { 255, 0, 255, 1 }, magenta = { 255, 0, 255, 1 }, mediumorchid = { 186, 85, 211, 1 }, mediumpurple = { 147, 112, 219, 1 }, rebeccapurple = { 102, 51, 153, 1 }, blueviolet = { 138, 43, 226, 1 }, darkviolet = { 148, 0, 211, 1 }, darkorchid = { 153, 50, 204, 1 }, darkmagenta = { 139, 0, 139, 1 }, purple = { 128, 0, 128, 1 }, indigo = { 75, 0, 130, 1 }, slateblue = { 106, 90, 205, 1 }, darkslateblue = { 72, 61, 139, 1 }, mediumslateblue = { 123, 104, 238, 1 }, greenyellow = { 173, 255, 47, 1 }, chartreuse = { 127, 255, 0, 1 }, lawngreen = { 124, 252, 0, 1 }, lime = { 0, 255, 0, 1 }, limegreen = { 50, 205, 50, 1 }, palegreen = { 152, 251, 152, 1 }, lightgreen = { 144, 238, 144, 1 }, mediumspringgreen = { 0, 250, 154, 1 }, springgreen = { 0, 255, 127, 1 }, mediumseagreen = { 60, 179, 113, 1 }, seagreen = { 46, 139, 87, 1 }, forestgreen = { 34, 139, 34, 1 }, green = { 0, 128, 0, 1 }, darkgreen = { 0, 100, 0, 1 }, yellowgreen = { 154, 205, 50, 1 }, olivedrab = { 107, 142, 35, 1 }, olive = { 128, 128, 0, 1 }, darkolivegreen = { 85, 107, 47, 1 }, mediumaquamarine = { 102, 205, 170, 1 }, darkseagreen = { 143, 188, 139, 1 }, lightseagreen = { 32, 178, 170, 1 }, darkcyan = { 0, 139, 139, 1 }, teal = { 0, 128, 128, 1 }, aqua = { 0, 255, 255, 1 }, cyan = { 0, 255, 255, 1 }, lightcyan = { 224, 255, 255, 1 }, paleturquoise = { 175, 238, 238, 1 }, aquamarine = { 127, 255, 212, 1 }, turquoise = { 64, 224, 208, 1 }, mediumturquoise = { 72, 209, 204, 1 }, darkturquoise = { 0, 206, 209, 1 }, cadetblue = { 95, 158, 160, 1 }, steelblue = { 70, 130, 180, 1 }, lightsteelblue = { 176, 196, 222, 1 }, powderblue = { 176, 224, 230, 1 }, lightblue = { 173, 216, 230, 1 }, skyblue = { 135, 206, 235, 1 }, lightskyblue = { 135, 206, 250, 1 }, deepskyblue = { 0, 191, 255, 1 }, dodgerblue = { 30, 144, 255, 1 }, cornflowerblue = { 100, 149, 237, 1 }, royalblue = { 65, 105, 225, 1 }, blue = { 0, 0, 255, 1 }, mediumblue = { 0, 0, 205, 1 }, darkblue = { 0, 0, 139, 1 }, navy = { 0, 0, 128, 1 }, midnightblue = { 25, 25, 112, 1 }, cornsilk = { 255, 248, 220, 1 }, blanchedalmond = { 255, 235, 205, 1 }, bisque = { 255, 228, 196, 1 }, navajowhite = { 255, 222, 173, 1 }, wheat = { 245, 222, 179, 1 }, burlywood = { 222, 184, 135, 1 }, tan = { 210, 180, 140, 1 }, rosybrown = { 188, 143, 143, 1 }, sandybrown = { 244, 164, 96, 1 }, goldenrod = { 218, 165, 32, 1 }, darkgoldenrod = { 184, 134, 11, 1 }, peru = { 205, 133, 63, 1 }, chocolate = { 210, 105, 30, 1 }, saddlebrown = { 139, 69, 19, 1 }, sienna = { 160, 82, 45, 1 }, brown = { 165, 42, 42, 1 }, maroon = { 128, 0, 0, 1 }, white = { 255, 255, 255, 1 }, snow = { 255, 250, 250, 1 }, honeydew = { 240, 255, 240, 1 }, mintcream = { 245, 255, 250, 1 }, azure = { 240, 255, 255, 1 }, aliceblue = { 240, 248, 255, 1 }, ghostwhite = { 248, 248, 255, 1 }, whitesmoke = { 245, 245, 245, 1 }, seashell = { 255, 245, 238, 1 }, beige = { 245, 245, 220, 1 }, oldlace = { 253, 245, 230, 1 }, floralwhite = { 255, 250, 240, 1 }, ivory = { 255, 255, 240, 1 }, antiquewhite = { 250, 235, 215, 1 }, linen = { 250, 240, 230, 1 }, lavenderblush = { 255, 240, 245, 1 }, mistyrose = { 255, 228, 225, 1 }, gainsboro = { 220, 220, 220, 1 }, lightgray = { 211, 211, 211, 1 }, silver = { 192, 192, 192, 1 }, darkgray = { 169, 169, 169, 1 }, gray = { 128, 128, 128, 1 }, dimgray = { 105, 105, 105, 1 }, lightslategray = { 119, 136, 153, 1 }, slategray = { 112, 128, 144, 1 }, darkslategray = { 47, 79, 79, 1 }, black = { 0, 0, 0, 1 } } + + +ColorUtils = {} + +function ColorUtils.is_valid_hex_code(s) + s = s:gsub("#", "") + local invalidChars = string.match(s, "[^0-9a-fA-F]+") + local hasValidChars = invalidChars == nil + local isValidLen = #s == 3 or #s == 4 or #s == 6 or #s == 8 + return hasValidChars and isValidLen +end + +function ColorUtils.hex_code_to_color(s) + if not ColorUtils.is_valid_hex_code(s) then error("ValueError: Not a valid hex code.") end @@ -59,87 +38,570 @@ function hex_code_to_color(s) end ---- Functions and tables that create, translate, validate, and manipulate colors. --- This is the main module for color-related functionalities. --- It encapsulates submodules like color.convert, color.tables, and color.validate. --- @module color +Utils = {} + +function Utils.process_args(class_meta, ...) + local args = { ... } + local processed_args --- This file intentionally left blank to help generate API docs. + if type(args[1]) == "table" then + if getmetatable(args[1]) == class_meta then + processed_args = args + else + processed_args = args[1] + end + else + processed_args = args + end + return processed_args +end ---- Functions to validate the form of color strings and numbers --- @submodule color +function Utils.has_non_integer_keys(t) + for k, _ in pairs(t) do + if type(k) ~= "number" or k ~= math.floor(k) or k < 1 then + return true + end + end + return false +end ---- Checks if a CSS hex code is formatted properly. --- Uses character and length matching to assert that the hex code is --- formatted correctly. Works for rgb, rgba, rrggbb, and rrggbbaa hex --- codes. Outputs true if correct and false if malformed. --- @tparam string s A hex code formatted as #rgb, #rgba, #rrggbb, or --- #rrggbbaa with or without the leading # symbol --- @treturn boolean true if correctly formatted, false if not. --- @usage --- print(is_valid_hex_code(FFF)) -- true --- --- print(is_valid_hex_code(#J37N)) -- false -function is_valid_hex_code(s) - s = s:gsub("#", "") - local invalidChars = string.match(s, "[^0-9a-fA-F]+") - local hasValidChars = invalidChars == nil - local isValidLen = #s == 3 or #s == 4 or #s == 6 or #s == 8 - return hasValidChars and isValidLen +function Utils.table_to_string(t) + local parts = {} + if Utils.has_non_integer_keys(t) then + for k, v in pairs(t) do + parts[#parts + 1] = tostring(k) .. " = " .. tostring(v) + end + else + for _, v in ipairs(t) do + parts[#parts + 1] = tostring(v) + end + end + return "{ " .. table.concat(parts, ", ") .. " }" +end + + +Vec2 = {} +Vec2.__index = Vec2 + +function Vec2.new(x, y) + local self = setmetatable({}, Vec2) + self.x = x or 0 + self.y = y or 0 + return self +end + +function Vec2.is_vec2(obj) + return type(obj) == "table" and obj.x and obj.y and not obj.z +end + +function Vec2.is_xy_pair(x, y) + return type(x) == "number" and type(y) == "number" +end + +function Vec2:Set(x, y) + if Vec2.is_vec2(x) then + self.x = x.x + self.y = x.y + return self + elseif Vec2.is_xy_pair(x, y) then + self.x = x + self.y = y + return self + else + error("TypeError: Invalid arguments for Vec2:set") + end +end + +function Vec2:add(x, y) + if Vec2.is_vec2(x) then + return Vec2.new(self.x + x.x, self.y + x.y) + elseif Vec2.is_xy_pair(x, y) then + return Vec2.new(self.x + x, self.y + y) + else + error("TypeError: Invalid arguments for Vec2:add") + end +end + +function Vec2:Add(x, y) + if Vec2.is_vec2(x) then + self.x = self.x + x.x + self.y = self.y + x.y + return self + elseif Vec2.is_xy_pair(x, y) then + self.x = self.x + x + self.y = self.y + y + return self + else + error("TypeError: Invalid arguments for Vec2:Add") + end +end + +function Vec2:sub(x, y) + if Vec2.is_vec2(x) then + return Vec2.new(self.x - x.x, self.y - x.y) + elseif Vec2.is_xy_pair(x, y) then + return Vec2.new(self.x - x, self.y - y) + else + error("TypeError: Invalid arguments for Vec2:sub") + end +end + +function Vec2:Sub(x, y) + if Vec2.is_vec2(x) then + self.x = self.x - x.x + self.y = self.y - y.y + return self + elseif Vec2.is_xy_pair(x, y) then + self.x = self.x - x + self.y = self.y - y + return self + else + error("TypeError: Invalid arguments for Vec2:Sub") + end +end + +function Vec2:mult(scalar) + return Vec2.new(self.x * scalar, self.y * scalar) +end + +function Vec2:Mult(scalar) + self.x = self.x * scalar + self.y = self.y * scalar + return self +end + +function Vec2:magnitude() + return math.sqrt(self.x * self.x + self.y * self.y) +end + +function Vec2:normalize() + local mag = self:magnitude() + if mag > 0 then + return Vec2.new(self.x / mag, self.y / mag) + else + return Vec2.new(0, 0) + end +end + +function Vec2:dot(other) + return self.x * other.x + self.y * other.y +end + +function Vec2:angle(other) + local dot_product = self:dot(other) + local mag_product = self:magnitude() * other:magnitude() + if mag_product > 0 then + return math.acos(dot_product / mag_product) + else + return 0 + end +end + +function Vec2:rotate(angle) + local cos_theta = math.cos(angle) + local sin_theta = math.sin(angle) + return Vec2.new( + self.x * cos_theta - self.y * sin_theta, + self.x * sin_theta + self.y * cos_theta + ) +end + +function Vec2:Rotate(angle) + local cos_theta = math.cos(angle) + local sin_theta = math.sin(angle) + self.x = self.x * cos_theta - self.y * sin_theta + self.y = self.x * sin_theta + self.y * cos_theta + return self +end + +function Vec2:distance(other) + if Vec2.is_vec2(other) then + local dx = self.x - other.x + local dy = self.y - other.y + return math.sqrt(dx * dx + dy * dy) + else + error("TypeError: Argument for Vec2:distance must be a Vec2") + end +end + +function Vec2:scale_about(other, scalar) + if Vec2.is_vec2(other) then + return Vec2.new( + other.x + (self.x - other.x) * scalar, + other.y + (self.y - other.y) * scalar + ) + else + error("TypeError: First argument for Vec2:scale_about must be a Vec2") + end +end + + +Point = {} +Point.__index = Point + +function Point.new(vec2, color, size) + local self = setmetatable({}, Point) + self.vec2 = vec2 or { x = 0, y = 0 } + self.color = color or { 1, 1, 1, 1 } + self.size = size or 2 + return self +end + +function Point.draw_all(...) + local points = Utils.process_args(Point, ...) + + for _, point in ipairs(points) do + if getmetatable(point) == Point then + point:draw() + else + error("Invalid argument to Point.draw_all:" .. + "Expected a Point instance or a table of Point instances") + end + end +end + +function Point:draw() + fill_circle({ self.vec2.x, self.vec2.y }, + self.size, + color_paint(self.color) + ) end --- paint = color_paint { r, g, b, a } --- paint = linear_gradient( {start_x, start_y}, {end_x, end_y}, {r, g, b, a}, {r, g, b, a}) +Triangle = {} +Triangle.__index = Triangle --- fill_circle( {x, y}, radius, paint) --- stroke_circle( {x, y}, radius, width, paint) +function Triangle.new(vec2_a, vec2_b, vec2_c) + local self = setmetatable({}, Triangle) + self.vec2_a = vec2_a or { x = 0, y = 0 } + self.vec2_b = vec2_b or { x = 0, y = 0 } + self.vec2_c = vec2_c or { x = 0, y = 0 } + return self +end --- stroke_arc( {x, y}, radius, width, rotation, aperture, paint) --- stroke_segment( {ax, ay}, {bx, by}, width, paint) +function Triangle:draw(color) + color = color or theme.text + local paint = color_paint(color) + move_to { self.vec2_a.x, self.vec2_a.y } + line_to { self.vec2_b.x, self.vec2_b.y } + line_to { self.vec2_c.x, self.vec2_c.y } + line_to { self.vec2_a.x, self.vec2_a.y } + fill(paint) +end --- fill_rect( {min_x, min_y}, {max_x, max_y}, corner_radius, paint) --- stroke_rect( {min_x, min_y}, {max_x, max_y}, corner_radius, width, paint) +function Triangle:get_vec2s() + return { vec2_a = self.vec2_a, vec2_b = self.vec2_b, vec2_c = self.vec2_c } +end --- stroke_bezier( {ax, ay}, {bx, by}, {cx, cy}, width, paint) +function Triangle:get_vec2_a() + return self.vec2_a +end --- text("hello world!", {r,g,b,a}) --- min, max = text_bounds("hello world!") --- text_box("lorem ipsum...", break_row_width, {r,g,b,a}) +function Triangle:get_vec2_b() + return self.vec2_b +end --- move_to {x, y} --- line_to {x, y} --- quad_to({bx, by}, {cx, cy}) --- fill(paint) +function Triangle:get_vec2_c() + return self.vec2_c +end --- translate {tx, ty} --- scale {sx, sy} --- scale {sx, sy} --- save() --- restore() +function Triangle:Set_vec2s(...) +end --- canvas_width --- canvas_height +function Triangle:Set_vec2_a(x, y) + self.vec2_a:Set(x, y) +end --- theme.azureHighlight --- theme.azureHighlightDark --- theme.azureHighlightBackground +function Triangle:Set_vec2_b(x, y) + self.vec2_b:Set(x, y) +end --- theme.greenHighlight --- theme.greenHighlightDark --- theme.azureHighlightBackground +function Triangle:Set_vec2_c(x, y) + self.vec2_c:Set(x, y) +end --- theme.redHighlight --- theme.redHighlightDark --- theme.redHighlightBackground +function Triangle:centroid() + local cx = (self.vec2_a.x + self.vec2_b.x + self.vec2_c.x) / 3 + local cy = (self.vec2_a.y + self.vec2_b.y + self.vec2_c.y) / 3 + return Vec2.new(cx, cy) +end --- theme.grooves --- theme.modules --- theme.text +function Triangle:area() + local a = self.vec2_a + local b = self.vec2_b + local c = self.vec2_c + + local area = 0.5 * math.abs( + a.x * (b.y - c.y) + + b.x * (c.y - a.y) + + c.x * (a.y - b.y) + ) + return area +end +function Triangle:perimeter() + local a_b = self.vec2_a:distance(self.vec2_b) + local b_c = self.vec2_b:distance(self.vec2_c) + local c_a = self.vec2_c:distance(self.vec2_a) -function btn(x, y, width, options) + local perimeter = a_b + b_c + c_a + return perimeter +end + +function Triangle:type() + local tolerance = 0.00001 + local a_b = self.vec2_a:distance(self.vec2_b) + local b_c = self.vec2_b:distance(self.vec2_c) + local c_a = self.vec2_c:distance(self.vec2_a) + + local ab_bc = math.abs(a_b - b_c) < tolerance + local ab_ca = math.abs(a_b - c_a) < tolerance + local bc_ca = math.abs(b_c - c_a) < tolerance + + if ab_bc and ab_ca then + return "equilateral" + elseif ab_bc or ab_ca or bc_ca then + return "isosceles" + else + return "scalene" + end +end + +function Triangle:angle_type() + local vec_a_b = self.vec2_b:sub(self.vec2_a) + local vec_a_c = self.vec2_c:sub(self.vec2_a) + local vec_b_a = self.vec2_a:sub(self.vec2_b) + local vec_b_c = self.vec2_c:sub(self.vec2_b) + local vec_c_a = self.vec2_a:sub(self.vec2_c) + local vec_c_b = self.vec2_b:sub(self.vec2_c) + + local dot_a = vec_a_b:dot(vec_a_c) + local dot_b = vec_b_a:dot(vec_b_c) + local dot_c = vec_c_a:dot(vec_c_b) + + local isRight = dot_a == 0 or dot_b == 0 or dot_c == 0 + local isObtuse = dot_a < 0 or dot_b < 0 or dot_c < 0 + + if isRight then + return "right" + elseif isObtuse then + return "obtuse" + else + return "acute" + end +end + +function Triangle:scale(scalar) + local centroid = self:centroid() + + return Triangle.new( + self.vec2_a:scale_about(centroid, scalar), + self.vec2_b:scale_about(centroid, scalar), + self.vec2_c:scale_about(centroid, scalar) + ) +end + +function Triangle:Scale(scalar) + local centroid = self:centroid() + + self.vec2_a = self.vec2_a:scale_about(centroid, scalar) + self.vec2_b = self.vec2_b:scale_about(centroid, scalar) + self.vec2_c = self.vec2_c:scale_about(centroid, scalar) +end + +function Triangle:rotate(angle) + local centroid = self:centroid() + + local rotate_vertex = function(vertex) + local translated_vertex = vertex:sub(centroid) + local rotated_vertex = translated_vertex:rotate(angle) + return rotated_vertex:add(centroid) + end + + return Triangle.new( + rotate_vertex(self.vec2_a), + rotate_vertex(self.vec2_b), + rotate_vertex(self.vec2_c) + ) +end + +function Triangle:Rotate(angle) + local centroid = self:centroid() + + local rotate_vertex = function(vertex) + local translated_vertex = vertex:sub(centroid) + local rotated_vertex = translated_vertex:rotate(angle) + return rotated_vertex:add(centroid) + end + + self.vec2_a = rotate_vertex(self.vec2_a) + self.vec2_b = rotate_vertex(self.vec2_b) + self.vec2_c = rotate_vertex(self.vec2_c) + return self +end + +function Triangle:translate(vec2) + return Triangle.new( + self.vec2_a:add(vec2), + self.vec2_b:add(vec2), + self.vec2_c:add(vec2) + ) +end + +function Triangle:Translate(vec2) + self.vec2_a:add(vec2) + self.vec2_b:add(vec2) + self.vec2_c:add(vec2) + return self +end + +function Triangle:bounding_box() + local min_x = math.min(self.vec2_a.x, self.vec2_b.x, self.vec2_c.x) + local max_x = math.max(self.vec2_a.x, self.vec2_b.x, self.vec2_c.x) + local min_y = math.min(self.vec2_a.y, self.vec2_b.y, self.vec2_c.y) + local max_y = math.max(self.vec2_a.y, self.vec2_b.y, self.vec2_c.y) + return Vec2.new(min_x, min_y), Vec2.new(max_x, max_y) +end + +function Triangle:incircle() + local a = self.vec2_b:distance(self.vec2_c) + local b = self.vec2_c:distance(self.vec2_a) + local c = self.vec2_a:distance(self.vec2_b) + local s = (a + b + c) / 2 + local area = math.sqrt(s * (s - a) * (s - b) * (s - c)) + local incenterX = (a * self.vec2_a.x + b * self.vec2_b.x + c * self.vec2_c.x) / (a + b + c) + local incenterY = (a * self.vec2_a.y + b * self.vec2_b.y + c * self.vec2_c.y) / (a + b + c) + local radius = area / s + return Vec2.new(incenterX, incenterY), radius +end + +function Triangle:circumcircle() + local a = self.vec2_b:distance(self.vec2_c) + local b = self.vec2_c:distance(self.vec2_a) + local c = self.vec2_a:distance(self.vec2_b) + local s = (a + b + c) / 2 + local area = math.sqrt(s * (s - a) * (s - b) * (s - c)) + local radius = (a * b * c) / (4 * area) + local ax, ay = self.vec2_a.x, self.vec2_a.y + local bx, by = self.vec2_b.x, self.vec2_b.y + local cx, cy = self.vec2_c.x, self.vec2_c.y + local D = 2 * ( + ax * (by - cy) + + bx * (cy - ay) + + cx * (ay - by) + ) + local Ux = ( + (ax ^ 2 + ay ^ 2) * (by - cy) + + (bx ^ 2 + by ^ 2) * (cy - ay) + + (cx ^ 2 + cy ^ 2) * (ay - by)) / D + local Uy = ( + (ax ^ 2 + ay ^ 2) * (cx - bx) + + (bx ^ 2 + by ^ 2) * (ax - cx) + + (cx ^ 2 + cy ^ 2) * (bx - ax)) / D + return Vec2.new(Ux, Uy), radius +end + + +Line = {} +Line.__index = Line + +function Line.new(vec2_a, vec2_b) + local self = setmetatable({}, Line) + self.vec2_a = vec2_a or { 0, 0 } + self.vec2_b = vec2_b or { 0, 0 } + return self +end + +local function process_args(class_meta, ...) + local args = { ... } + local processed_args + + if type(args[1]) == "table" then + if getmetatable(args[1]) == class_meta then + processed_args = args + else + processed_args = args[1] + end + else + processed_args = args + end + + return processed_args +end + +function Line.draw_between_all(...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + for j = i + 1, #vec2s do + local line = Line.new(vec2s[i], vec2s[j]) + line:draw() + end + end +end + +function Line.dash_between_all(...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + for j = i + 1, #vec2s do + local line = Line.new(vec2s[i], vec2s[j]) + line:dashed() + end + end +end + +function Line.draw_from_to_all(vec2, ...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + local line = Line.new(vec2, vec2s[i]) + line:draw() + end +end + +function Line.dash_from_to_all(vec2, ...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + local line = Line.new(vec2, vec2s[i]) + line:dash() + end +end + +function Line:draw(color, width) + color = color or theme.text + width = width or 1 + local paint = color_paint(color) + stroke_segment( + { self.vec2_a.x, self.vec2_a.y }, + { self.vec2_b.x, self.vec2_b.y }, + width, paint + ) +end + +function Line:dashed(color, width, dash_length, space_length) + color = color or theme.text + width = width or 1 + dash_length = dash_length or 5 + space_length = space_length or dash_length + local paint = color_paint(color) + + local total_distance = self.vec2_a:distance(self.vec2_b) + local direction = self.vec2_b:sub(self.vec2_a):normalize() + + local current_distance = 0 + while current_distance < total_distance do + local start_dash = self.vec2_a:add(direction:mult(current_distance)) + current_distance = math.min(current_distance + dash_length, total_distance) + local end_dash = self.vec2_a:add(direction:mult(current_distance)) + + local temp_line = Line.new(start_dash, end_dash) + temp_line:draw(color, width) + + current_distance = current_distance + space_length + end +end + + +function button(x, y, width, options) -- Error Handling local function checkMutuallyExclusiveArgs(arg1Name, arg1, arg2Name, arg2) local e = "MutuallyExclusiveArgError: '%s' and '%s' cannot be used" .. @@ -250,7 +712,7 @@ function btn(x, y, width, options) drawButton() end -function tileFn(func, r, c) +function tile_button_fn(func, r, c) return function(x, y, w, o) local h = o.height or w for i = 0, c - 1 do @@ -263,65 +725,10 @@ function tileFn(func, r, c) end ---- Useful debugging functions. --- @module debug - ---- Returns a set of functions that together enable stdout-like printing. --- The built-in Lua print() function can't print anywhere in Audulus. This --- function enables you to add in a stdout-like experience in Audulus. The --- function creates two functions (normally named print and printAll) that --- assist in printing variables beneath the Canvas node. print() will add a --- variable or value to the print queue. Use print() just as you would in any --- any other program. Then, call printAll() at the very end of your script to --- display the print queue. Each print item is numbered in the order it was --- called starting at 1. Additionally, displays the current memory usage. --- @treturn function add_to_queue Adds variable to print queue. --- @treturn function print_queue Prints the queue beneath the Canvas node. --- @usage --- print, printAll = create_print_logger() --- --- x = 1 + 1 --- print(x) --- --- color = {0.5, 0.75, 0.1, 1} --- print(color) --- --- coordinate = {x = 1, y = 12} --- print(coordinate) --- --- printAll() --- -- (Note: This appears below the Canvas node) -- --- -- Memory usage (KB): 72 --- -- Print Queue Output --- -- _________________ --- -- 1. 2 --- -- 2. {0.5, 0.75, 0.1, 1} --- -- 3. {x = 1, y = 12} -function create_print_logger() - local queue = {} - - local function has_non_integer_keys(t) - for k, _ in pairs(t) do - if type(k) ~= "number" or k ~= math.floor(k) or k < 1 then - return true - end - end - return false - end +Debug = {} - local function table_to_string(t) - local parts = {} - if has_non_integer_keys(t) then - for k, v in pairs(t) do - parts[#parts + 1] = tostring(k) .. " = " .. tostring(v) - end - else - for _, v in ipairs(t) do - parts[#parts + 1] = tostring(v) - end - end - return "{ " .. table.concat(parts, ", ") .. " }" - end +function Debug.Logger() + local queue = {} local function add_to_queue(...) local args = { ... } @@ -329,17 +736,33 @@ function create_print_logger() for i, arg in ipairs(args) do statements[i] = (type(arg) == "table") - and table_to_string(arg) or tostring(arg) + and Utils.table_to_string(arg) or tostring(arg) end table.insert(queue, table.concat(statements, ", ")) end - local function print_queue() - local memory = math.floor(collectgarbage("count")) + local function get_peak_memory(interval) + if _PeakMemory == nil then + _PeakMemory = math.floor(collectgarbage("count")) + end + + if Time == nil then Time = 0 end + local current_memory_usage = math.floor(collectgarbage("count")) + local truncated_time = math.floor(Time * 100) / 100 + + if _PeakMemory < current_memory_usage then + _PeakMemory = current_memory_usage + end + + if truncated_time % interval == 0 then _PeakMemory = 0 end + + return _PeakMemory + end + local function print_queue() translate { 0, -30 } - text("Memory usage (KB): " .. memory, theme.text) + text("Peak memory usage (KB): " .. get_peak_memory(10), theme.text) translate { 0, -20 } text("Print Queue Output", theme.text) translate { 0, -4 } @@ -352,7 +775,52 @@ function create_print_logger() end end - return addToQueue, printQueue + return add_to_queue, print_queue +end + +print, print_all = Debug.Logger() + + +Graph = {} +Graph.__index = Graph + +function Graph.new(x_max, y_max, step, color) + local self = setmetatable({}, Graph) + self.x_max = x_max or 100 + self.y_max = y_max or 100 + self.step = step or 10 + self.color = color or { 0.4, 0.4, 0.4, 1 } + return self end +function Graph:draw() + local paint = color_paint(self.color) + + for i = 0, self.step * self.step * 2, self.step do + stroke_segment({ -self.x_max, -self.y_max + i }, { self.x_max, -self.y_max + i }, 1, paint) + stroke_segment({ -self.x_max + i, -self.y_max }, { -self.x_max + i, self.y_max }, 1, paint) + end + + stroke_segment({ -self.x_max, 0 }, { self.x_max, 0 }, 2, paint) + stroke_segment({ 0, self.y_max }, { 0, -self.y_max }, 2, paint) +end + + +-- AUDULUS-CANVAS LIBRARY ---------------------------------------------- + +----- Instructions ----- +-- 1. Create 'Time' input (case-sensitive) +-- 2. Attach Timer node to the 'Time' input +-- 3. Select 'Save Data' at the bottom of the inspector panel +-- 4. Set a custom W(idth) and H(eight) in the inspector panel +-- 5. Write your code below this line + +-- CODE ---------------------------------------------------------------- + + + + + +-- PRINT CONSOLE ------------------------------------------------------- +print_all() diff --git a/minified/print.lua.minified b/minified/print.lua.minified deleted file mode 100644 index 9575a6b..0000000 --- a/minified/print.lua.minified +++ /dev/null @@ -1,7 +0,0 @@ -local function p() local q={}; local function h(t) for k,_ in pairs(t) do if type(k)~="number" or k~=math.floor(k) or k<1 then return true end end return false end local function tS(t) local p={}; if h(t) then for k,v in pairs(t) do p[#p+1]="["..tostring(k).."]="..tostring(v) end else for _,v in ipairs(t) do p[#p+1]=tostring(v) end end return "{"..table.concat(p,", ").."}" end local function a(...) local a={...}; local s={}; for _,arg in ipairs(a) do s[#s+1]=(type(arg)=="table") and tS(arg) or tostring(arg) end table.insert(q,table.concat(s,", ")) end local function pQ() local m=math.floor(collectgarbage("count")); translate{0,-30}; text("Memory usage (KB): "..m,theme.text); translate{0,-20}; text("Print Queue Output",theme.text); translate{0,-4}; text("_________________",theme.text); translate{0,-20}; for i,s in ipairs(q) do text(i..": "..s,theme.text); translate{0,-14} end end return a,pQ end - -print, printAll() = p() - --- INSERT SCRIPT HERE -- - -printAll() \ No newline at end of file diff --git a/src/builtins/builtins.lua b/src/builtins/builtins.lua index 7b6c5ab..be811d8 100644 --- a/src/builtins/builtins.lua +++ b/src/builtins/builtins.lua @@ -1,40 +1,8 @@ ---- Draw, move, scale, and color basic shapes. --- These functions draw, move, scale, and color shapes on the Canvas node. --- There are also several built-in theme values that represent color tables --- matching the style of Audulus. The Audulus-Canvas library is extends the --- usefulness of these built-ins by adding additional abstraction layers and --- utility functions that simplify complex drawing operations. --- @module builtins - --- Note: If you would like to see the source code for these functions, you can --- view it at https://github.com/audulus/vger. - ---- Returns a paint userdata from a color table. --- Creates a userdata called paint that represents an rgba color. Paints are --- used to color all of the SVG shapes. It is good practice to keep colors --- values as color values right up until you need them to be paints, usually --- just one line before you actually draw the shape that takes a paint. This is --- because you cannot index into and manipulate the rgba values of a paint. --- @tparam table color_table An {r, g, b, a} color table where each variable is --- a normalized 0 to 1 value. --- @treturn userdata A paint userdata. --- @usage --- white = {1, 1, 1, 1} --- paint = color_paint(white) --- fill_circle({0, 0}, 10, paint) -- white circle --- --- -- In this example, sine is a Canvas node input and is a 0 to 1 sine wave --- pulsing_red = {sine, 0, 0, 1} --- pulsing_red_paint = color_paint(pulsing_red) --- fill_rect({0, 0}, {40, 10}, 0, pulsing_red_paint) -- --- --- print(white[1]) -- 1 --- print(paint[1]) -- Error: attempt to index global 'white' (a userdata value) function color_paint(color_table) end --- Returns a linear gradient paint from two color tables and a set of coordinates. -function linear_gradient(start, end, color_start, color_end) +function linear_gradient(start_coord, end_coord, color_start, color_end) end --- Draws a solid circle. diff --git a/src/color/ColorTables.lua b/src/color/ColorTables.lua new file mode 100644 index 0000000..a6a1f0f --- /dev/null +++ b/src/color/ColorTables.lua @@ -0,0 +1,3 @@ +ColorTables = {} + +ColorTables.htmlColors = { indianred = { 205, 92, 92, 1 }, lightcoral = { 240, 128, 128, 1 }, salmon = { 250, 128, 114, 1 }, darksalmon = { 233, 150, 122, 1 }, lightsalmon = { 255, 160, 122, 1 }, crimson = { 220, 20, 60, 1 }, red = { 255, 0, 0, 1 }, firebrick = { 178, 34, 34, 1 }, darkred = { 139, 0, 0, 1 }, pink = { 255, 192, 203, 1 }, lightpink = { 255, 182, 193, 1 }, hotpink = { 255, 105, 180, 1 }, deeppink = { 255, 20, 147, 1 }, mediumvioletred = { 199, 21, 133, 1 }, palevioletred = { 219, 112, 147, 1 }, coral = { 255, 127, 80, 1 }, tomato = { 255, 99, 71, 1 }, orangered = { 255, 69, 0, 1 }, darkorange = { 255, 140, 0, 1 }, orange = { 255, 165, 0, 1 }, gold = { 255, 215, 0, 1 }, yellow = { 255, 255, 0, 1 }, lightyellow = { 255, 255, 224, 1 }, lemonchiffon = { 255, 250, 205, 1 }, lightgoldenrodyellow = { 250, 250, 210, 1 }, papayawhip = { 255, 239, 213, 1 }, moccasin = { 255, 228, 181, 1 }, peachpuff = { 255, 218, 185, 1 }, palegoldenrod = { 238, 232, 170, 1 }, khaki = { 240, 230, 140, 1 }, darkkhaki = { 189, 183, 107, 1 }, lavender = { 230, 230, 250, 1 }, thistle = { 216, 191, 216, 1 }, plum = { 221, 160, 221, 1 }, violet = { 238, 130, 238, 1 }, orchid = { 218, 112, 214, 1 }, fuchsia = { 255, 0, 255, 1 }, magenta = { 255, 0, 255, 1 }, mediumorchid = { 186, 85, 211, 1 }, mediumpurple = { 147, 112, 219, 1 }, rebeccapurple = { 102, 51, 153, 1 }, blueviolet = { 138, 43, 226, 1 }, darkviolet = { 148, 0, 211, 1 }, darkorchid = { 153, 50, 204, 1 }, darkmagenta = { 139, 0, 139, 1 }, purple = { 128, 0, 128, 1 }, indigo = { 75, 0, 130, 1 }, slateblue = { 106, 90, 205, 1 }, darkslateblue = { 72, 61, 139, 1 }, mediumslateblue = { 123, 104, 238, 1 }, greenyellow = { 173, 255, 47, 1 }, chartreuse = { 127, 255, 0, 1 }, lawngreen = { 124, 252, 0, 1 }, lime = { 0, 255, 0, 1 }, limegreen = { 50, 205, 50, 1 }, palegreen = { 152, 251, 152, 1 }, lightgreen = { 144, 238, 144, 1 }, mediumspringgreen = { 0, 250, 154, 1 }, springgreen = { 0, 255, 127, 1 }, mediumseagreen = { 60, 179, 113, 1 }, seagreen = { 46, 139, 87, 1 }, forestgreen = { 34, 139, 34, 1 }, green = { 0, 128, 0, 1 }, darkgreen = { 0, 100, 0, 1 }, yellowgreen = { 154, 205, 50, 1 }, olivedrab = { 107, 142, 35, 1 }, olive = { 128, 128, 0, 1 }, darkolivegreen = { 85, 107, 47, 1 }, mediumaquamarine = { 102, 205, 170, 1 }, darkseagreen = { 143, 188, 139, 1 }, lightseagreen = { 32, 178, 170, 1 }, darkcyan = { 0, 139, 139, 1 }, teal = { 0, 128, 128, 1 }, aqua = { 0, 255, 255, 1 }, cyan = { 0, 255, 255, 1 }, lightcyan = { 224, 255, 255, 1 }, paleturquoise = { 175, 238, 238, 1 }, aquamarine = { 127, 255, 212, 1 }, turquoise = { 64, 224, 208, 1 }, mediumturquoise = { 72, 209, 204, 1 }, darkturquoise = { 0, 206, 209, 1 }, cadetblue = { 95, 158, 160, 1 }, steelblue = { 70, 130, 180, 1 }, lightsteelblue = { 176, 196, 222, 1 }, powderblue = { 176, 224, 230, 1 }, lightblue = { 173, 216, 230, 1 }, skyblue = { 135, 206, 235, 1 }, lightskyblue = { 135, 206, 250, 1 }, deepskyblue = { 0, 191, 255, 1 }, dodgerblue = { 30, 144, 255, 1 }, cornflowerblue = { 100, 149, 237, 1 }, royalblue = { 65, 105, 225, 1 }, blue = { 0, 0, 255, 1 }, mediumblue = { 0, 0, 205, 1 }, darkblue = { 0, 0, 139, 1 }, navy = { 0, 0, 128, 1 }, midnightblue = { 25, 25, 112, 1 }, cornsilk = { 255, 248, 220, 1 }, blanchedalmond = { 255, 235, 205, 1 }, bisque = { 255, 228, 196, 1 }, navajowhite = { 255, 222, 173, 1 }, wheat = { 245, 222, 179, 1 }, burlywood = { 222, 184, 135, 1 }, tan = { 210, 180, 140, 1 }, rosybrown = { 188, 143, 143, 1 }, sandybrown = { 244, 164, 96, 1 }, goldenrod = { 218, 165, 32, 1 }, darkgoldenrod = { 184, 134, 11, 1 }, peru = { 205, 133, 63, 1 }, chocolate = { 210, 105, 30, 1 }, saddlebrown = { 139, 69, 19, 1 }, sienna = { 160, 82, 45, 1 }, brown = { 165, 42, 42, 1 }, maroon = { 128, 0, 0, 1 }, white = { 255, 255, 255, 1 }, snow = { 255, 250, 250, 1 }, honeydew = { 240, 255, 240, 1 }, mintcream = { 245, 255, 250, 1 }, azure = { 240, 255, 255, 1 }, aliceblue = { 240, 248, 255, 1 }, ghostwhite = { 248, 248, 255, 1 }, whitesmoke = { 245, 245, 245, 1 }, seashell = { 255, 245, 238, 1 }, beige = { 245, 245, 220, 1 }, oldlace = { 253, 245, 230, 1 }, floralwhite = { 255, 250, 240, 1 }, ivory = { 255, 255, 240, 1 }, antiquewhite = { 250, 235, 215, 1 }, linen = { 250, 240, 230, 1 }, lavenderblush = { 255, 240, 245, 1 }, mistyrose = { 255, 228, 225, 1 }, gainsboro = { 220, 220, 220, 1 }, lightgray = { 211, 211, 211, 1 }, silver = { 192, 192, 192, 1 }, darkgray = { 169, 169, 169, 1 }, gray = { 128, 128, 128, 1 }, dimgray = { 105, 105, 105, 1 }, lightslategray = { 119, 136, 153, 1 }, slategray = { 112, 128, 144, 1 }, darkslategray = { 47, 79, 79, 1 }, black = { 0, 0, 0, 1 } } diff --git a/src/color/ColorUtils.lua b/src/color/ColorUtils.lua new file mode 100644 index 0000000..b445d5f --- /dev/null +++ b/src/color/ColorUtils.lua @@ -0,0 +1,31 @@ +ColorUtils = {} + +function ColorUtils.is_valid_hex_code(s) + s = s:gsub("#", "") + local invalidChars = string.match(s, "[^0-9a-fA-F]+") + local hasValidChars = invalidChars == nil + local isValidLen = #s == 3 or #s == 4 or #s == 6 or #s == 8 + return hasValidChars and isValidLen +end + +function ColorUtils.hex_code_to_color(s) + if not ColorUtils.is_valid_hex_code(s) then + error("ValueError: Not a valid hex code.") + end + + s = tostring(s):gsub("#", "") + local color = {} + if #s == 3 or #s == 4 then + table.insert(color, tonumber(s:sub(1, 1):rep(2), 16) / 255) + table.insert(color, tonumber(s:sub(2, 2):rep(2), 16) / 255) + table.insert(color, tonumber(s:sub(3, 3):rep(2), 16) / 255) + table.insert(color, (#s == 4) and tonumber(s:sub(4, 4):rep(2), 16) / 255 or 1) + elseif #s == 6 or #s == 8 then + table.insert(color, tonumber(s:sub(1, 2), 16) / 255) + table.insert(color, tonumber(s:sub(3, 4), 16) / 255) + table.insert(color, tonumber(s:sub(5, 6), 16) / 255) + table.insert(color, (#s == 8) and tonumber(s:sub(7, 8), 16) / 255 or 1) + end + + return color +end diff --git a/src/color/color.convert.lua b/src/color/color.convert.lua deleted file mode 100644 index 47eb3db..0000000 --- a/src/color/color.convert.lua +++ /dev/null @@ -1,49 +0,0 @@ ---- Functions to convert various color types into one another\ --- @submodule color - ---- Converts a hex code string to a color table. --- Takes a string representation of a CSS hex value and converts it into --- an `{r, g, b, a}` color table. The function ignores the leading # --- symbol if present and will parse a 3 (rgb), 4 (rgba), 6 (rrggbb), or --- 8 (rrggbbaa) character-long hex value into a normalized (0 to 1) rgba --- color table. Sets a to 1 if not present in the hex code. --- @tparam string s A hex code formatted as #rgb, #rgba, #rrggbb, or --- #rrggbbaa with or without the leading # symbol --- @treturn table A color table in the format {r, g, b, a} --- @raise ValueError if hex code is malformed --- @usage --- white = hex_code_to_color("#FFF") --- print(white) -- {1, 1, 1, 1} --- --- black = hex_code_to_color("000F") --- print(black) -- {0, 0, 0, 1} --- --- orange = hex_code_to_color("#FFA500") --- print(orange) -- {0.9450..., 0.7686..., 0.0588..., 1} --- --- blue_transparent = hex_code_to_color("0000FF33") --- print(blue_transparent) -- {0, 0, 1, 0.2} --- --- malformed_hex = hex_code_to_color("#G09F3") --- -- ValueError: Not a valid hex code. -function hex_code_to_color(s) - if not is_valid_hex_code(s) then - error("ValueError: Not a valid hex code.") - end - - s = tostring(s):gsub("#", "") - local color = {} - if #s == 3 or #s == 4 then - table.insert(color, tonumber(s:sub(1, 1):rep(2), 16) / 255) - table.insert(color, tonumber(s:sub(2, 2):rep(2), 16) / 255) - table.insert(color, tonumber(s:sub(3, 3):rep(2), 16) / 255) - table.insert(color, (#s == 4) and tonumber(s:sub(4, 4):rep(2), 16) / 255 or 1) - elseif #s == 6 or #s == 8 then - table.insert(color, tonumber(s:sub(1, 2), 16) / 255) - table.insert(color, tonumber(s:sub(3, 4), 16) / 255) - table.insert(color, tonumber(s:sub(5, 6), 16) / 255) - table.insert(color, (#s == 8) and tonumber(s:sub(7, 8), 16) / 255 or 1) - end - - return color -end diff --git a/src/color/color.lua b/src/color/color.lua deleted file mode 100644 index 2fd50b9..0000000 --- a/src/color/color.lua +++ /dev/null @@ -1,6 +0,0 @@ ---- Create, translate, validate, and manipulate colors. --- This is the main module for color-related functionalities. --- It encapsulates submodules like color.convert, color.tables, and color.validate. --- @module color - --- This file intentionally left blank to help generate API docs. diff --git a/src/color/color.tables.lua b/src/color/color.tables.lua deleted file mode 100644 index be78f95..0000000 --- a/src/color/color.tables.lua +++ /dev/null @@ -1,7 +0,0 @@ ---- Tables of colors --- @submodule color - ---- All of the named HTML colors. --- @table htmlColors --- @field colorname {r, g, b, a} -htmlColors = { indianred = { 205, 92, 92, 1 }, lightcoral = { 240, 128, 128, 1 }, salmon = { 250, 128, 114, 1 }, darksalmon = { 233, 150, 122, 1 }, lightsalmon = { 255, 160, 122, 1 }, crimson = { 220, 20, 60, 1 }, red = { 255, 0, 0, 1 }, firebrick = { 178, 34, 34, 1 }, darkred = { 139, 0, 0, 1 }, pink = { 255, 192, 203, 1 }, lightpink = { 255, 182, 193, 1 }, hotpink = { 255, 105, 180, 1 }, deeppink = { 255, 20, 147, 1 }, mediumvioletred = { 199, 21, 133, 1 }, palevioletred = { 219, 112, 147, 1 }, coral = { 255, 127, 80, 1 }, tomato = { 255, 99, 71, 1 }, orangered = { 255, 69, 0, 1 }, darkorange = { 255, 140, 0, 1 }, orange = { 255, 165, 0, 1 }, gold = { 255, 215, 0, 1 }, yellow = { 255, 255, 0, 1 }, lightyellow = { 255, 255, 224, 1 }, lemonchiffon = { 255, 250, 205, 1 }, lightgoldenrodyellow = { 250, 250, 210, 1 }, papayawhip = { 255, 239, 213, 1 }, moccasin = { 255, 228, 181, 1 }, peachpuff = { 255, 218, 185, 1 }, palegoldenrod = { 238, 232, 170, 1 }, khaki = { 240, 230, 140, 1 }, darkkhaki = { 189, 183, 107, 1 }, lavender = { 230, 230, 250, 1 }, thistle = { 216, 191, 216, 1 }, plum = { 221, 160, 221, 1 }, violet = { 238, 130, 238, 1 }, orchid = { 218, 112, 214, 1 }, fuchsia = { 255, 0, 255, 1 }, magenta = { 255, 0, 255, 1 }, mediumorchid = { 186, 85, 211, 1 }, mediumpurple = { 147, 112, 219, 1 }, rebeccapurple = { 102, 51, 153, 1 }, blueviolet = { 138, 43, 226, 1 }, darkviolet = { 148, 0, 211, 1 }, darkorchid = { 153, 50, 204, 1 }, darkmagenta = { 139, 0, 139, 1 }, purple = { 128, 0, 128, 1 }, indigo = { 75, 0, 130, 1 }, slateblue = { 106, 90, 205, 1 }, darkslateblue = { 72, 61, 139, 1 }, mediumslateblue = { 123, 104, 238, 1 }, greenyellow = { 173, 255, 47, 1 }, chartreuse = { 127, 255, 0, 1 }, lawngreen = { 124, 252, 0, 1 }, lime = { 0, 255, 0, 1 }, limegreen = { 50, 205, 50, 1 }, palegreen = { 152, 251, 152, 1 }, lightgreen = { 144, 238, 144, 1 }, mediumspringgreen = { 0, 250, 154, 1 }, springgreen = { 0, 255, 127, 1 }, mediumseagreen = { 60, 179, 113, 1 }, seagreen = { 46, 139, 87, 1 }, forestgreen = { 34, 139, 34, 1 }, green = { 0, 128, 0, 1 }, darkgreen = { 0, 100, 0, 1 }, yellowgreen = { 154, 205, 50, 1 }, olivedrab = { 107, 142, 35, 1 }, olive = { 128, 128, 0, 1 }, darkolivegreen = { 85, 107, 47, 1 }, mediumaquamarine = { 102, 205, 170, 1 }, darkseagreen = { 143, 188, 139, 1 }, lightseagreen = { 32, 178, 170, 1 }, darkcyan = { 0, 139, 139, 1 }, teal = { 0, 128, 128, 1 }, aqua = { 0, 255, 255, 1 }, cyan = { 0, 255, 255, 1 }, lightcyan = { 224, 255, 255, 1 }, paleturquoise = { 175, 238, 238, 1 }, aquamarine = { 127, 255, 212, 1 }, turquoise = { 64, 224, 208, 1 }, mediumturquoise = { 72, 209, 204, 1 }, darkturquoise = { 0, 206, 209, 1 }, cadetblue = { 95, 158, 160, 1 }, steelblue = { 70, 130, 180, 1 }, lightsteelblue = { 176, 196, 222, 1 }, powderblue = { 176, 224, 230, 1 }, lightblue = { 173, 216, 230, 1 }, skyblue = { 135, 206, 235, 1 }, lightskyblue = { 135, 206, 250, 1 }, deepskyblue = { 0, 191, 255, 1 }, dodgerblue = { 30, 144, 255, 1 }, cornflowerblue = { 100, 149, 237, 1 }, royalblue = { 65, 105, 225, 1 }, blue = { 0, 0, 255, 1 }, mediumblue = { 0, 0, 205, 1 }, darkblue = { 0, 0, 139, 1 }, navy = { 0, 0, 128, 1 }, midnightblue = { 25, 25, 112, 1 }, cornsilk = { 255, 248, 220, 1 }, blanchedalmond = { 255, 235, 205, 1 }, bisque = { 255, 228, 196, 1 }, navajowhite = { 255, 222, 173, 1 }, wheat = { 245, 222, 179, 1 }, burlywood = { 222, 184, 135, 1 }, tan = { 210, 180, 140, 1 }, rosybrown = { 188, 143, 143, 1 }, sandybrown = { 244, 164, 96, 1 }, goldenrod = { 218, 165, 32, 1 }, darkgoldenrod = { 184, 134, 11, 1 }, peru = { 205, 133, 63, 1 }, chocolate = { 210, 105, 30, 1 }, saddlebrown = { 139, 69, 19, 1 }, sienna = { 160, 82, 45, 1 }, brown = { 165, 42, 42, 1 }, maroon = { 128, 0, 0, 1 }, white = { 255, 255, 255, 1 }, snow = { 255, 250, 250, 1 }, honeydew = { 240, 255, 240, 1 }, mintcream = { 245, 255, 250, 1 }, azure = { 240, 255, 255, 1 }, aliceblue = { 240, 248, 255, 1 }, ghostwhite = { 248, 248, 255, 1 }, whitesmoke = { 245, 245, 245, 1 }, seashell = { 255, 245, 238, 1 }, beige = { 245, 245, 220, 1 }, oldlace = { 253, 245, 230, 1 }, floralwhite = { 255, 250, 240, 1 }, ivory = { 255, 255, 240, 1 }, antiquewhite = { 250, 235, 215, 1 }, linen = { 250, 240, 230, 1 }, lavenderblush = { 255, 240, 245, 1 }, mistyrose = { 255, 228, 225, 1 }, gainsboro = { 220, 220, 220, 1 }, lightgray = { 211, 211, 211, 1 }, silver = { 192, 192, 192, 1 }, darkgray = { 169, 169, 169, 1 }, gray = { 128, 128, 128, 1 }, dimgray = { 105, 105, 105, 1 }, lightslategray = { 119, 136, 153, 1 }, slategray = { 112, 128, 144, 1 }, darkslategray = { 47, 79, 79, 1 }, black = { 0, 0, 0, 1 } } diff --git a/src/color/color.validate.lua b/src/color/color.validate.lua deleted file mode 100644 index a303f64..0000000 --- a/src/color/color.validate.lua +++ /dev/null @@ -1,21 +0,0 @@ ---- Functions to validate the form of color strings and numbers --- @submodule color - ---- Checks if a CSS hex code is formatted properly. --- Uses character and length matching to assert that the hex code is --- formatted correctly. Works for rgb, rgba, rrggbb, and rrggbbaa hex --- codes. Outputs true if correct and false if malformed. --- @tparam string s A hex code formatted as #rgb, #rgba, #rrggbb, or --- #rrggbbaa with or without the leading # symbol --- @treturn boolean true if correctly formatted, false if not. --- @usage --- print(is_valid_hex_code(FFF)) -- true --- --- print(is_valid_hex_code(#J37N)) -- false -function is_valid_hex_code(s) - s = s:gsub("#", "") - local invalidChars = string.match(s, "[^0-9a-fA-F]+") - local hasValidChars = invalidChars == nil - local isValidLen = #s == 3 or #s == 4 or #s == 6 or #s == 8 - return hasValidChars and isValidLen -end diff --git a/src/debug/Debug.lua b/src/debug/Debug.lua new file mode 100644 index 0000000..a21f40e --- /dev/null +++ b/src/debug/Debug.lua @@ -0,0 +1,54 @@ +Debug = {} + +function Debug.Logger() + local queue = {} + + local function add_to_queue(...) + local args = { ... } + local statements = {} + + for i, arg in ipairs(args) do + statements[i] = (type(arg) == "table") + and Utils.table_to_string(arg) or tostring(arg) + end + + table.insert(queue, table.concat(statements, ", ")) + end + + local function get_peak_memory(interval) + if _PeakMemory == nil then + _PeakMemory = math.floor(collectgarbage("count")) + end + + if Time == nil then Time = 0 end + local current_memory_usage = math.floor(collectgarbage("count")) + local truncated_time = math.floor(Time * 100) / 100 + + if _PeakMemory < current_memory_usage then + _PeakMemory = current_memory_usage + end + + if truncated_time % interval == 0 then _PeakMemory = 0 end + + return _PeakMemory + end + + local function print_queue() + translate { 0, -30 } + text("Peak memory usage (KB): " .. get_peak_memory(10), theme.text) + translate { 0, -20 } + text("Print Queue Output", theme.text) + translate { 0, -4 } + text("_________________", theme.text) + translate { 0, -20 } + + for i, s in ipairs(queue) do + text(i .. ": " .. s, theme.text) + translate { 0, -14 } + end + end + + return add_to_queue, print_queue +end + +print, print_all = Debug.Logger() diff --git a/src/debug/debug.lua b/src/debug/debug.lua deleted file mode 100644 index 825e62e..0000000 --- a/src/debug/debug.lua +++ /dev/null @@ -1,91 +0,0 @@ ---- Add debugging capabilities. --- @module debug - ---- Returns a set of functions that together enable stdout-like printing. --- The built-in Lua print() function can't print anywhere in Audulus. This --- function enables you to add in a stdout-like experience in Audulus. The --- function creates two functions (normally named print and printAll) that --- assist in printing variables beneath the Canvas node. print() will add a --- variable or value to the print queue. Use print() just as you would in any --- any other program. Then, call printAll() at the very end of your script to --- display the print queue. Each print item is numbered in the order it was --- called starting at 1. Additionally, displays the current memory usage. --- @treturn function add_to_queue Adds variable to print queue. --- @treturn function print_queue Prints the queue beneath the Canvas node. --- @usage --- print, printAll = create_print_logger() --- --- x = 1 + 1 --- print(x) --- --- color = {0.5, 0.75, 0.1, 1} --- print(color) --- --- coordinate = {x = 1, y = 12} --- print(coordinate) --- --- printAll() --- -- (Note: This appears below the Canvas node) -- --- -- Memory usage (KB): 72 --- -- Print Queue Output --- -- _________________ --- -- 1. 2 --- -- 2. {0.5, 0.75, 0.1, 1} --- -- 3. {x = 1, y = 12} -function create_print_logger() - local queue = {} - - local function has_non_integer_keys(t) - for k, _ in pairs(t) do - if type(k) ~= "number" or k ~= math.floor(k) or k < 1 then - return true - end - end - return false - end - - local function table_to_string(t) - local parts = {} - if has_non_integer_keys(t) then - for k, v in pairs(t) do - parts[#parts + 1] = tostring(k) .. " = " .. tostring(v) - end - else - for _, v in ipairs(t) do - parts[#parts + 1] = tostring(v) - end - end - return "{ " .. table.concat(parts, ", ") .. " }" - end - - local function add_to_queue(...) - local args = { ... } - local statements = {} - - for i, arg in ipairs(args) do - statements[i] = (type(arg) == "table") - and table_to_string(arg) or tostring(arg) - end - - table.insert(queue, table.concat(statements, ", ")) - end - - local function print_queue() - local memory = math.floor(collectgarbage("count")) - - translate { 0, -30 } - text("Memory usage (KB): " .. memory, theme.text) - translate { 0, -20 } - text("Print Queue Output", theme.text) - translate { 0, -4 } - text("_________________", theme.text) - translate { 0, -20 } - - for i, s in ipairs(queue) do - text(i .. ": " .. s, theme.text) - translate { 0, -14 } - end - end - - return add_to_queue, print_queue -end diff --git a/src/debug/print.lua.minified b/src/debug/print.lua.minified deleted file mode 100644 index 9575a6b..0000000 --- a/src/debug/print.lua.minified +++ /dev/null @@ -1,7 +0,0 @@ -local function p() local q={}; local function h(t) for k,_ in pairs(t) do if type(k)~="number" or k~=math.floor(k) or k<1 then return true end end return false end local function tS(t) local p={}; if h(t) then for k,v in pairs(t) do p[#p+1]="["..tostring(k).."]="..tostring(v) end else for _,v in ipairs(t) do p[#p+1]=tostring(v) end end return "{"..table.concat(p,", ").."}" end local function a(...) local a={...}; local s={}; for _,arg in ipairs(a) do s[#s+1]=(type(arg)=="table") and tS(arg) or tostring(arg) end table.insert(q,table.concat(s,", ")) end local function pQ() local m=math.floor(collectgarbage("count")); translate{0,-30}; text("Memory usage (KB): "..m,theme.text); translate{0,-20}; text("Print Queue Output",theme.text); translate{0,-4}; text("_________________",theme.text); translate{0,-20}; for i,s in ipairs(q) do text(i..": "..s,theme.text); translate{0,-14} end end return a,pQ end - -print, printAll() = p() - --- INSERT SCRIPT HERE -- - -printAll() \ No newline at end of file diff --git a/src/debug/print_logger.lua b/src/debug/print_logger.lua deleted file mode 100644 index d8c27bd..0000000 --- a/src/debug/print_logger.lua +++ /dev/null @@ -1,107 +0,0 @@ ---- Useful debugging functions. --- @module debug - ---- Returns a set of functions that together enable stdout-like printing. --- The built-in Lua print() function can't print anywhere in Audulus. This --- function enables you to add in a stdout-like experience in Audulus. The --- function creates two functions (normally named print and printAll) that --- assist in printing variables beneath the Canvas node. print() will add a --- variable or value to the print queue. Use print() just as you would in any --- any other program. Then, call printAll() at the very end of your script to --- display the print queue. Each print item is numbered in the order it was --- called starting at 1. Additionally, displays the current memory usage. --- @treturn function add_to_queue Adds variable to print queue. --- @treturn function print_queue Prints the queue beneath the Canvas node. --- @usage --- print, printAll = create_print_logger() --- --- x = 1 + 1 --- print(x) --- --- color = {0.5, 0.75, 0.1, 1} --- print(color) --- --- coordinate = {x = 1, y = 12} --- print(coordinate) --- --- printAll() --- -- (Note: This appears below the Canvas node) -- --- -- Memory usage (KB): 72 --- -- Print Queue Output --- -- _________________ --- -- 1. 2 --- -- 2. {0.5, 0.75, 0.1, 1} --- -- 3. {x = 1, y = 12} -function create_print_logger() - local queue = {} - - local function has_non_integer_keys(t) - for k, _ in pairs(t) do - if type(k) ~= "number" or k ~= math.floor(k) or k < 1 then - return true - end - end - return false - end - - local function table_to_string(t) - local parts = {} - if has_non_integer_keys(t) then - for k, v in pairs(t) do - parts[#parts + 1] = tostring(k) .. " = " .. tostring(v) - end - else - for _, v in ipairs(t) do - parts[#parts + 1] = tostring(v) - end - end - return "{ " .. table.concat(parts, ", ") .. " }" - end - - local function add_to_queue(...) - local args = { ... } - local statements = {} - - for i, arg in ipairs(args) do - statements[i] = (type(arg) == "table") - and table_to_string(arg) or tostring(arg) - end - - table.insert(queue, table.concat(statements, ", ")) - end - - local function get_peak_memory(interval) - if _PeakMemory == nil then - _PeakMemory = math.floor(collectgarbage("count")) - end - - if Time == nil then Time = 0 end - local current_memory_usage = math.floor(collectgarbage("count")) - local truncated_time = math.floor(Time * 100) / 100 - - if _PeakMemory < current_memory_usage then - _PeakMemory = current_memory_usage - end - - if truncated_time % interval == 0 then _PeakMemory = 0 end - - return _PeakMemory - end - - local function print_queue() - translate { 0, -30 } - text("Peak memory usage (KB): " .. get_peak_memory(10), theme.text) - translate { 0, -20 } - text("Print Queue Output", theme.text) - translate { 0, -4 } - text("_________________", theme.text) - translate { 0, -20 } - - for i, s in ipairs(queue) do - text(i .. ": " .. s, theme.text) - translate { 0, -14 } - end - end - - return addToQueue, printQueue -end diff --git a/src/draw/Line.lua b/src/draw/Line.lua index 1d9e4a4..8c53b1b 100644 --- a/src/draw/Line.lua +++ b/src/draw/Line.lua @@ -35,6 +35,16 @@ function Line.draw_between_all(...) end end +function Line.dash_between_all(...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + for j = i + 1, #vec2s do + local line = Line.new(vec2s[i], vec2s[j]) + line:dashed() + end + end +end + function Line.draw_from_to_all(vec2, ...) local vec2s = process_args(Line, ...) for i = 1, #vec2s do @@ -43,6 +53,14 @@ function Line.draw_from_to_all(vec2, ...) end end +function Line.dash_from_to_all(vec2, ...) + local vec2s = process_args(Line, ...) + for i = 1, #vec2s do + local line = Line.new(vec2, vec2s[i]) + line:dash() + end +end + function Line:draw(color, width) color = color or theme.text width = width or 1 diff --git a/src/draw/Point.lua b/src/draw/Point.lua index f7b5d31..b2d2668 100644 --- a/src/draw/Point.lua +++ b/src/draw/Point.lua @@ -9,25 +9,8 @@ function Point.new(vec2, color, size) return self end -local function process_args(class_meta, ...) - local args = { ... } - local processed_args - - if type(args[1]) == "table" then - if getmetatable(args[1]) == class_meta then - processed_args = args - else - processed_args = args[1] - end - else - processed_args = args - end - - return processed_args -end - function Point.draw_all(...) - local points = process_args(Point, ...) + local points = Utils.process_args(Point, ...) for _, point in ipairs(points) do if getmetatable(point) == Point then diff --git a/src/draw/Triangle.lua b/src/draw/Triangle.lua new file mode 100644 index 0000000..1a7df8a --- /dev/null +++ b/src/draw/Triangle.lua @@ -0,0 +1,232 @@ +Triangle = {} +Triangle.__index = Triangle + +function Triangle.new(vec2_a, vec2_b, vec2_c) + local self = setmetatable({}, Triangle) + self.vec2_a = vec2_a or { x = 0, y = 0 } + self.vec2_b = vec2_b or { x = 0, y = 0 } + self.vec2_c = vec2_c or { x = 0, y = 0 } + return self +end + +function Triangle:draw(color) + color = color or theme.text + local paint = color_paint(color) + move_to { self.vec2_a.x, self.vec2_a.y } + line_to { self.vec2_b.x, self.vec2_b.y } + line_to { self.vec2_c.x, self.vec2_c.y } + line_to { self.vec2_a.x, self.vec2_a.y } + fill(paint) +end + +function Triangle:get_vec2s() + return { vec2_a = self.vec2_a, vec2_b = self.vec2_b, vec2_c = self.vec2_c } +end + +function Triangle:get_vec2_a() + return self.vec2_a +end + +function Triangle:get_vec2_b() + return self.vec2_b +end + +function Triangle:get_vec2_c() + return self.vec2_c +end + +function Triangle:Set_vec2s(...) +end + +function Triangle:Set_vec2_a(x, y) + self.vec2_a:Set(x, y) +end + +function Triangle:Set_vec2_b(x, y) + self.vec2_b:Set(x, y) +end + +function Triangle:Set_vec2_c(x, y) + self.vec2_c:Set(x, y) +end + +function Triangle:centroid() + local cx = (self.vec2_a.x + self.vec2_b.x + self.vec2_c.x) / 3 + local cy = (self.vec2_a.y + self.vec2_b.y + self.vec2_c.y) / 3 + return Vec2.new(cx, cy) +end + +function Triangle:area() + local a = self.vec2_a + local b = self.vec2_b + local c = self.vec2_c + + local area = 0.5 * math.abs( + a.x * (b.y - c.y) + + b.x * (c.y - a.y) + + c.x * (a.y - b.y) + ) + return area +end + +function Triangle:perimeter() + local a_b = self.vec2_a:distance(self.vec2_b) + local b_c = self.vec2_b:distance(self.vec2_c) + local c_a = self.vec2_c:distance(self.vec2_a) + + local perimeter = a_b + b_c + c_a + return perimeter +end + +function Triangle:type() + local tolerance = 0.00001 + local a_b = self.vec2_a:distance(self.vec2_b) + local b_c = self.vec2_b:distance(self.vec2_c) + local c_a = self.vec2_c:distance(self.vec2_a) + + local ab_bc = math.abs(a_b - b_c) < tolerance + local ab_ca = math.abs(a_b - c_a) < tolerance + local bc_ca = math.abs(b_c - c_a) < tolerance + + if ab_bc and ab_ca then + return "equilateral" + elseif ab_bc or ab_ca or bc_ca then + return "isosceles" + else + return "scalene" + end +end + +function Triangle:angle_type() + local vec_a_b = self.vec2_b:sub(self.vec2_a) + local vec_a_c = self.vec2_c:sub(self.vec2_a) + local vec_b_a = self.vec2_a:sub(self.vec2_b) + local vec_b_c = self.vec2_c:sub(self.vec2_b) + local vec_c_a = self.vec2_a:sub(self.vec2_c) + local vec_c_b = self.vec2_b:sub(self.vec2_c) + + local dot_a = vec_a_b:dot(vec_a_c) + local dot_b = vec_b_a:dot(vec_b_c) + local dot_c = vec_c_a:dot(vec_c_b) + + local isRight = dot_a == 0 or dot_b == 0 or dot_c == 0 + local isObtuse = dot_a < 0 or dot_b < 0 or dot_c < 0 + + if isRight then + return "right" + elseif isObtuse then + return "obtuse" + else + return "acute" + end +end + +function Triangle:scale(scalar) + local centroid = self:centroid() + + return Triangle.new( + self.vec2_a:scale_about(centroid, scalar), + self.vec2_b:scale_about(centroid, scalar), + self.vec2_c:scale_about(centroid, scalar) + ) +end + +function Triangle:Scale(scalar) + local centroid = self:centroid() + + self.vec2_a = self.vec2_a:scale_about(centroid, scalar) + self.vec2_b = self.vec2_b:scale_about(centroid, scalar) + self.vec2_c = self.vec2_c:scale_about(centroid, scalar) +end + +function Triangle:rotate(angle) + local centroid = self:centroid() + + local rotate_vertex = function(vertex) + local translated_vertex = vertex:sub(centroid) + local rotated_vertex = translated_vertex:rotate(angle) + return rotated_vertex:add(centroid) + end + + return Triangle.new( + rotate_vertex(self.vec2_a), + rotate_vertex(self.vec2_b), + rotate_vertex(self.vec2_c) + ) +end + +function Triangle:Rotate(angle) + local centroid = self:centroid() + + local rotate_vertex = function(vertex) + local translated_vertex = vertex:sub(centroid) + local rotated_vertex = translated_vertex:rotate(angle) + return rotated_vertex:add(centroid) + end + + self.vec2_a = rotate_vertex(self.vec2_a) + self.vec2_b = rotate_vertex(self.vec2_b) + self.vec2_c = rotate_vertex(self.vec2_c) + return self +end + +function Triangle:translate(vec2) + return Triangle.new( + self.vec2_a:add(vec2), + self.vec2_b:add(vec2), + self.vec2_c:add(vec2) + ) +end + +function Triangle:Translate(vec2) + self.vec2_a:add(vec2) + self.vec2_b:add(vec2) + self.vec2_c:add(vec2) + return self +end + +function Triangle:bounding_box() + local min_x = math.min(self.vec2_a.x, self.vec2_b.x, self.vec2_c.x) + local max_x = math.max(self.vec2_a.x, self.vec2_b.x, self.vec2_c.x) + local min_y = math.min(self.vec2_a.y, self.vec2_b.y, self.vec2_c.y) + local max_y = math.max(self.vec2_a.y, self.vec2_b.y, self.vec2_c.y) + return Vec2.new(min_x, min_y), Vec2.new(max_x, max_y) +end + +function Triangle:incircle() + local a = self.vec2_b:distance(self.vec2_c) + local b = self.vec2_c:distance(self.vec2_a) + local c = self.vec2_a:distance(self.vec2_b) + local s = (a + b + c) / 2 + local area = math.sqrt(s * (s - a) * (s - b) * (s - c)) + local incenterX = (a * self.vec2_a.x + b * self.vec2_b.x + c * self.vec2_c.x) / (a + b + c) + local incenterY = (a * self.vec2_a.y + b * self.vec2_b.y + c * self.vec2_c.y) / (a + b + c) + local radius = area / s + return Vec2.new(incenterX, incenterY), radius +end + +function Triangle:circumcircle() + local a = self.vec2_b:distance(self.vec2_c) + local b = self.vec2_c:distance(self.vec2_a) + local c = self.vec2_a:distance(self.vec2_b) + local s = (a + b + c) / 2 + local area = math.sqrt(s * (s - a) * (s - b) * (s - c)) + local radius = (a * b * c) / (4 * area) + local ax, ay = self.vec2_a.x, self.vec2_a.y + local bx, by = self.vec2_b.x, self.vec2_b.y + local cx, cy = self.vec2_c.x, self.vec2_c.y + local D = 2 * ( + ax * (by - cy) + + bx * (cy - ay) + + cx * (ay - by) + ) + local Ux = ( + (ax ^ 2 + ay ^ 2) * (by - cy) + + (bx ^ 2 + by ^ 2) * (cy - ay) + + (cx ^ 2 + cy ^ 2) * (ay - by)) / D + local Uy = ( + (ax ^ 2 + ay ^ 2) * (cx - bx) + + (bx ^ 2 + by ^ 2) * (ax - cx) + + (cx ^ 2 + cy ^ 2) * (bx - ax)) / D + return Vec2.new(Ux, Uy), radius +end diff --git a/src/draw/draw.button.lua b/src/draw/draw.button.lua deleted file mode 100644 index fa5df5c..0000000 --- a/src/draw/draw.button.lua +++ /dev/null @@ -1,2 +0,0 @@ ---- Functions to convert various color types into one another --- @submodule draw diff --git a/src/draw/draw.lua b/src/draw/draw.lua deleted file mode 100644 index 3a7a5ba..0000000 --- a/src/draw/draw.lua +++ /dev/null @@ -1,6 +0,0 @@ ---- Draw shapes. --- This is the main library for drawing functions. It employs and extends the --- built-in functions found in the Canvas node. --- @module draw - --- This file intentionally left blank to help generate API docs. diff --git a/src/draw/draw.primitives.lua b/src/draw/draw.primitives.lua deleted file mode 100644 index de2798c..0000000 --- a/src/draw/draw.primitives.lua +++ /dev/null @@ -1,7 +0,0 @@ -function fill_triangle(vec2_a, vec2_b, vec2_c, paint) - move_to(vec2_a) - line_to(vec2_b) - line_to(vec2_c) - line_to(vec2_a) - fill(paint) -end diff --git a/src/math/Vec2.lua b/src/math/Vec2.lua index 70f6194..43697be 100644 --- a/src/math/Vec2.lua +++ b/src/math/Vec2.lua @@ -8,18 +8,32 @@ function Vec2.new(x, y) return self end -local function is_vec(v) - return type(v) == "table" and v.x and v.y +function Vec2.is_vec2(obj) + return type(obj) == "table" and obj.x and obj.y and not obj.z end -local function is_num_pair(x, y) +function Vec2.is_xy_pair(x, y) return type(x) == "number" and type(y) == "number" end +function Vec2:Set(x, y) + if Vec2.is_vec2(x) then + self.x = x.x + self.y = x.y + return self + elseif Vec2.is_xy_pair(x, y) then + self.x = x + self.y = y + return self + else + error("TypeError: Invalid arguments for Vec2:set") + end +end + function Vec2:add(x, y) - if is_vec(x) then + if Vec2.is_vec2(x) then return Vec2.new(self.x + x.x, self.y + x.y) - elseif is_num_pair(x, y) then + elseif Vec2.is_xy_pair(x, y) then return Vec2.new(self.x + x, self.y + y) else error("TypeError: Invalid arguments for Vec2:add") @@ -27,11 +41,11 @@ function Vec2:add(x, y) end function Vec2:Add(x, y) - if is_vec(x) then + if Vec2.is_vec2(x) then self.x = self.x + x.x self.y = self.y + x.y return self - elseif is_num_pair(x, y) then + elseif Vec2.is_xy_pair(x, y) then self.x = self.x + x self.y = self.y + y return self @@ -41,9 +55,9 @@ function Vec2:Add(x, y) end function Vec2:sub(x, y) - if is_vec(x) then + if Vec2.is_vec2(x) then return Vec2.new(self.x - x.x, self.y - x.y) - elseif is_num_pair(x, y) then + elseif Vec2.is_xy_pair(x, y) then return Vec2.new(self.x - x, self.y - y) else error("TypeError: Invalid arguments for Vec2:sub") @@ -51,11 +65,11 @@ function Vec2:sub(x, y) end function Vec2:Sub(x, y) - if is_vec(x) then + if Vec2.is_vec2(x) then self.x = self.x - x.x self.y = self.y - y.y return self - elseif is_num_pair(x, y) then + elseif Vec2.is_xy_pair(x, y) then self.x = self.x - x self.y = self.y - y return self @@ -119,7 +133,7 @@ function Vec2:Rotate(angle) end function Vec2:distance(other) - if is_vec(other) then + if Vec2.is_vec2(other) then local dx = self.x - other.x local dy = self.y - other.y return math.sqrt(dx * dx + dy * dy) @@ -127,3 +141,14 @@ function Vec2:distance(other) error("TypeError: Argument for Vec2:distance must be a Vec2") end end + +function Vec2:scale_about(other, scalar) + if Vec2.is_vec2(other) then + return Vec2.new( + other.x + (self.x - other.x) * scalar, + other.y + (self.y - other.y) * scalar + ) + else + error("TypeError: First argument for Vec2:scale_about must be a Vec2") + end +end diff --git a/src/utils/Utils.lua b/src/utils/Utils.lua new file mode 100644 index 0000000..de4240a --- /dev/null +++ b/src/utils/Utils.lua @@ -0,0 +1,41 @@ +Utils = {} + +function Utils.process_args(class_meta, ...) + local args = { ... } + local processed_args + + if type(args[1]) == "table" then + if getmetatable(args[1]) == class_meta then + processed_args = args + else + processed_args = args[1] + end + else + processed_args = args + end + + return processed_args +end + +function Utils.has_non_integer_keys(t) + for k, _ in pairs(t) do + if type(k) ~= "number" or k ~= math.floor(k) or k < 1 then + return true + end + end + return false +end + +function Utils.table_to_string(t) + local parts = {} + if Utils.has_non_integer_keys(t) then + for k, v in pairs(t) do + parts[#parts + 1] = tostring(k) .. " = " .. tostring(v) + end + else + for _, v in ipairs(t) do + parts[#parts + 1] = tostring(v) + end + end + return "{ " .. table.concat(parts, ", ") .. " }" +end diff --git a/src/draw/button.lua b/src/widgets/Button.lua similarity index 100% rename from src/draw/button.lua rename to src/widgets/Button.lua